- Rust 76.8%
- JavaScript 13.1%
- Shell 5.1%
- HTML 2.1%
- CSS 2.1%
- Other 0.8%
The hero_proc server requires a name for ad-hoc runs but the SDK had it as Option<String>, leading to confusing runtime errors. Now it is a required String in both the OpenRPC spec and all generated/hand-edited types, so callers get a compile-time error instead. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|---|---|---|
| .claude | ||
| .forgejo/workflows | ||
| crates | ||
| docker | ||
| docs | ||
| embedded_scripts | ||
| etc/hero_proc | ||
| examples | ||
| scripts | ||
| testcases | ||
| tests | ||
| .gitignore | ||
| buildenv.sh | ||
| Cargo.lock | ||
| Cargo.toml | ||
| Makefile | ||
| README.md | ||
hero_proc
A lightweight process supervisor with dependency management, similar to systemd but simpler.
Quick Start
Install from Source
make build # Build all release binaries
make install # Install to ~/hero/bin/
Run
# Set required environment variables
export FORGE_TOKEN=your_forgejo_token_here
# Start server + web dashboard
make run
# Use the CLI
hero_proc service list
hero_proc service status my-service
hero_proc service start my-service
hero_proc service stop my-service
The web admin dashboard is available at http://127.0.0.1:9999.
Documentation
- Data Model Reference: Core concepts, schemas, and data model specification
- OpenRPC API: JSON-RPC 2.0 method reference
- Example Configurations: Ready-to-use examples
- SDK README: Rust SDK for programmatic service management
Features
- Dependency Graph: Services declare dependencies (
requires,after,wants,conflicts) - State Machine: Explicit states (Inactive, Blocked, Starting, Running, Stopping, Success, Exited, Failed)
- Process Groups: Signals sent to process groups, handling
sh -cchild processes correctly - Health Checks: TCP, HTTP, and exec-based health checks with retries
- Ordered Shutdown: Dependents stop before their dependencies
- Hot Reload: Reload configuration without full restart
- Secrets Management: Encrypted secret storage with Forgejo sync (init, pull, push)
- Scheduled Actions: Cron-based scheduling for recurring tasks
- PTY Attach: Live terminal attach to running processes via WebSocket
- Web Admin Dashboard: Real-time service management UI with charts, logs, events, and bulk operations
- TUI Dashboard: Interactive terminal UI for service management (ratatui-based)
- Fully Embedded UI: All assets (Bootstrap, Chart.js, icons) compiled into the binary — no CDN or network required
- OpenRPC API: 92 JSON-RPC 2.0 methods over Unix socket
Architecture
hero_proc_server (daemon)
| unix socket (IPC + JSON-RPC 2.0)
v
hero_proc (CLI/TUI) hero_proc_ui (web admin dashboard)
| unix socket + TCP :9999
Crate Structure
crates/
hero_proc_sdk/ # OpenRPC client SDK — generated client + builders + factory
hero_proc_server/ # Process supervisor daemon (JSON-RPC 2.0 via Unix socket)
hero_proc/ # Command-line interface + TUI
hero_proc_ui/ # Web admin dashboard (Axum + Askama + Bootstrap)
hero_proc_lib/ # SQLite persistence layer (jobs, runs, secrets, logging, services)
hero_proc_examples/ # Runnable SDK usage examples
hero_proc_integration_test/ # Integration test suite + stress tests
Dependency Graph
hero_proc_sdk (no internal deps)
^ ^ ^ ^
| | | |
server CLI UI lib
All crates depend on hero_proc_sdk. No cross-dependencies between server, CLI, UI, or lib.
Ports and Sockets
| Component | Binding | Default |
|---|---|---|
| hero_proc_server | Unix socket (IPC) | $HERO_SOCKET_DIR/hero_proc/rpc.sock |
| hero_proc_ui | Unix socket (local) | $HERO_SOCKET_DIR/hero_proc/ui.sock |
| hero_proc_ui | TCP (HTTP dashboard) | 9999 |
Core Concepts
| Concept | Role | Lifetime |
|---|---|---|
| Action | Executable template (script + interpreter + config) | Stored, reusable |
| Service | Supervision unit — desired state + auto-restart | Ongoing, supervisor-managed |
| Job | Single execution of an action | Transient |
| Run | Universal grouping unit — groups jobs under a single lifecycle | Transient |
Service
A service is a supervision unit (like a systemd unit). It declares a desired state and references one or more actions. The supervisor continuously reconciles reality with the desired state:
start— supervisor ensures the service is running; restarts on crashstop— supervisor ensures the service is stoppedignore— supervisor does not manage this service
Action
An action is a reusable executable template: a script, its interpreter, environment, timeout, retry policy, and dependency edges. Actions can declare depends_on other actions for intra-service ordering.
Job
A job is a single execution of an action. Jobs can be one-shot (run and exit) or long-running processes (is_process = true), where exiting is treated as failure. Each job tracks phase (pending -> running -> succeeded/failed), PID, exit code, and logs.
Run
A run is the universal execution grouping unit. It serves two roles:
- Service run — created automatically when a service is started. Named
service_{name}, withservice_idpointing back to the owning service. If a service has 3 actions, starting it creates 1 run with 3 jobs. - Ad-hoc run — standalone execution of a set of actions (e.g., build pipelines, one-off tasks). Name is required.
service_idisNone.
A run can depend on other runs by ID — the supervisor will not start it until all dependency runs have reached "ok". Status progression: created → waiting_deps → starting → running → ok | error | halted.
Principles
- Run is the universal grouping unit: both ad-hoc executions and service starts create a Run. The
service_idfield distinguishes them. - Cascade delete: deleting a Run or Service deletes all associated Jobs. A Job belongs to exactly one Run.
- Clean restart: when a Service is started, previous Jobs for that Service are removed from the database by default (can be overridden).
- Provenance tracking: each Job records its
service_idandaction_idso the origin is always traceable.
For the full data model specification, see docs/README.md.
CLI Commands
All CLI commands are organized into subcommand groups:
Service Management
hero_proc service list # List all services
hero_proc service status <name> # Show service status
hero_proc service start <name> # Start a service
hero_proc service stop <name> # Stop (cascades to dependents)
hero_proc service restart <name> # Restart a service
hero_proc service kill <name> # Send signal to service
hero_proc service add <name> # Add a service at runtime
hero_proc service add-job <svc> ... # Add a job to a service
hero_proc service remove <name> # Remove a service
hero_proc service logs <name> # View service logs
hero_proc service why <name> # Show why service is blocked
hero_proc service tree # Show dependency tree
Job Management
hero_proc job list # List jobs
hero_proc job get <id> # Get job details
hero_proc job create ... # Create a job
hero_proc job delete <id> # Delete a job
hero_proc job status <id> # Job status
hero_proc job logs <id> # Job logs
hero_proc job retry <id> # Retry a failed job
hero_proc job cancel <id> # Cancel a running job
Run Tracking
hero_proc run list # List runs
hero_proc run get <id> # Get run details
hero_proc run logs <id> # Run logs
hero_proc run stats # Run statistics
Log Management
hero_proc log query # Query logs
hero_proc log filter # Filter logs
hero_proc log prune # Prune old logs
hero_proc log export # Export logs
Secrets Management
hero_proc secret set <key> <val> # Set a secret
hero_proc secret get <key> # Get a secret
hero_proc secret list # List secrets
hero_proc secret delete <key> # Delete a secret
hero_proc secret init # Initialize secrets store
hero_proc secret pull # Pull secrets from Forgejo
hero_proc secret push # Push secrets to Forgejo
Actions
hero_proc action list # List actions
hero_proc action get <name> # Get action details
hero_proc action set ... # Register an action
hero_proc action delete <name> # Delete an action
Scripts
hero_proc script scan # Scan for scripts
hero_proc script list # List registered scripts
hero_proc script get <name> # Get script details
hero_proc script set ... # Register a script
hero_proc script delete <name> # Delete a script
hero_proc script run <name> # Run a script
System
hero_proc system ping # Check daemon connectivity
hero_proc system health # Server health check
hero_proc system stats # System statistics
hero_proc system shutdown [--force] # Shutdown daemon
hero_proc system reset [--force] # Stop all, delete all configs
hero_proc system wipe # Wipe all data
hero_proc system demo # Create demo services
hero_proc system schedules # List scheduled actions
Debug
hero_proc debug state # Full graph state dump
hero_proc debug procs # Process tree dump
Other
hero_proc attach <name> # Attach to PTY of running process
hero_proc tui # Launch interactive TUI dashboard
Web Admin Dashboard
The hero_proc_ui crate provides a real-time web admin dashboard at http://localhost:9999 with tabs for:
- Actions: Registered actions with interpreter, timeout, and tags
- Jobs: Job instances with phase, status, and logs; includes statistics
- Runs: Execution runs with status and job counts
- Services: Service management, dependencies, and action mappings
- Secrets: Encrypted configuration values
- Logs: Query and filter system logs by source, level, and timestamp
All UI assets (Bootstrap 5.3.3, Bootstrap Icons) are embedded in the binary via rust-embed.
# Start server + UI
make run
# Or start separately
hero_proc_server &
hero_proc_ui --port 9999
SDK Usage
Factory (Recommended)
use hero_proc_sdk::*;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Connect to the default local socket
let hp = hero_proc_factory().await?;
// All RPC methods available directly
let pong = hp.system_ping(SystemPingInput {}).await?;
println!("server: {}", pong.version);
// High-level helpers
let svc = simple_service("myapp", "./myapp --serve");
hp.start_service("myapp", svc, 30).await?;
hp.stop_service("myapp", 10).await?;
Ok(())
}
Builder API
use hero_proc_sdk::{ServiceBuilder, ActionBuilder};
let service = ServiceBuilder::new("myapp")
.description("My application")
.exec("./myapp --server")
.requires(&["database"])
.build();
Presets
use hero_proc_sdk::{simple_service, oneshot_service, system_service, sleep_service};
let svc = simple_service("myapp", "./myapp --serve");
let setup = oneshot_service("setup", "bash setup.sh");
let sys = system_service("logger", "/usr/bin/logger");
Remote Connection
let hp = HeroProcFactory::builder()
.http("http://10.0.0.1:8080")
.connect().await?;
Environment Variables
Required
| Variable | Description |
|---|---|
FORGE_TOKEN |
Forgejo personal access token. Used for secrets sync and authentication. |
WEBROOT |
Base URL of the hero_proc UI (e.g. http://127.0.0.1:9998/). make run sets this automatically. |
Optional
| Variable | Default | Description |
|---|---|---|
HERO_PROC_LOG_LEVEL |
info |
Log level: trace, debug, info, warn, error |
HERO_PROC_CONFIG_DIR |
~/hero/cfg/hero_proc |
Service config directory |
HERO_PROC_SOCKET |
$HERO_SOCKET_DIR/hero_proc/rpc.sock |
Unix socket path |
Server Flags
hero_proc_server \
--db-path ~/hero/var/hero_proc.db \
--socket $HERO_SOCKET_DIR/hero_proc/rpc.sock \
--log-level info \
--screen # Run in GNU Screen session
Shutdown Ordering
Services are stopped in reverse dependency order:
Example: database <- app <- worker
Startup order: database -> app -> worker
Shutdown order: worker -> app -> database
When stopping a single service, dependents are stopped first:
hero_proc service stop databasestops worker, then app, then database- Dependencies are NOT auto-stopped (other services may need them)
Development
make check # Verify workspace builds
make test # Run unit tests
make build # Build all release binaries
make install # Build release and install to ~/hero/bin/
make lint # Run clippy linter
make fmt # Format code
make test-all # Run all tests (unit + bash + rhai)
# Run server + UI
make run # Release build, install, start on port 9999
make rundev # Debug build, start on port 9999
make stop # Graceful shutdown
# Integration tests
make test-bash # Bash-based integration tests
make test-rhai # Rhai-based integration tests
make test-shutdown # Shutdown scenario tests
# Playground
make play-tui # Launch TUI with sample services
make play-web # Launch web UI with sample services
# Release
make ship-binary # Tag and push for CI
make release # Create release