No description
  • Rust 88.9%
  • Shell 9.3%
  • Makefile 1.7%
Find a file
Jan De Landtsheer e8e8429969
Some checks failed
Build and Test / build (push) Failing after 1m10s
Tests / test (push) Failing after 1m45s
fix: use setsid() for interactive services so getty can acquire TTY
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.
2026-04-05 16:06:25 +02:00
.claude chore: remove stale plan files, update settings 2026-03-27 08:32:35 +01:00
.forgejo/workflows Implement hardened process shim with cgroup v2 tracking 2026-03-19 23:26:45 +02:00
crates fix: use setsid() for interactive services so getty can acquire TTY 2026-04-05 16:06:25 +02:00
docker chore: remove all remaining zinit references from codebase 2026-03-23 14:24:49 +01:00
docs fix: use setsid() for interactive services so getty can acquire TTY 2026-04-05 16:06:25 +02:00
etc/my_init feat: per-service spawn mode configuration (ADR 015) 2026-04-05 15:48:02 +02:00
examples docs: comprehensive audit and update to reflect current reality 2026-03-19 19:44:14 +02:00
scripts feat: rename project to my_init 2026-03-19 17:13:33 +02:00
tests feat: per-service spawn mode configuration (ADR 015) 2026-04-05 15:48:02 +02:00
.gitignore feat: port from zinit and cleanup 2026-03-17 10:38:34 +02:00
ARCHITECTURE.md docs: comprehensive audit and update to reflect current reality 2026-03-19 19:44:14 +02:00
buildenv.sh chore: remove all remaining zinit references from codebase 2026-03-23 14:24:49 +01:00
Cargo.lock fix: remove rust-version directive from all workspace crates 2026-04-04 13:08:41 +02:00
Cargo.toml bump: v0.4.0 — three-state health checks, start timeout fix 2026-04-04 13:05:12 +02:00
LICENSE Initial commit 2026-03-17 06:16:12 +00:00
Makefile feat: rename project to my_init 2026-03-19 17:13:33 +02:00
README.md docs: complete reorganization and cleanup 2026-03-19 19:55:17 +02:00

my_init

A lightweight process supervisor with dependency management, similar to systemd but simpler.


📚 Documentation

Welcome! MyInit documentation is organized into three categories:


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_server in 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 -c child 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-assigned class=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

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 running
  • stop: 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 *_all commands
  • system: 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 database stops 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.