Architecture
Technical overview of pitchfork's internal design.
System Overview
┌────────────────────────────────────────────────────────────┐
│ USER │
│ pitchfork start/stop/status/run/logs │
└───────────────────────────┬────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────┐
│ CLI │
│ • Reads pitchfork.toml configs │
│ • Sends IPC requests │
└───────────────────────────┬────────────────────────────────┘
│ Unix Socket
│ ~/.local/state/pitchfork/ipc/main.sock
▼
┌────────────────────────────────────────────────────────────┐
│ SUPERVISOR │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ IPC Server │ │ Interval │ │ Cron │ │
│ │ │ │ Watcher │ │ Watcher │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ │ │ │ │
│ └────────────────┼────────────────┘ │
│ ▼ │
│ ┌───────────────────────┐ │
│ │ Daemon Management │ │
│ │ • spawn processes │ │
│ │ • monitor output │ │
│ │ • handle retries │ │
│ └───────────────────────┘ │
└────────────────────────────────────────────────────────────┘
│
┌──────────────┼──────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Daemon │ │ Daemon │ │ Daemon │
└─────────┘ └─────────┘ └─────────┘Components
| Component | Purpose |
|---|---|
| CLI | User commands, config parsing, IPC client |
| Supervisor | Background daemon, process management |
| IPC | Unix socket communication (MessagePack) |
| State File | Persistent state in TOML with file locking |
Supervisor Auto-Start
When you run a command like pitchfork start, the CLI:
- Checks if the supervisor is running
- If not, starts it in the background
- Connects via Unix socket
- Sends the command
The supervisor runs independently and manages all daemons.
Background Watchers
Interval Watcher (10 seconds)
- Refreshes process list (checks which PIDs are alive)
- Handles autostop (stops daemons when shell leaves directory)
- Retries failed daemons with remaining retry attempts
Cron Watcher (60 seconds)
- Checks daemons with cron schedules
- Triggers according to retrigger policy
Daemon States
| State | Meaning |
|---|---|
| Running | Process is alive |
| Waiting | Waiting for ready check |
| Stopped | Exited successfully (code 0) |
| Errored | Exited with error (code ≠ 0) |
State Persistence
Daemon state is stored in ~/.local/state/pitchfork/state.toml:
toml
[daemons.myapp]
id = "myapp"
pid = 12345
status = "running"
dir = "/path/to/project"
autostop = true
retry = 2
retry_count = 0
[disabled]
# Set of disabled daemon IDs
[shell_dirs]
# Map of shell_pid → working_directoryAll state file access uses file locking for concurrent safety.
Process Spawning
When starting a daemon:
- Check if already running
- Prepend
execto command (eliminates shell wrapper) - Create log file
- Spawn process with piped stdout/stderr
- Record PID in state file
- Start monitoring for readiness
Readiness Detection
| Method | Trigger |
|---|---|
| Delay | Wait N seconds, still running = ready |
| Output | Regex matches stdout/stderr |
| HTTP | Endpoint returns 2xx |
First check to succeed marks daemon as ready.
