pitchfork

repository·main·Indexed 19 days ago

https://github.com/jdx/pitchfork

A CLI tool for managing development daemons with a focus on developer experience. It provides features such as auto start/stop via shell hooks (supporting Bash, Zsh, and Fish), dependency management, ready checks, and cron scheduling. Daemons are configured via pitchfork.toml and can be managed using commands for starting, running one-off processes, and configuring system boot startup via launchd on macOS or systemd on Linux.

Tokens
83.7K
Snippets
321
Records
414
Agent score
66%

What's inside pitchfork

  1. Overview of Pitchfork features

    main

    Pitchfork is a process manager for developers designed to manage 'daemons' (background processes). Key capabilities include:

    • Idempotent Starts: Starts daemons only if they are not already running.
    • Automatic Restarts: Configurable retry limits and exponential backoff on failure.
    • Smart Ready Checks: Verifies daemon readiness via delays, output patterns, HTTP endpoints, TCP ports, or custom commands.
    • Shell Integration: Auto-start/stop daemons when entering or leaving project directories.
    • Dependency Management: Topological start ordering based on declared dependencies.
    • File Watching: Auto-restarts on file changes using glob patterns with debouncing.
    • Scheduling: Cron-style scheduling with configurable retrigger modes (finish, always, success, fail).
    • Observability: Terminal TUI (with Vim keybindings) or a web dashboard for monitoring.
    • AI Integration: Built-in MCP server for managing daemons via AI assistants like Claude or Cursor.
    • Resource Management: Enforces memory and CPU limits per daemon.
    • Container Support: Designed to run as PID 1 in Docker with zombie reaping and signal forwarding.
    • Lifecycle Hooks: Execute commands on ready, fail, retry, stop, and exit events.
  2. Use the Pitchfork TUI Log Viewer

    main

    The Log Viewer provides real-time access to daemon logs. Features include:

    • Streaming: Real-time log streaming with a 'follow mode' (auto-scroll).
    • Navigation: Search within logs and jump to the top (g) or bottom (G) of the buffer.
    • View Modes: Toggle an expanded full-screen view for better readability.
  3. Understand the Pitchfork configuration hierarchy

    main

    Pitchfork loads configuration files in a specific order where later files override earlier ones. This allows for global defaults that can be overridden by user-specific or project-specific settings.

    Loading Order

    1. System-level: /etc/pitchfork/config.toml (namespace: global)
    2. User-level: ~/.config/pitchfork/config.toml (namespace: global)
    3. Project-level: Files are searched from the filesystem root down to the current directory in this order:
      • .config/pitchfork.toml (lowest precedence in directory)
      • .config/pitchfork.local.toml (overrides .config/pitchfork.toml)
      • pitchfork.toml (overrides everything in .config/)
      • pitchfork.local.toml (highest precedence in directory; typically not committed to version control)

    This hierarchy mirrors mise behavior.

  4. How pitchfork's architecture works

    main

    Pitchfork operates using a client-server model consisting of a CLI and a background Supervisor.

    • CLI: The user interface. It parses pitchfork.toml configurations and sends commands to the Supervisor via a Unix socket located at ~/.local/state/pitchfork/sock/main.sock using MessagePack IPC.
    • Supervisor: A background daemon that manages the lifecycle of all processes. It handles process spawning, monitoring output, and managing retries.
    • Watchers: The Supervisor uses background watchers to maintain system state:
      • Interval Watcher: Runs every 10 seconds to refresh the process list, handle autostop (when leaving a directory), retry failed daemons, and check resource limits.
      • Cron Watcher: Runs every 10 seconds to trigger daemons with cron schedules.
      • File Watcher: Monitors directories matching daemon watch glob patterns. It debounces changes (default 1s) and only restarts daemons that are currently in a Running state.
  5. Understand daemon shutdown behavior

    main

    Pitchfork uses a graceful shutdown strategy when running pitchfork stop:

    1. SIGTERM: It sends a SIGTERM and waits up to the stop_timeout (default 5 seconds) for the process to exit.
    2. SIGKILL: If the process does not exit within the timeout, it sends a SIGKILL to force termination.

    If your daemon takes longer than 3 seconds to stop, it may be ignoring SIGTERM or performing slow cleanup.

    Testing signal handling: You can test if your daemon responds to SIGTERM by manually sending the signal to its PID:

    kill -TERM $(pitchfork status myapp --json | jq .pid)

    Debugging shutdown timing: Start the supervisor with debug logs, stop your app, and grep the supervisor logs for termination signals:

    PITCHFORK_LOG=debug pitchfork supervisor start --force
    pitchfork stop myapp
    pitchfork logs pitchfork | grep -i "sigterm\|sigkill\|terminated"
  6. Understand Auto-Start and Auto-Stop behaviors

    main

    The auto option in pitchfork.toml accepts an array of strings to define daemon lifecycle rules:

    • ["start"]: The daemon starts automatically when you cd into the project directory.
    • ["stop"]: The daemon stops automatically when you cd out of the project directory.
    • ["start", "stop"]: The daemon both starts on entry and stops on exit.

    Lifecycle Logic:

    1. Entering a directory with auto = ["start", ...] triggers daemon startup.
    2. Leaving a directory with auto = [..., "stop"] marks the daemon for stopping.
    3. Pitchfork implements a delay before stopping to handle quick directory switches.
    4. Daemons only stop if no other active terminal sessions remain in that directory.
  7. Use the Pitchfork TUI Dashboard

    main

    The Dashboard view provides a live overview of your daemons. Key capabilities include:

    • Monitoring: View live daemon status (color-coded), CPU usage, and memory usage per daemon.
    • Filtering: Use fuzzy search to filter the list of daemons.
    • Sorting: Use sortable columns to organize the view.
    • Batch Operations: Use Space to select multiple daemons, then perform actions like starting, stopping, or restarting them all at once.
  8. Use the Pitchfork TUI Config Editor

    main

    The Config Editor allows you to manage daemon definitions through a form-based interface. You can:

    • Create new daemons.
    • Edit existing daemon configurations.
    • Delete daemons from configuration files.
    • Benefit from built-in validation for required fields and formats.
  9. Authenticate with the Pitchfork API

    main

    Authentication requirements depend on the bind_address used:

    • Loopback only (127.0.0.1, ::1): No authentication is required.
    • Non-loopback (e.g., 0.0.0.0, LAN IP): A 64-character hex token is auto-generated at startup and printed to stderr. You must include this token in the X-Pitchfork-Token header for all requests.

    You can also define a fixed token in your configuration under [settings.api].token to avoid using the auto-generated one.

    # Example using a token for a non-loopback address
    curl -H "X-Pitchfork-Token: <token>" http://192.168.1.100:3120/api/daemons
  10. Understand template resolution order and limitations

    main

    Templates are rendered level-by-level following the dependency graph:

    1. Level 0: Daemons with no dependencies (start first).
    2. Level 1: Daemons depending on Level 0 (can reference Level 0).
    3. Level 2: Daemons depending on Level 1 (can reference Level 0 and 1).

    Important Rules:

    • Concurrency: Daemons within the same level start concurrently and cannot reference each other's ports via templates.
    • Self-Reference Limitation: A daemon's own port and ports are not available at template rendering time because ports are resolved after the command is constructed. To access the current daemon's own resolved ports, use the $PORT, $PORT0, $PORT1, etc., environment variables.
    • Dependency Requirement: Use {{ daemons.xxx.port }} to reference the ports of your dependencies.
  11. Configure Ready Checks for daemons

    main

    A 'Ready Check' allows Pitchfork to determine when a service is actually functional, rather than just when the process has started. You can use the ready_http key in your configuration to point to a health check endpoint. Pitchfork will wait for this endpoint to become available before considering the daemon 'ready'.

    [daemons.api]
    run = "npm run server"
    ready_http = "http://localhost:3000/health"
  12. How readiness detection works

    main

    Pitchfork uses several methods to determine if a daemon has successfully started and is ready to receive traffic. The first check to succeed marks the daemon as ready.

    • Delay: Waits for a fixed number of seconds. This is only used if no other check type is configured.
    • Output: Matches a regex against stdout or stderr.
    • HTTP: Checks if a specific endpoint returns a 2xx status code.
    • Port: Checks if a TCP port is listening.
    • Command: Executes a shell command; success is defined by an exit code of 0.