|
|
@@ -0,0 +1,295 @@
|
|
|
+---
|
|
|
+name: process-compose-ops
|
|
|
+description: "Process Compose orchestration for non-containerized local services. Use for: process-compose.yaml schema, replacing PM2/supervisord/Foreman, health checks (readiness_probe, liveness_probe), restart policies (always/exit_on_failure/no), process dependencies (depends_on conditions), TUI navigation and shortcuts (F4 maximize, Tab panes, r/s/t process control), REST API and MCP server integration, headless mode (-t=false for daemons), per-process and consolidated logging (log_location), cron and interval scheduling (availability.schedule), namespace grouping for multi-stack composition, environment variable handling (env files, secrets), Windows Task Scheduler boot persistence, supply-chain verified single-binary install, multi-replica processes, foreground/serial execution patterns, dry-run validation, project update (hot reload without restart), process restart/stop/start via CLI or TUI, log tailing and follow modes, shutdown timeouts and signals, agent-friendly MCP tools for process control."
|
|
|
+license: MIT
|
|
|
+allowed-tools: "Read Write Bash Edit"
|
|
|
+metadata:
|
|
|
+ author: claude-mods
|
|
|
+ related-skills: portless-ops, docker-ops, cli-ops
|
|
|
+ upstream: https://github.com/F1bonacc1/process-compose
|
|
|
+---
|
|
|
+
|
|
|
+# Process Compose Operations
|
|
|
+
|
|
|
+Process Compose is a Go-based supervisor for non-containerized services. Single binary, YAML config, built-in TUI, REST API, **MCP server**, and proper Windows support. Replacement for PM2/supervisord/Foreman in the local-dev role.
|
|
|
+
|
|
|
+**Why not PM2:** PM2 5.x has 15+ known CVEs (axios/lodash/tar/minimist transitive npm exposure). PC compiles all deps in at build time with `go.sum` hashes — structurally resistant to TanStack-style npm worm attacks.
|
|
|
+
|
|
|
+**Why not Docker Compose:** Container overhead is unnecessary for local Python/Node/Go dev servers running directly. PC gives you health checks, dependencies, and restart policies without the container layer.
|
|
|
+
|
|
|
+## Install (verified)
|
|
|
+
|
|
|
+```bash
|
|
|
+# Pin a specific version, verify SHA-256 against upstream checksums
|
|
|
+VER="v1.110.0"
|
|
|
+BASE="https://github.com/F1bonacc1/process-compose/releases/download/$VER"
|
|
|
+
|
|
|
+curl -fsSL -o pc.zip "$BASE/process-compose_windows_amd64.zip"
|
|
|
+curl -fsSL -o checksums.txt "$BASE/process-compose_checksums.txt"
|
|
|
+
|
|
|
+EXPECTED=$(grep "process-compose_windows_amd64.zip" checksums.txt | awk '{print $1}')
|
|
|
+ACTUAL=$(sha256sum pc.zip | awk '{print $1}')
|
|
|
+[ "$EXPECTED" = "$ACTUAL" ] || { echo "HASH MISMATCH"; exit 1; }
|
|
|
+
|
|
|
+unzip pc.zip
|
|
|
+# Commit process-compose.exe to your repo's bin/ directory
|
|
|
+```
|
|
|
+
|
|
|
+Record the binary's hash in your repo's `SUPPLY-CHAIN.md` for re-verification on next upgrade.
|
|
|
+
|
|
|
+## process-compose.yaml Quick Reference
|
|
|
+
|
|
|
+```yaml
|
|
|
+version: "0.5"
|
|
|
+
|
|
|
+log_level: info
|
|
|
+log_length: 1000
|
|
|
+
|
|
|
+processes:
|
|
|
+
|
|
|
+ my-service:
|
|
|
+ command: "pythonw -m uvicorn main:app --host 127.0.0.1 --port 8000"
|
|
|
+ working_dir: "X:/path/to/repo"
|
|
|
+ environment:
|
|
|
+ - "DJANGO_SETTINGS_MODULE=myapp.settings"
|
|
|
+ - "PYTHONUNBUFFERED=1"
|
|
|
+ readiness_probe:
|
|
|
+ http_get:
|
|
|
+ host: localhost
|
|
|
+ port: 8000
|
|
|
+ path: /
|
|
|
+ initial_delay_seconds: 5
|
|
|
+ period_seconds: 10
|
|
|
+ timeout_seconds: 3
|
|
|
+ failure_threshold: 3
|
|
|
+ availability:
|
|
|
+ restart: always # always | exit_on_failure | on_failure | no
|
|
|
+ backoff_seconds: 5
|
|
|
+ max_restarts: 20
|
|
|
+ depends_on:
|
|
|
+ database:
|
|
|
+ condition: process_healthy # process_started | process_healthy | process_completed
|
|
|
+ shutdown:
|
|
|
+ signal: 15 # SIGTERM
|
|
|
+ timeout_seconds: 30
|
|
|
+ log_location: "logs/my-service.log"
|
|
|
+
|
|
|
+ scheduled-job:
|
|
|
+ command: "python backup.py"
|
|
|
+ schedule: "0 2 * * *" # 2am daily cron
|
|
|
+ availability:
|
|
|
+ restart: exit_on_failure
|
|
|
+```
|
|
|
+
|
|
|
+## Restart Policies
|
|
|
+
|
|
|
+| Policy | Restarts on... |
|
|
|
+|---|---|
|
|
|
+| `always` | Any exit (success or failure) — best for long-running daemons |
|
|
|
+| `on_failure` | Non-zero exit codes only |
|
|
|
+| `exit_on_failure` | Stops PC entirely if this process fails — use for critical deps |
|
|
|
+| `no` | Never restart |
|
|
|
+
|
|
|
+## Dependency Conditions
|
|
|
+
|
|
|
+| Condition | Wait until... |
|
|
|
+|---|---|
|
|
|
+| `process_started` | Dependency spawned (PID exists). Fastest, weakest guarantee. |
|
|
|
+| `process_healthy` | Dependency's readiness_probe passes. Strong guarantee. |
|
|
|
+| `process_completed` | Dependency exited successfully (for init/setup processes). |
|
|
|
+
|
|
|
+## CLI Reference
|
|
|
+
|
|
|
+```bash
|
|
|
+# Lifecycle
|
|
|
+process-compose up -f config.yaml # Start (foreground TUI by default)
|
|
|
+process-compose up -f config.yaml -t=false # Headless (no TUI)
|
|
|
+process-compose up -f config.yaml --dry-run # Validate config without starting
|
|
|
+process-compose down # Stop all processes + project
|
|
|
+
|
|
|
+# Inspection (against running PC)
|
|
|
+process-compose -p 8888 process list # all processes + status
|
|
|
+process-compose -p 8888 process logs <name> --follow
|
|
|
+process-compose -p 8888 attach # TUI for running project
|
|
|
+
|
|
|
+# Process control
|
|
|
+process-compose -p 8888 process restart <name>
|
|
|
+process-compose -p 8888 process stop <name>
|
|
|
+process-compose -p 8888 process start <name>
|
|
|
+
|
|
|
+# Reload config without stopping (hot update)
|
|
|
+process-compose -p 8888 project update -f config.yaml
|
|
|
+
|
|
|
+# Standalone inspection (no running PC)
|
|
|
+process-compose info # config home info
|
|
|
+process-compose graph -f config.yaml # dependency graph
|
|
|
+process-compose analyze -f config.yaml # startup timing analysis
|
|
|
+```
|
|
|
+
|
|
|
+**Key flag gotcha:** there's no `--detached` flag. To run in background:
|
|
|
+- Linux/Mac: `process-compose up -t=false &` (shell backgrounding)
|
|
|
+- Windows: launch via Task Scheduler or `Start-Process` with `-WindowStyle Hidden`
|
|
|
+
|
|
|
+## TUI Navigation
|
|
|
+
|
|
|
+Launch: `process-compose attach` (or `up` without `-t=false`).
|
|
|
+
|
|
|
+| Key | Action |
|
|
|
+|---|---|
|
|
|
+| `↑` `↓` or `j` `k` | Navigate process list |
|
|
|
+| `Tab` | Switch focus between process list and log pane |
|
|
|
+| `F4` | Maximize current pane (toggle) |
|
|
|
+| `F5` | Unfollow logs (lets you scroll history) |
|
|
|
+| `F6` | Unwrap log lines |
|
|
|
+| `r` | Restart selected process |
|
|
|
+| `s` | Stop selected process |
|
|
|
+| `t` | Start selected process |
|
|
|
+| `/` | Filter process list |
|
|
|
+| `?` | Help overlay |
|
|
|
+| `q` | Quit TUI (PC keeps running in background) |
|
|
|
+
|
|
|
+## MCP Server Integration
|
|
|
+
|
|
|
+PC ships a built-in MCP server exposing processes as tools for AI agents. Enable via the config or CLI flag. With the MCP server on, a Claude Code agent can directly:
|
|
|
+
|
|
|
+- List running processes
|
|
|
+- Get process status/health
|
|
|
+- Restart/stop/start processes
|
|
|
+- Read process logs
|
|
|
+
|
|
|
+This replaces shell-based glue scripts (the old PM2-broker pattern).
|
|
|
+
|
|
|
+## API Port Selection
|
|
|
+
|
|
|
+Default API port is 8080. Common collisions:
|
|
|
+
|
|
|
+| Port 8080 user | Workaround |
|
|
|
+|---|---|
|
|
|
+| Dagu dashboard | Use `-p 8888` until Dagu decommissioned |
|
|
|
+| Tomcat / Spring Boot dev | Use `-p 8888` |
|
|
|
+| Other dev tool defaults | Pick anything free in 8000–9999 range |
|
|
|
+
|
|
|
+If you change the API port, every subsequent CLI call needs `-p <port>`:
|
|
|
+
|
|
|
+```bash
|
|
|
+process-compose -p 8888 process list
|
|
|
+process-compose -p 8888 process logs axiom --follow
|
|
|
+```
|
|
|
+
|
|
|
+## Windows Boot Persistence Pattern
|
|
|
+
|
|
|
+Task Scheduler runs with minimal PATH. Use a wrapper script that sets PATH explicitly before launching PC.
|
|
|
+
|
|
|
+```powershell
|
|
|
+# scripts/boot-start.ps1
|
|
|
+$root = "X:\00_Orchestration\compose-portless"
|
|
|
+$pcExe = "$root\bin\process-compose.exe"
|
|
|
+
|
|
|
+# Explicit PATH for managed services (Python, uv, Git tools, cloudflared, etc.)
|
|
|
+$env:PATH = (@(
|
|
|
+ "$root\bin"
|
|
|
+ "C:\Program Files\Git\usr\bin" # openssl, bash
|
|
|
+ "C:\Users\<user>\AppData\Local\Programs\Python\Python313\Scripts"
|
|
|
+ "$env:PATH"
|
|
|
+) -join ';')
|
|
|
+
|
|
|
+# Optional: source secrets from gitignored .env
|
|
|
+$envFile = "$root\.env"
|
|
|
+if (Test-Path $envFile) {
|
|
|
+ Get-Content $envFile | ForEach-Object {
|
|
|
+ if ($_ -match '^\s*([A-Z_]+)\s*=\s*(.+?)\s*$') {
|
|
|
+ [Environment]::SetEnvironmentVariable($matches[1], $matches[2], 'Process')
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+# Launch headless
|
|
|
+& $pcExe -p 8888 -t=false -L "$root\logs\process-compose.log" up -f "$root\process-compose.yaml"
|
|
|
+```
|
|
|
+
|
|
|
+Register as a Task Scheduler entry with `LogonType S4U` (runs at boot, no password, no interactive logon needed):
|
|
|
+
|
|
|
+```powershell
|
|
|
+$principal = New-ScheduledTaskPrincipal -UserId $env:USERNAME -LogonType S4U -RunLevel Highest
|
|
|
+$action = New-ScheduledTaskAction -Execute "powershell.exe" `
|
|
|
+ -Argument "-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$root\scripts\boot-start.ps1`""
|
|
|
+$trigger = New-ScheduledTaskTrigger -AtStartup
|
|
|
+Register-ScheduledTask -TaskName "ProcessCompose-Boot" `
|
|
|
+ -Action $action -Trigger $trigger -Principal $principal -Force
|
|
|
+```
|
|
|
+
|
|
|
+## YAML Gotchas
|
|
|
+
|
|
|
+| Gotcha | Symptom | Fix |
|
|
|
+|---|---|---|
|
|
|
+| Windows PATH with backslashes in double-quoted YAML | `yaml: found unknown escape character` | Use single quotes: `- 'PATH=C:\Program Files\Git\usr\bin;...'` |
|
|
|
+| `command` with quoted paths containing spaces | First arg eaten | Wrap whole command in single quotes, inner paths in double: `'"C:/Program Files/foo.exe" arg1 arg2'` |
|
|
|
+| Forgot `working_dir` | Process starts in PC's cwd, can't find files | Always specify absolute `working_dir` |
|
|
|
+| Health probe wrong port | Process restart-loops with `Not Ready` | Match `readiness_probe.http_get.port` to where the process actually binds |
|
|
|
+| Secrets in YAML | Committed to git | Use `environment` to pass-through; set in shell env or gitignored `.env` |
|
|
|
+
|
|
|
+## Common Operations
|
|
|
+
|
|
|
+```bash
|
|
|
+# Validate config before applying
|
|
|
+process-compose up --dry-run -f process-compose.yaml
|
|
|
+
|
|
|
+# Hot-reload after editing config
|
|
|
+process-compose -p 8888 project update -f process-compose.yaml
|
|
|
+
|
|
|
+# Restart one service after code change
|
|
|
+process-compose -p 8888 process restart axiom
|
|
|
+
|
|
|
+# Watch logs of a misbehaving service
|
|
|
+process-compose -p 8888 process logs axiom --follow
|
|
|
+
|
|
|
+# Stop one service temporarily for debugging
|
|
|
+process-compose -p 8888 process stop axiom
|
|
|
+# Now run it manually with your debugger, then:
|
|
|
+process-compose -p 8888 process start axiom
|
|
|
+```
|
|
|
+
|
|
|
+## When to Use Process Compose vs Alternatives
|
|
|
+
|
|
|
+| Need | Tool |
|
|
|
+|---|---|
|
|
|
+| Local non-containerized services with health/dependencies/MCP | **Process Compose** |
|
|
|
+| Production node.js process supervision | PM2 (despite age) |
|
|
|
+| Container-based stack | Docker Compose |
|
|
|
+| Job queue with cron + DAGs | Dagu, Temporal, Airflow |
|
|
|
+| System service supervision | systemd (Linux), Windows Services |
|
|
|
+| One-shot Procfile run | Foreman / Overmind / Hivemind (Unix-only) |
|
|
|
+
|
|
|
+## Worked Example
|
|
|
+
|
|
|
+See `X:\00_Orchestration\compose-portless\` for an 11-process production stack:
|
|
|
+- `process-compose.yaml` — health-checked services with depends_on chains
|
|
|
+- `scripts/boot-start.ps1` — PATH-aware boot wrapper
|
|
|
+- `docs/MIGRATION-LOG.md` — full migration from PM2 + Caddy, every gotcha documented
|
|
|
+- `docs/SUPPLY-CHAIN.md` — binary verification procedure
|
|
|
+
|
|
|
+## Anti-Patterns
|
|
|
+
|
|
|
+```
|
|
|
+BAD: process-compose up --detached # flag does not exist
|
|
|
+GOOD: process-compose up -t=false & # background via shell
|
|
|
+
|
|
|
+BAD: put secrets in process-compose.yaml (commits to git)
|
|
|
+GOOD: source from gitignored .env in boot wrapper
|
|
|
+
|
|
|
+BAD: use API port 8080 (clashes with Dagu, Tomcat, others)
|
|
|
+GOOD: -p 8888 (or any free port), document the choice
|
|
|
+
|
|
|
+BAD: ignore readiness_probe and just hope services come up
|
|
|
+GOOD: configure http_get probe on a real endpoint; depends_on uses process_healthy
|
|
|
+
|
|
|
+BAD: upgrade PC by running an installer (npm install -g, scoop install, brew install)
|
|
|
+GOOD: download specific version, verify SHA-256 against upstream checksums.txt, commit binary
|
|
|
+```
|
|
|
+
|
|
|
+## Related Skills
|
|
|
+
|
|
|
+- `portless-ops` — the routing layer we pair with PC (replaces Caddy)
|
|
|
+- `docker-ops` — container alternative for the same role
|
|
|
+- `mcp-ops` — PC's MCP server fits this ecosystem
|
|
|
+- `cli-ops` — general CLI tool patterns
|