Skip to content

Releases: jdx/pitchfork

v2.0.0: Namespaces, Port Management, and File Watching

04 Mar 14:10
@jdx jdx
Immutable release. Only release title and notes can be modified.
95d8824

Choose a tag to compare

Pitchfork v2.0.0 is a major release that introduces namespace-qualified daemon IDs, port conflict management, and several important bug fixes. The namespace change is breaking -- daemon IDs are now in namespace/name format -- but short IDs continue to work when unambiguous, and legacy log directories are automatically migrated.

Highlights

  • Namespaces: Daemons across different projects no longer collide. Each project gets a namespace (derived from directory name or explicit config), and daemon IDs become namespace/name. Short names still work when you're inside the project directory.
  • Port conflict detection: Daemons can declare expected ports and opt into auto-bump, so pitchfork will find an available port if the configured one is already in use.
  • File watching actually works: The watch config field was previously broken -- patterns were lost after daemon startup. This release rewrites the watcher to persist patterns in state and dynamically pick up new daemons.

Added

  • Port conflict detection and auto-bump: Declare expected_port and auto_bump_port in your daemon config, and pitchfork will check for conflicts before starting and automatically increment ports if needed. Resolved ports are injected as PORT, PORT0, PORT1, etc. environment variables. New CLI flags --expected-port and --auto-bump-port are available on run, start, and config add. A network view (press p in the TUI) shows all listening processes. (#259) - @benjaminwestern

    [daemons.api]
    run = "npm run dev"
    expected_port = [3000]
    auto_bump_port = true

Fixed

  • File watching for daemon auto-restart: The watch field in pitchfork.toml was documented but non-functional. Watch patterns and base directories are now persisted in daemon state and the watcher dynamically refreshes every 10 seconds to pick up new daemons. (#255) - @benjaminwestern
  • pitchfork config add generates valid TOML: Previously, pitchfork config add joined all arguments into a single run string, producing broken config. It now accepts proper CLI flags (--run, --retry, --watch, --depends, --env, etc.) and generates correct TOML with each option as a separate field. (#258) - @benjaminwestern
  • pitchfork logs --tail bypasses pager: Using --tail no longer opens less and blocks with (END) -- logs now stream directly to stdout. (#253) - @jdx
  • TUI log rendering and scroll behavior: Fixed text wrapping causing lines to be hidden below the viewport. The scroll model was rewritten to track the last visible line rather than the first, and tab characters and ANSI clear-screen codes are now stripped from log output. (#264) - @dimmyjing

Breaking Changes

  • Daemon IDs now include a namespace: All daemon IDs are internally stored as namespace/name (e.g., frontend/api). The namespace is derived from the project directory name, or can be explicitly set with namespace = "..." at the top of pitchfork.toml. Short IDs (e.g., api) continue to work when unambiguous. The PITCHFORK_DAEMON_ID environment variable now contains the fully-qualified ID, and a new PITCHFORK_DAEMON_NAMESPACE variable is available. Log directories are renamed from <name>/ to <namespace>--<name>/; existing logs are automatically migrated to a legacy namespace. The depends field now accepts cross-namespace references (e.g., global/postgres). (#213) - @gaojunran

    If you have scripts that parse PITCHFORK_DAEMON_ID, they will now receive namespace/name instead of just name. Directory names containing -- are reserved for internal encoding and will require an explicit namespace override.

New Contributors

Full Changelog: v1.6.0...v2.0.0

v1.6.0: Lifecycle Hooks and Reverse Proxy Support

21 Feb 17:22
@jdx jdx
Immutable release. Only release title and notes can be modified.
5f59d71

Choose a tag to compare

Pitchfork v1.6.0 adds daemon lifecycle hooks for reacting to ready, failure, and retry events, along with new environment variables injected into every daemon process. This release also adds support for serving the web UI behind a reverse proxy path prefix and fixes ready_cmd to respect the daemon's working directory.

Highlights

  • Lifecycle hooks: Run custom shell commands when daemons become ready, fail, or retry via a new [daemons.<name>.hooks] config section
  • Daemon metadata env vars: Every daemon process now receives PITCHFORK_DAEMON_ID and PITCHFORK_RETRY_COUNT automatically
  • Reverse proxy path prefixes: Serve the web UI under a custom path using --web-path or PITCHFORK_WEB_PATH

Added

  • Daemon lifecycle hooks -- Configure on_ready, on_fail, and on_retry hooks under [daemons.<name>.hooks] to fire shell commands in response to daemon events. Hooks are fire-and-forget and run in the daemon's working directory. (#245) - @jdx

    [daemons.api]
    run = "node server.js"
    retry = 3
    
    [daemons.api.hooks]
    on_ready = "echo 'api is ready'"
    on_fail = "./scripts/cleanup.sh"
    on_retry = "echo 'retrying...'"
  • Daemon process environment variables -- PITCHFORK_DAEMON_ID and PITCHFORK_RETRY_COUNT are now automatically set for every daemon process and its hooks. The on_fail hook additionally receives PITCHFORK_EXIT_CODE. (#245) - @jdx

  • Web UI path prefix support -- Use --web-path <PATH> or PITCHFORK_WEB_PATH=<PATH> to serve the web UI under a subpath, making it easy to run behind a reverse proxy. All routes, links, HTMX polling, SSE streaming, and static assets work correctly under the prefix. (#244) - @jdx

    PITCHFORK_WEB_PORT=9001 PITCHFORK_WEB_PATH=ps pitchfork supervisor run
    # Web UI is then available at /ps/ on port 9001

Fixed

  • ready_cmd now respects daemon working directory -- The readiness check command (ready_cmd) previously ran in the supervisor's directory rather than the daemon's configured dir. It now correctly uses the daemon's working directory. (#243) - @gaojunran

New Contributors

Full Changelog: v1.5.0...v1.6.0

v1.5.0: Cleaner process shutdowns

16 Feb 23:25
@jdx jdx
Immutable release. Only release title and notes can be modified.
68fefa6

Choose a tag to compare

This release improves how pitchfork stops daemons and their child processes, making shutdown more reliable and eliminating orphaned processes.

Highlights

  • Process group-based shutdown — Pitchfork now spawns each daemon in its own process group via setsid() and uses killpg() to signal the entire group at once. This replaces the old approach of walking /proc to find children, which was prone to race conditions where a child could fork between the scan and the kill. Daemons that spawn multiple children (e.g. npm run dev) will now shut down cleanly and atomically. #239

  • SIGKILL escalation after SIGTERM — When a daemon doesn't respond to SIGTERM, pitchfork now automatically escalates to SIGKILL to ensure the process is terminated. No more stuck daemons that ignore graceful shutdown signals. #238 — thanks @gaojunran!

For full documentation, see pitchfork.jdx.dev.

v1.4.3: State file bug fix

12 Feb 00:56
@jdx jdx
Immutable release. Only release title and notes can be modified.
3d9625e

Choose a tag to compare

A small patch release fixing an issue where errored daemons could corrupt the state file.

Bug Fixes

  • Fixed invalid state file when daemons error without an exit code — When a daemon entered an errored state without a known exit code, the state file could become unreadable due to TOML's lack of null support. Pitchfork now handles unknown exit codes gracefully, preventing state file corruption. (#231)

v1.4.1

11 Feb 19:28
@jdx jdx
Immutable release. Only release title and notes can be modified.
a04ab34

Choose a tag to compare

Added

  • (config) add dir and env fields for daemons (#227)

Fixed

  • (status) return error when daemon not found and improve test diagnostics (#224)

v1.3.0: Pitchfork v1.3.0 Release Notes

01 Feb 21:45
@jdx jdx
Immutable release. Only release title and notes can be modified.
2469cc9

Choose a tag to compare

Local Config Overrides, Smarter Logs, and Stop Everything

This release focuses on developer workflow improvements. You can now keep machine-specific configuration separate from shared project config with pitchfork.local.toml, filter logs by time with --since, and stop all running daemons in one command. We've also added a new ready_cmd option for more flexible readiness checks.

Highlights

Local Configuration Files (#198)

You can now create pitchfork.local.toml files alongside your pitchfork.toml to store machine-specific overrides. This is perfect for developer-specific ports, paths, or environment variables that shouldn't be committed to version control.

# pitchfork.local.toml (add to .gitignore)
[daemons.api]
run = "exec npm start -- --port 3001"

See the configuration docs for details.

Stop All Daemons (#195)

Shut down everything at once with pitchfork stop --all. Daemons are stopped in reverse dependency order, so dependents stop before the services they rely on.

pitchfork stop --all

Custom Readiness Commands (#187)

The new ready_cmd option lets you specify a shell command to determine when a daemon is ready. The daemon is marked ready when the command exits successfully—useful for databases, health endpoints, or any service that needs custom readiness logic.

[daemons.postgres]
run = "exec postgres -D /var/lib/postgres/data"
ready_cmd = "pg_isready -h localhost"

See readiness checks for all available options.

Time-Based Log Filtering (#204)

Filter logs with human-friendly time expressions using --since. Supports relative times, clock times, and full datetimes. Logs also now use a pager by default for easier reading.

pitchfork logs api --since 5min      # last 5 minutes
pitchfork logs api --since 1h        # last hour  
pitchfork logs api --since '10:30'   # since 10:30 AM today

Improvements

  • List command now shows available daemons (#206) - Daemons defined in config but not yet started now appear in pitchfork list, so you can see everything available without checking your config file.

  • Web UI improvements (#191) - The web interface got a visual refresh.

Bug Fixes

  • Fixed daemon stop logic to handle edge cases more reliably (#192)

Full Changelog · Documentation

v1.2.0: Beautiful Errors and a Visual Config Editor

20 Jan 03:04
@jdx jdx
Immutable release. Only release title and notes can be modified.
999bee6

Choose a tag to compare

Pitchfork v1.2.0 brings a major quality-of-life upgrade: a built-in config editor in the TUI and completely overhauled error messages. No more guessing what went wrong—errors now show exactly where problems occur with source code highlighting, helpful suggestions, and links to documentation.

The new TUI config editor lets you create, edit, and delete daemons without leaving the terminal or hand-editing TOML files. Combined with the improved error diagnostics, configuring pitchfork is now significantly more approachable for new users.

Highlights

TUI Config Editor (#171)

Create and manage daemon configurations directly from the TUI:

  • Press n to create a new daemon
  • Press E to edit an existing daemon
  • Press D to delete a daemon
  • Full form-based editor with validation for all daemon options

See the TUI guide for complete keybinding reference.

Rich Error Diagnostics (#180, #181, #182, #183)

Errors now include context that actually helps you fix problems:

  × failed to parse configuration
   ╭─[pitchfork.toml:5:1]
 4 │ [daemons.api]
 5 │ run =
   ·       ╰── expected string
   ╰────
  help: check TOML syntax at https://toml.io
  • Config errors show the exact file and line where parsing failed
  • IPC errors suggest fixes like "ensure the supervisor is running with: pitchfork supervisor start"
  • All errors include documentation links to pitchfork.jdx.dev

Internal Improvements

  • Modularized supervisor into focused submodules for better maintainability (#175)

Full Changelog: v1.1.0...v1.2.0

v1.1.0

19 Jan 18:17
@jdx jdx
Immutable release. Only release title and notes can be modified.
af178c5

Choose a tag to compare

Pitchfork v1.1.0 brings file watching for automatic daemon restarts—a much-requested feature for development workflows. When your source files change, pitchfork can now automatically restart the affected daemons, eliminating the need for manual restarts during development. This release also includes improved retry configuration, better cron scheduling accuracy, and makes the web UI opt-in to reduce resource usage.

Highlights

File Watching for Auto-Restart (#165)

Daemons can now automatically restart when specified files change. Use glob patterns to watch your source files:

[daemons.api]
run = "npm run dev"
watch = ["src/**/*.ts", "package.json"]

Changes are debounced (1 second) to avoid rapid restarts during batch saves. See the File Watching guide for details.

Boolean Retry Configuration (#170)

Retry configuration now accepts boolean values for common cases:

[daemons.api]
retry = true   # Retry forever on failure

[daemons.oneshot]
retry = false  # Never retry

Numeric values continue to work for specific retry counts. See the Auto-Restart guide for more information.

Web UI Now Opt-In (#172)

The web UI no longer runs by default, reducing resource usage for CLI and TUI users. Enable it when needed with --web-port or PITCHFORK_WEB_PORT:

pitchfork supervisor run --web-port 19876

Improvements

  • Auto-generated JSON schema (#167) - The JSON schema for pitchfork.toml is now auto-generated from Rust types, ensuring it always stays in sync with the actual configuration options.

  • macOS code signing (#173) - macOS binaries are now code-signed, reducing security warnings during installation.

Bug Fixes

  • Cron scheduling accuracy (#163) - Sub-minute cron schedules (e.g., */30 * * * * *) now work correctly. The cron watcher checks every 10 seconds instead of 60, and properly tracks the last trigger time to prevent missed or duplicate executions.

  • Log tailing reliability (#164) - Fixed race conditions and position tracking in pitchfork logs --tail that could cause gaps in log output.


Full Changelog: v1.0.0...v1.1.0

v1.0.1

19 Jan 04:29
@jdx jdx
Immutable release. Only release title and notes can be modified.
1d31246

Choose a tag to compare

Added

  • implement daemon dependency resolution (#135)
  • add restart command to CLI (#134)

Fixed

  • restart command preserves daemon dependency configuration (#142)
  • add missing depends field to restart command (#136)
  • set IPC socket permissions to 0600 for security (#133)
  • handle shell command parsing errors instead of silently failing (#132)

Other

  • bump version to 1.0.0 (#147)
  • release v0.3.1 (#121)
  • reduce unnecessary daemon cloning in loops (#144)
  • use periodic log flushing instead of per-line (#139)
  • refresh only tracked PIDs instead of all processes (#141)
  • cache compiled regex patterns (#143)

Security

  • add rate limiting to IPC server (#137)
  • canonicalize config paths to prevent symlink exploitation (#138)
  • add centralized daemon ID validation (#140)

v1.0.0

19 Jan 04:15
@jdx jdx
Immutable release. Only release title and notes can be modified.
4d4ab03

Choose a tag to compare

Added

  • implement daemon dependency resolution (#135)
  • add restart command to CLI (#134)

Fixed

  • restart command preserves daemon dependency configuration (#142)
  • add missing depends field to restart command (#136)
  • set IPC socket permissions to 0600 for security (#133)
  • handle shell command parsing errors instead of silently failing (#132)

Other

  • reduce unnecessary daemon cloning in loops (#144)
  • use periodic log flushing instead of per-line (#139)
  • refresh only tracked PIDs instead of all processes (#141)
  • cache compiled regex patterns (#143)

Security

  • add rate limiting to IPC server (#137)
  • canonicalize config paths to prevent symlink exploitation (#138)
  • add centralized daemon ID validation (#140)