- Rust 88.9%
- Shell 9.3%
- Makefile 1.7%
setpgid(0,0) only creates a new process group. agetty needs setsid() to become a session leader — required for TIOCSCTTY to succeed. Without this, the ioctl fails with EPERM and Ctrl-C/Z are broken. |
||
|---|---|---|
| .claude | ||
| .forgejo/workflows | ||
| crates | ||
| docker | ||
| docs | ||
| etc/my_init | ||
| examples | ||
| scripts | ||
| tests | ||
| .gitignore | ||
| ARCHITECTURE.md | ||
| buildenv.sh | ||
| Cargo.lock | ||
| Cargo.toml | ||
| LICENSE | ||
| Makefile | ||
| README.md | ||
my_init
A lightweight process supervisor with dependency management, similar to systemd but simpler.
📚 Documentation
Welcome! MyInit documentation is organized into three categories:
- Getting Started Guide: A step-by-step tutorial to running your first service.
- CLI Reference: Detailed guide for the
my_initcommand-line tool. - Configuration Guide: Reference for the service TOML specification.
- Architecture Overview: High-level design and production hardening features.
- Full Documentation Index: Index of all technical references and specifications.
Quick Install
Get started in one command:
curl -fsSL https://forge.ourworld.tf/geomind_code/my_init/raw/branch/main/scripts/install.sh | bash
Or download and run the installer script directly:
cd /tmp && curl -O https://forge.ourworld.tf/geomind_code/my_init/raw/branch/main/scripts/install.sh
chmod +x install.sh
./install.sh
This will:
- Detect your OS and architecture
- Download pre-built binaries (Linux amd64, macOS arm64)
- Install to
$HOME/hero/bin - Configure your shell PATH automatically
- Start
my_init_serverin background (macOS/Windows only)
Features
- Dependency Graph: Services declare dependencies (
requires,after,wants,conflicts) - State Machine: 8 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
- Production Hardening: OOM protection (-1000 for PID 1), supervisor watchdog, and environment sanitization
- User/Group Support: Run services as specific users/groups for least-privilege security
- Hot Reload: Reload configuration without full restart
- Multi-Environment: Works in containers, VMs, and bare-metal
- Web Admin Dashboard: Real-time service management UI with charts, logs, events, and bulk operations
- Fully Embedded UI: All assets (Bootstrap, Chart.js, icons) compiled into the binary — no CDN or network required
Deployment Modes
my_init adapts its behavior based on deployment environment:
Container Mode
Use my_init_pid1 as your container entrypoint:
ENTRYPOINT ["/usr/bin/my_init_pid1", "--container"]
Or set the environment variable:
MY_INIT_CONTAINER=1 my_init_pid1
Behavior:
- Loads services from
/etc/my_init/services/ - Clean exit on shutdown (no reboot syscall)
- No system services directory
VM / Bare-Metal Mode
Use my_init_pid1 as your init system (PID 1):
# In /sbin/init or kernel cmdline: init=/usr/bin/my_init_pid1
Behavior:
- Loads system services from
/etc/my_init/system/first (auto-assignedclass=system) - Loads user services from
/etc/my_init/services/second - Handles reboot/poweroff via syscalls (SIGINT=reboot, SIGTERM=poweroff)
- Never exits (kernel panic prevention)
Standalone Mode
Run my_init_server directly (not as PID 1):
my_init_server --config-dir /etc/my_init/services
Optionally enable system services directory:
my_init_server --config-dir /etc/my_init/services --pid1-mode
Quick Start
Installation (Recommended)
Download and install pre-built binaries:
./scripts/install.sh
This script:
- Detects your OS and architecture
- Downloads binaries from Forgejo registry
- Installs to
$HOME/hero/bin - Configures your PATH automatically
- On macOS/Windows, automatically starts the server in the background
Building from Source
# Full build with Makefile
make build
# Or manual build
cargo build --release --workspace
# Run the server + admin UI
make run
# Use the CLI
my_init list
my_init status my-service
my_init start my-service
my_init stop my-service
See scripts/README.md for detailed information about installation scripts and the Makefile for build targets.
Architecture
my_init_pid1 (PID 1 shim)
| spawns/monitors
v
my_init_server (daemon)
| unix socket (IPC + OpenRPC)
v
my_init (CLI/TUI) my_init_ui (web admin dashboard)
Crate Structure
my_init is organized as a Cargo workspace with separate crates:
crates/
my_init_sdk/ # Library: shared types, protocol, client implementations
my_init_server/ # Binary: process supervisor daemon (IPC + OpenRPC)
my_init/ # Binary: CLI client and TUI
my_init_ui/ # Binary: web admin dashboard
my_init_pid1/ # Binary: PID 1 init shim (Linux only)
Dependency Graph
my_init_sdk (no internal deps)
^ ^ ^ ^
| | | |
server CLI UI pid1
All crates depend only on my_init_sdk. No cross-dependencies between server, CLI, UI, or pid1.
Ports and Sockets
| Component | Binding | Default |
|---|---|---|
| my_init_server | Unix socket (IPC) | ~/hero/var/sockets/my_init_server.sock |
| my_init_server | TCP (API, optional, disable with --web-port 0) |
3875 |
| my_init_ui | TCP (HTTP dashboard) | 9880 |
| my_init_ui | Unix socket (local tool access) | ~/hero/var/sockets/my_init_admin.sock |
Configuration
Service configs are TOML files in the config directory (default: /etc/my_init/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
my_init list # List all services
my_init status <name> # Show service status
my_init start <name> # Start a service
my_init stop <name> # Stop (cascades to dependents)
my_init restart <name> # Restart a service
my_init kill <name> [signal] # Send signal to service
my_init logs <name> [-n N] # View service logs
my_init why <name> # Show why service is blocked
my_init tree # Show dependency tree
my_init reload # Reload configuration
my_init add-service <toml> # Add service at runtime
my_init remove-service <name> # Remove a service
my_init start-all # Start all user-class services
my_init stop-all # Stop all user-class services
my_init delete-all # Delete all user-class services
my_init shutdown # Stop all services, exit daemon
my_init poweroff # Power off system (signals init)
my_init reboot # Reboot system (signals init)
# Debug commands
my_init debug-state # Full graph state dump
my_init debug-procs <name> # Process tree for a service
Web Admin Dashboard
The my_init_ui crate provides a real-time web admin dashboard at http://localhost:9880:
- Services tab: Live service list with state badges, PID, memory usage, restart counts
- Tasks tab: Oneshot service results with exit codes
- Add Service: Full form for creating/editing services with all config options
- Logs: Per-service log viewer with ANSI color support, stream filtering, auto-refresh
- Events: Real-time event stream with filtering
- Reset All: Bulk stop and delete all services with confirmation
- API Docs: Interactive OpenRPC documentation
- MCP: Model Context Protocol connection details for AI tool integration
- Charts: Memory usage history graph, service state distribution
All UI assets (Bootstrap 5.3.3, Bootstrap Icons, Chart.js) are embedded in the binary via rust-embed — no internet connection needed.
The UI connects to my_init_server via the SDK (AsyncMyInitClient) over Unix socket.
# Start server + UI
make run
# Or start separately
my_init_server --config-dir ~/hero/cfg/my_init &
my_init_ui --port 9880
Path Configuration
my_init uses platform-specific default paths. For details, see the Path Configuration guide.
Environment Variables
| Variable | Default | Description |
|---|---|---|
MY_INIT_LOG_LEVEL |
info |
Log level: trace, debug, info, warn, error |
MY_INIT_CONFIG_DIR |
Platform-specific (see above) | Service config directory |
MY_INIT_SOCKET |
Platform-specific (see above) | Unix socket path |
MY_INIT_CONTAINER |
unset | If set, my_init_pid1 runs in container mode |
Example: Custom Paths
# Use custom config and socket directories
export MY_INIT_CONFIG_DIR=/opt/my-services
export MY_INIT_SOCKET=/tmp/my-my_init.sock
# Start server
my_init_server
# Connect with CLI
my_init list
Library Usage
Use my_init_sdk as a library dependency:
use my_init_sdk::{MyInitClient, ServiceConfig};
// Blocking client
let socket = my_init_sdk::socket::default_path();
let mut client = MyInitClient::connect_unix(&socket)?;
let services = client.list()?;
// Async client
use my_init_sdk::AsyncMyInitClient;
let mut client = AsyncMyInitClient::connect_unix(&socket).await?;
let status = client.status("my-service").await?;
Docker Usage
# Build test image
docker build -t my_init-test -f docker/Dockerfile .
# Run (uses container mode automatically)
docker run -it --rm my_init-test
# With debug logging
docker run -it --rm -e MY_INIT_LOG_LEVEL=debug my_init-test
# Explicit container mode
docker run -it --rm -e MY_INIT_CONTAINER=1 my_init-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:
my_init 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 lint # Run clippy linter
make test-all # Run all tests (unit + bash)
# Run specific integration tests
make test-bash # Legacy bash-based tests
# Playground
make play-tui # Launch TUI with sample services for manual testing
make play-web # Launch web UI with sample services
License
See LICENSE file.