| .forgejo/workflows | ||
| docker | ||
| docs | ||
| etc/zinit | ||
| scripts | ||
| sysvol | ||
| tests/integration | ||
| zinit-client | ||
| zinit-common | ||
| zinit-pid1 | ||
| zinit-server | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CLAUDE.md | ||
| originalgap.txt | ||
| README.md | ||
zinit
A lightweight process supervisor with dependency management, similar to systemd but simpler.
Features
- Dependency Graph: Services declare dependencies (
requires,after,wants,conflicts) - State Machine: 7 explicit states (Inactive, Blocked, Starting, Running, Stopping, 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
- Multi-Environment: Works in containers, VMs, and bare-metal
Deployment Modes
zinit adapts its behavior based on deployment environment:
Container Mode
Use zinit-pid1 as your container entrypoint:
ENTRYPOINT ["/usr/bin/zinit-pid1", "--container"]
Or set the environment variable:
ZINIT_CONTAINER=1 zinit-pid1
Behavior:
- Loads services from
/etc/zinit/services/ - Clean exit on shutdown (no reboot syscall)
- No system services directory
VM / Bare-Metal Mode
Use zinit-pid1 as your init system (PID 1):
# In /sbin/init or kernel cmdline: init=/usr/bin/zinit-pid1
Behavior:
- Loads system services from
/etc/zinit/system/first (auto-assignedclass=system) - Loads user services from
/etc/zinit/services/second - Handles reboot/poweroff via syscalls (SIGINT=reboot, SIGTERM=poweroff)
- Never exits (kernel panic prevention)
Standalone Mode
Run zinit-server directly (not as PID 1):
zinit-server --config-dir /etc/zinit/services
Optionally enable system services directory:
zinit-server --config-dir /etc/zinit/services --pid1-mode
Quick Start
# Build
cargo build --release --workspace
# Run the server
zinit-server --config-dir /etc/zinit/services
# Use the CLI
zinit list
zinit status my-service
zinit start my-service
zinit stop my-service
Architecture
zinit-pid1 (PID 1 shim)
│ spawns/monitors
▼
zinit-server (daemon)
│ unix socket
▼
zinit-client (CLI/TUI)
| Crate | Purpose |
|---|---|
zinit-common |
Shared types, configs, RPC protocol, blocking client |
zinit-server |
Main daemon: supervisor, dependency graph, process management |
zinit-client |
CLI interface (optional TUI with --features tui) |
zinit-pid1 |
PID 1 init shim for containers/VMs |
Configuration
Service configs are TOML files in the config directory (default: /etc/zinit/services/):
[service]
name = "my-app"
exec = "/usr/bin/my-app --daemon"
dir = "/var/lib/my-app" # optional working directory
oneshot = false # exit after success (default: false)
status = "start" # start | stop | ignore (default: start)
class = "user" # user | system (default: user)
[dependencies]
requires = ["database"] # must be running
after = ["logger"] # start order only
wants = ["metrics"] # soft dependency
conflicts = ["legacy-app"] # mutual exclusion
[lifecycle]
restart = "on-failure" # always | on-failure | never
stop_signal = "SIGTERM"
start_timeout_ms = 30000
stop_timeout_ms = 10000
restart_delay_ms = 1000
restart_delay_max_ms = 60000
max_restarts = 0 # 0 = unlimited
[health]
type = "http"
endpoint = "http://localhost:8080/health"
interval_ms = 10000
retries = 3
[logging]
buffer_lines = 1000
Targets
Virtual services for grouping:
[target]
name = "multi-user"
[dependencies]
requires = ["network", "logger", "database"]
Service Status
The status field controls supervisor behavior:
start(default): Automatically start and keep runningstop: Keep stopped (won't auto-start)ignore: Supervisor ignores this service
Service Class
The class field protects critical services from bulk operations:
user(default): Normal service, affected by*_allcommandssystem: Protected service, skipped by bulk operations
System-class services are immune to start_all, stop_all, and delete_all commands.
CLI Commands
zinit list # List all services
zinit status <name> # Show service status
zinit start <name> # Start a service
zinit stop <name> # Stop (cascades to dependents)
zinit restart <name> # Restart a service
zinit kill <name> [signal] # Send signal to service
zinit logs <name> [-n N] # View service logs
zinit why <name> # Show why service is blocked
zinit tree # Show dependency tree
zinit reload # Reload configuration
zinit add-service <toml> # Add service at runtime
zinit remove-service <name> # Remove a service
zinit start-all # Start all user-class services
zinit stop-all # Stop all user-class services
zinit delete-all # Delete all user-class services
zinit shutdown # Stop all services, exit daemon
zinit poweroff # Power off system (signals init)
zinit reboot # Reboot system (signals init)
# Debug commands
zinit debug-state # Full graph state dump
zinit debug-procs <name> # Process tree for a service
Environment Variables
| Variable | Default | Description |
|---|---|---|
ZINIT_LOG_LEVEL |
info |
Log level: trace, debug, info, warn, error |
ZINIT_CONFIG_DIR |
/etc/zinit/services |
Service config directory |
ZINIT_SOCKET |
/var/run/zinit.sock |
Unix socket path |
ZINIT_CONTAINER |
unset | If set, zinit-pid1 runs in container mode |
Docker Usage
# Build test image
docker build -t zinit-test -f docker/Dockerfile .
# Run (uses container mode automatically)
docker run -it --rm zinit-test
# With debug logging
docker run -it --rm -e ZINIT_LOG_LEVEL=debug zinit-test
# Explicit container mode
docker run -it --rm -e ZINIT_CONTAINER=1 zinit-test
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:
zinit stop databasestops worker, then app, then database- Dependencies are NOT auto-stopped (other services may need them)
Development
cargo check --workspace # Verify builds
cargo test --workspace # Run tests
cargo build --release --workspace # Build all binaries
cargo clippy --workspace # Lint
License
See LICENSE file.