Settings Reference
This page documents all configurable settings for pitchfork. Settings can be configured via:
- Environment variables (highest priority)
- Project-level:
pitchfork.tomlorpitchfork.local.tomlin[settings]section - User-level:
~/.config/pitchfork/config.tomlin[settings]section - System-level:
/etc/pitchfork/config.tomlin[settings]section
Settings are merged in precedence order, with later sources overriding earlier ones.
Settings for supervisor-owned services, such as [settings.web] and [settings.proxy], are resolved when the supervisor process starts. After that, they do not hot-reload: changing any setting requires restarting the supervisor with pitchfork supervisor start --force for the change to take effect. This applies regardless of whether the setting is in a project-level or global config file.
Configuration in pitchfork.toml
Add a [settings] section to any pitchfork.toml file:
# Daemon definitions
[daemons.myapp]
run = "node server.js"
# Settings configuration
[settings.general]
autostop_delay = "5m"
log_level = "debug"
[settings.logs]
time_retention = "7d"
[settings.tui]
refresh_rate = "1s"
[settings.supervisor]
file_watch_debounce = "2s"Global Configuration
For user-wide settings, create ~/.config/pitchfork/config.toml:
# Global daemons (e.g., database services)
[daemons.postgres]
run = "postgres -D /usr/local/var/postgres"
# Global settings
[settings.general]
log_level = "info"
[settings.web]
auto_start = trueEnvironment Variables
Every setting has a corresponding environment variable that overrides all file configurations:
# Override via environment
export PITCHFORK_LOG=debug
export PITCHFORK_WEB_AUTO_START=true
export PITCHFORK_AUTOSTOP_DELAY=5mAll Settings
General Settings
general.autostop_delay
DurationDelay before auto-stopping daemons when leaving a directory
When using shell hooks with auto = ["stop"], this controls how long pitchfork waits
before stopping a daemon after you leave its directory.
This delay prevents unnecessary stop/start cycles when briefly switching directories.
Examples:
"0s"- Stop immediately (no delay)"30s"- Wait 30 seconds"1m"- Wait 1 minute (default)"5m"- Wait 5 minutes
Set to "0s" to disable the delay and stop daemons immediately.
general.interval
DurationSupervisor background task refresh interval
Controls how often the supervisor refreshes its internal state and checks for:
- Daemon health status changes
- Configuration file updates
- Process state synchronization
Lower values provide more responsive status updates but use more resources.
Recommended values:
"5s"- For development/testing"10s"- Default, balanced"30s"- For production with many daemons
general.log_level
StringConsole log level (trace, debug, info, warn, error)
Controls the verbosity of log output to the console.
Available levels:
"trace"- Most verbose, includes all internal details"debug"- Detailed information for debugging"info"- Normal operation messages (default)"warn"- Warnings and potential issues"error"- Only errors
general.log_file_level
StringFile log level (trace, debug, info, warn, error)
Controls the verbosity of log output written to log files.
Can be set independently from log_level to have more verbose file logs.
For example, set console to "info" but file to "debug" to keep
detailed logs for troubleshooting without cluttering the console.
general.mise
BooleanWrap daemon commands with mise x -- globally
When enabled, pitchfork wraps every daemon command with mise x -- so that
mise sets up the correct tool versions, PATH,
and environment variables before the daemon runs.
This is especially useful when pitchfork is started as a login item or boot
daemon, where the shell profile (.zshrc, .bashrc) is not sourced and
tools installed via Homebrew or mise are not on PATH.
Individual daemons can override this with mise = true or mise = false
in their configuration.
general.mise_bin
StringExplicit path to the mise binary
By default, pitchfork searches well-known locations for the mise binary:
~/.local/bin/mise~/.cargo/bin/mise/usr/local/bin/mise/opt/homebrew/bin/mise
Set this to an absolute path if mise is installed elsewhere.
general.startup_log_timestamps
BooleanShow timestamps in startup log output
When enabled, pitchfork prefixes each startup log line and result line
with a timestamp (e.g. 19:03:15), making it easier to see how long
each daemon took to start.
When disabled (default), a dim bullet (•) is used instead to keep
the output compact and aligned with the spinner / status icons.
Logs
logs.time_retention
DurationTime-based log retention duration (e.g. '7d', '30d')
Maximum age of log entries to keep in the SQLite log store.
When set, log entries older than this duration are automatically pruned.
Examples: "7d" for 7 days, "30d" for 30 days, "1h" for 1 hour.
When empty (default), no time-based pruning is performed. You can combine
this with line_retention to enforce both a time limit and a line count limit.
Logs are pruned automatically by the supervisor during its interval watcher cycle (no more than once per hour). No manual rotation command is needed.
logs.line_retention
NumberCount-based log retention (e.g. 10000)
Maximum number of log entries to keep per daemon in the SQLite log store.
When set, only the most recent N log entries are retained. Older entries are automatically pruned.
When set to 0 (default), no count-based pruning is performed. You can combine
this with time_retention to enforce both a time limit and a line count limit.
Logs are pruned automatically by the supervisor during its interval watcher cycle (no more than once per hour). No manual rotation command is needed.
IPC Settings
ipc.connect_attempts
NumberNumber of connection retry attempts
How many times to retry connecting to the supervisor before giving up.
Each attempt uses exponential backoff between connect_min_delay and connect_max_delay.
ipc.connect_min_delay
DurationMinimum delay between connection retries
The initial delay between connection retry attempts.
The actual delay increases exponentially up to connect_max_delay.
ipc.connect_max_delay
DurationMaximum delay between connection retries
The maximum delay between connection retry attempts. Exponential backoff will not exceed this value.
ipc.request_timeout
DurationDefault timeout for IPC requests
Maximum time to wait for a response from the supervisor for most operations.
Note: Daemon start operations may use a longer timeout calculated from
the daemon's ready_delay setting plus a buffer.
ipc.rate_limit
NumberMaximum IPC requests per second per connection
Rate limiting for IPC connections to prevent local DoS attacks. Uses a sliding window algorithm.
Most users won't need to change this. Increase if you have automated tools making many rapid requests to the supervisor.
ipc.rate_limit_window
DurationRate limit sliding window duration
The time window for rate limiting calculations.
rate_limit requests are allowed within each window.
Web UI Settings
web.auto_start
BooleanAutomatically start web UI when supervisor starts
When enabled, the web UI server will automatically start alongside the supervisor.
By default, this is disabled. You can also start the web UI manually with:
pitchfork supervisor start --web-port=3120
web.bind_address
StringWeb server bind address
IP address for the web UI to listen on.
Security Warning: The default 127.0.0.1 only allows local connections.
Setting this to 0.0.0.0 will expose the web UI to your network.
Examples:
"127.0.0.1"- Local only (default, recommended)"0.0.0.0"- All interfaces (use with caution)"192.168.1.100"- Specific interface
web.bind_port
NumberDefault web server port
The port number for the web UI. If this port is in use, pitchfork will
try subsequent ports up to port_attempts times.
web.port_attempts
NumberNumber of ports to try if default is in use
If the default port is occupied, pitchfork will try this many consecutive ports before giving up.
For example, with bind_port = 3120 and port_attempts = 10,
it will try ports 3120, 3121, 3122, ... up to 3129.
web.log_lines
NumberInitial number of log lines to display
How many lines of logs to show initially when viewing daemon logs in the web UI. More lines means slower initial load but more history visible.
web.base_path
StringURL path prefix for the web UI (e.g. "ps" serves at /ps/)
Serves the web UI under a sub-path prefix, useful when running behind a reverse proxy that routes a path prefix to pitchfork.
Examples:
""- Serve at root/(default)"ps"- Serve at/ps/"tools/pitchfork"- Serve at/tools/pitchfork/
Equivalent to the --web-path CLI flag. The CLI flag takes priority over this setting.
web.sse_poll_interval
DurationServer-Sent Events poll interval for log streaming
How often the web UI checks for new log lines when streaming logs. Lower values provide more real-time updates but use more resources.
Api
api.auto_start
BooleanAutomatically start the standalone API server
When true, pitchfork starts a standalone API server on api.bind_address + api.bind_port when the supervisor launches. The web UI does not need to be enabled for this; you can run the API alone and serve the Vue SPA from a separate static host (e.g. nginx, Vite dev server).
Default is false so the API is only available through the bundled web UI.
api.bind_address
StringIP address the API server binds to
Use "0.0.0.0" to make the API reachable from other devices on your network. Keep "127.0.0.1" (default) to restrict it to localhost.
api.bind_port
NumberPort the standalone API server listens on
Set to 0 (default) to disable the standalone API server. Set to any valid port number (e.g. 8081) to start the API on its own port.
api.port_attempts
NumberNumber of consecutive ports to try if api.bind_port is in use
api.token
StringAuthentication token for API access when bound to non-loopback addresses
When the API server or web UI is bound to a non-loopback address (e.g., "0.0.0.0"), this token is required on every API request via the X-Pitchfork-Token header.
If left empty and the bind address is non-loopback, a random 32-byte hex token is auto-generated on startup and printed to the supervisor log. This token is injected into the served index.html, so the bundled Vue SPA works without additional configuration.
For external API consumers (e.g., curl, mobile apps), set this to a fixed value or pass it via the PITCHFORK_API_TOKEN environment variable.
TUI Settings
tui.refresh_rate
DurationDaemon list refresh interval
How often the TUI refreshes the daemon list and status information.
Lower values provide more responsive updates but may increase CPU usage, especially with many daemons.
Recommended values:
"1s"- More responsive"2s"- Default, balanced"5s"- Lower resource usage
tui.tick_rate
DurationEvent loop tick rate
How often the TUI checks for keyboard input and other events. This affects input responsiveness.
Most users won't need to change this. Lower values make the UI more responsive but use more CPU.
tui.stat_history
NumberNumber of stat samples to keep for graphs
How many CPU/memory stat samples to keep for each daemon's graph. With the default refresh rate of 2s, 60 samples = ~2 minutes of history.
Increase for longer history in graphs, at the cost of more memory.
tui.message_duration
DurationStatus message display duration
How long status messages (like "Daemon started") remain visible in the TUI before automatically clearing.
Supervisor Settings
supervisor.ready_check_interval
DurationInterval between ready checks (HTTP, TCP, command)
How often to poll when checking if a daemon is ready using:
ready_http- HTTP health endpointready_port- TCP port listeningready_cmd- Shell command exit code
Lower values detect readiness faster but use more resources.
supervisor.file_watch_debounce
DurationFile watch debounce duration
When using watch patterns to auto-restart daemons on file changes,
this controls how long to wait after the last change before triggering
a restart.
This prevents rapid restart cycles when many files change at once (e.g., during a build or git checkout).
supervisor.log_flush_interval
DurationDaemon log buffer flush interval
How often daemon log output is flushed to disk. Lower values mean logs appear faster in the UI but may impact performance.
supervisor.stop_timeout
DurationMaximum time to wait for daemon to stop gracefully
When stopping a daemon, pitchfork sends SIGTERM and waits this long for the process to exit gracefully before sending SIGKILL.
Increase for daemons that need time to clean up (e.g., flush data).
supervisor.restart_delay
DurationDelay between stop and start during restart
Brief pause after stopping a daemon before starting it again. Helps ensure resources (like ports) are fully released.
supervisor.cron_check_interval
DurationInterval for checking cron schedules
How often to check if any cron-scheduled daemons should be triggered.
The default of 10 seconds supports sub-minute cron schedules. Increase for lower resource usage if you don't need fine-grained scheduling.
supervisor.watch_interval
DurationFile watcher config refresh interval
How often the supervisor refreshes file watch configuration when using watch patterns.
This controls how quickly newly started/stopped daemons with watch patterns are reflected in the active watcher set.
For polling watcher cadence, use supervisor.watch_poll_interval.
Lower values react faster to configuration/runtime changes but use more CPU.
The default "10s" is appropriate for most environments.
supervisor.watch_poll_interval
DurationPolling watcher filesystem scan interval
How often polling-based file watchers scan for changes.
This applies when daemon watch_mode is poll, or when watch_mode = "auto"
falls back to polling because native watchers are unavailable.
Lower values detect changes faster but use more CPU and I/O.
"100ms" is useful for highly interactive workflows;
"500ms" is a practical default for remote/networked filesystems.
supervisor.http_client_timeout
DurationTimeout for HTTP ready checks
Maximum time to wait for a response when checking ready_http endpoints.
Increase if your services take a while to respond during startup.
supervisor.port_bump_attempts
NumberMaximum port increment attempts when auto_bump_port is enabled
When auto_bump_port = true is set on a daemon, pitchfork will try incrementing
all of the daemon's ports by the same offset to find a free range. This setting
controls how many offsets are tried before giving up with an error.
For example, with port = [3000] and port_bump_attempts = 10, pitchfork will
try ports 3000, 3001, 3002, ... up to 3009 before reporting failure.
This is a global default; individual daemons can override it with
port_bump_attempts in their daemon configuration.
supervisor.container
BooleanEnable container/PID1 mode for running inside Docker containers
When enabled, pitchfork operates as a proper PID 1 process inside a container:
- Installs a SIGCHLD handler to reap all orphaned/zombie child processes
- Routes SIGTERM/SIGINT through the graceful shutdown sequence
This is essential when running pitchfork as the entrypoint of a Docker container, where PID 1 must reap zombie processes to prevent process table exhaustion.
Can also be enabled via the --container CLI flag on pitchfork supervisor run.
supervisor.cleanup_orphans
BooleanKill orphaned daemon processes when supervisor starts
When enabled, the supervisor scans the state file on startup for daemon
processes left behind by a previous supervisor instance that was killed
unexpectedly (for example, with kill -9). Any matching live processes are
terminated so the new supervisor starts with a clean slate.
This is recommended for local development where an unclean shutdown (IDE restart, system crash, etc.) would otherwise leave stale processes holding ports and consuming resources.
Disable this on long-lived servers where you want daemons to survive a supervisor restart without interruption.
supervisor.user
StringDefault user to run daemon processes as
Default Unix user for daemon processes spawned by the supervisor.
When set, all daemons run as this user unless an individual daemon sets
user = "...". The value may be a username (for example "postgres") or
a numeric UID (for example "501").
If unset and the supervisor is running as root via sudo, daemons default to
the sudo-calling user from SUDO_UID/SUDO_GID instead of running as root.
supervisor.cpu_violation_threshold
NumberConsecutive CPU-over-limit samples before killing a daemon
When a daemon has cpu_limit configured, the supervisor checks CPU usage at
each interval tick. To avoid killing daemons during transient spikes (e.g. JIT
warm-up, burst responses), the process is only killed after this many
consecutive samples exceed the limit. A single sample below the limit
resets the counter.
Examples:
1- Kill immediately on first over-limit sample (no grace period)3- Require 3 consecutive over-limit samples (default)5- More tolerant of short bursts
With the default interval of 10s, a threshold of 3 means a daemon must
exceed its CPU limit for ~30 seconds before being killed.
Proxy
proxy.enable
BooleanEnable the reverse proxy server for daemons
When enabled, pitchfork starts a reverse proxy that routes requests from
<slug>.<tld>:<port> to the daemon's actual listening port.
Only daemons with an explicit slug are routable through the proxy.
No slug = not proxied.
Example: myapp.localhost:7777 -> localhost:3000 (daemon with slug = "myapp")
proxy.tld
StringTop-level domain used for proxy URLs
The TLD appended to daemon hostnames in proxy URLs.
With the default localhost, daemon URLs look like:
myapp.localhost:7777 (for a daemon with slug = "myapp")
For custom TLDs (e.g. test), you need wildcard DNS resolution.
On macOS, you can use dnsmasq or add entries to /etc/resolver/.
proxy.host
StringBind address for the reverse proxy server
IP address the reverse proxy listens on.
Security Warning: The default 127.0.0.1 only allows local connections.
Setting this to 0.0.0.0 will expose the proxy on every network interface,
including externally routable ones -- anyone on the same LAN can then reach
your local daemons.
Examples:
"127.0.0.1"- Local only (default, recommended)"0.0.0.0"- All interfaces (use with caution)"::1"- IPv6 loopback
proxy.port
NumberPort the reverse proxy server listens on
The port pitchfork's reverse proxy binds to. Must be in the range 1-65535.
Default is 443 (standard HTTPS port) since the proxy defaults to HTTPS. Users can override this to any port (e.g. 7777) to avoid requiring elevated privileges.
Ports below 1024 require the supervisor to be started with elevated
privileges (e.g. sudo pitchfork supervisor start).
proxy.https
BooleanEnable HTTPS for the reverse proxy
When enabled (default), the proxy serves HTTPS instead of HTTP.
You must also configure proxy.tls_cert and proxy.tls_key, or pitchfork
will auto-generate a self-signed certificate stored in the state directory.
Set to false to use plain HTTP (e.g. for simple local development).
proxy.tls_cert
StringPath to TLS certificate file (PEM format) for HTTPS proxy
Path to a PEM-encoded TLS certificate file used when proxy.https = true.
If left empty and proxy.https = true, pitchfork will auto-generate a
self-signed certificate and store it in $PITCHFORK_STATE_DIR/proxy/cert.pem.
proxy.tls_key
StringPath to TLS private key file (PEM format) for HTTPS proxy
Path to a PEM-encoded private key file used when proxy.https = true.
If left empty and proxy.https = true, pitchfork will auto-generate a
self-signed key and store it in $PITCHFORK_STATE_DIR/proxy/key.pem.
proxy.auto_trust
BooleanAutomatically install the proxy TLS certificate into the system trust store
When enabled (default), pitchfork automatically installs the proxy's self-signed CA certificate into the system trust store during supervisor startup, so that browsers and tools trust HTTPS proxy URLs without certificate warnings.
On macOS, this triggers a system authorization dialog (Touch ID or password).
On Linux, this requires write access to the system CA directory (typically
needs sudo).
If auto-trust fails (e.g. due to permissions), it is silently skipped and a warning is logged. You can manually install the certificate with: pitchfork proxy trust
Set to false to disable auto-trust entirely.
proxy.auto_start
BooleanAutomatically start daemons when accessed via proxy URL
When enabled (default), visiting a proxy URL for a stopped daemon will automatically start that daemon. The browser receives a "Starting…" page that refreshes every 2 seconds until the daemon is ready, at which point the request is proxied normally.
Set to false to disable auto-start and return a plain 502 error for
stopped daemons (the previous behaviour).
proxy.auto_start_timeout
DurationMaximum time to wait for an auto-started daemon to become ready
When a daemon is auto-started via a proxy request, the proxy waits up to this duration for the entire auto-start operation to complete — including waiting for the daemon's readiness signal and detecting the bound port.
If the daemon does not become ready and bind a port within this timeout, the browser receives an error page indicating the startup timed out.
Examples:
"15s"- Shorter timeout for fast-starting services"30s"- Default, suitable for most daemons"60s"- For daemons with slow initialisation (e.g. large Java apps)
proxy.sync_hosts
BooleanAutomatically sync slug hostnames to /etc/hosts
When enabled (default), pitchfork automatically adds entries to /etc/hosts
for registered slugs (e.g. 127.0.0.1 myapp.localhost) so that browsers
can resolve them.
This is needed because Safari does not auto-resolve .localhost subdomains,
and custom TLDs (e.g. .test) always require DNS entries.
Entries are managed in a marked block in /etc/hosts and cleaned up when
the proxy shuts down. Writing to /etc/hosts may require sudo.
Set to false to disable automatic hosts file management. You will need to
configure DNS resolution yourself (e.g. dnsmasq, /etc/resolver/ on macOS).
proxy.wildcard
BooleanEnable wildcard subdomain matching for proxy routes
When enabled (default), requests for subdomains of a registered slug will fall back to the parent slug's daemon.
For example, with slug "myapp":
myapp.localhost→ exact match (always works)tenant.myapp.localhost→ wildcard fallback to "myapp"
This is useful for multi-tenant apps where each tenant gets a unique
subdomain (e.g. acme.myapp.localhost, globex.myapp.localhost) but
all share the same backend server.
Set to false to require exact hostname matches only.
proxy.worktree
BooleanEnable git worktree / jj workspace auto-discovery for slug routing
When enabled (default), pitchfork automatically detects git worktrees or jj workspaces for registered slugs and routes subdomain prefixes to the corresponding worktree / workspace.
For example, with slug "myapp" pointing to /home/user/myapp (main branch), a git worktree at /home/user/myapp-feature-a (branch feature-a) or a jj workspace at /home/user/myapp-feature-a is automatically discovered. Requests to feature-a.myapp.localhost are routed to the daemon running in that directory.
Each worktree / workspace gets its own namespace (the directory name), so multiple copies can run the same daemon name without conflict.
Branch / workspace names are sanitized for URL compatibility:
feature/my-endpoint becomes feature-my-endpoint, accessed as
feature-my-endpoint.myapp.localhost.
Set to false to disable worktree/workspace discovery. Only the main
project directory will be used for slug routing.
proxy.lan
BooleanEnable LAN mode for the reverse proxy
When enabled, the proxy switches to the .local TLD and publishes slug
hostnames via mDNS so that other devices on the same network can reach
your daemons (e.g. myapp.local from a phone or another computer).
LAN mode:
- Forces
proxy.tldtolocal(mDNS requirement) - Publishes each slug as an mDNS address record (
<slug>.local → <LAN-IP>) - Binds the proxy to
0.0.0.0instead of127.0.0.1(overridable viaproxy.host) - Auto-detects your LAN IP and re-publishes mDNS records if it changes
Other devices must trust the pitchfork CA certificate to use HTTPS.
Run pitchfork proxy trust on each device, or use proxy.https = false.
proxy.lan_ip
StringPin a specific LAN IP address instead of auto-detecting
When set, skips auto-detection and uses this IP for mDNS publishing.
Implies proxy.lan = true if a non-empty value is provided.
