Skip to content

File Watching

Automatically restart daemons when source files change. This is useful for development workflows where you want hot-reloading behavior.

Basic Configuration

Add the watch field to your daemon configuration with glob patterns:

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

When any .ts file in src/ or package.json changes, the daemon will automatically restart.

You can also select the watcher backend per daemon:

toml
[daemons.api]
run = "npm run dev"
watch = ["src/**/*.ts", "package.json"]
watch_mode = "auto" # native | poll | auto
  • native (default): use OS-native notifications (inotify/FSEvents/etc.)
  • poll: use polling file scans (works better on some NFS/remote mounts)
  • auto: prefer native, automatically fall back to polling when native watch setup fails

How It Works

  1. On supervisor start: Pitchfork scans all daemons for watch patterns
  2. Directory watching: Patterns are expanded and their parent directories are watched recursively
  3. File change detection: The notify crate detects file changes with debouncing (1 second)
  4. Pattern matching: Changed files are matched against glob patterns
  5. Auto-restart: Running daemons with matching patterns are automatically restarted

When watch_mode = "poll" (or "auto" falls back), polling interval is controlled by settings.supervisor.watch_poll_interval.

TIP

Only running daemons are restarted. If a daemon is stopped, file changes won't start it.

Glob Pattern Syntax

Patterns use standard glob syntax:

PatternMatches
*.jsAll .js files in the daemon's directory
src/**/*.tsAll .ts files in src/ and subdirectories
package.jsonSpecific file
lib/**/*.pyAll .py files in lib/ and subdirectories
config/*.tomlAll .toml files in config/ directory

Patterns are resolved relative to the pitchfork.toml file that defines the daemon.

Examples

Node.js Development Server

toml
[daemons.api]
run = "npm run dev"
watch = ["src/**/*.ts", "src/**/*.tsx", "package.json", "tsconfig.json"]
ready_http = "http://localhost:3000/health"

Python Flask App

toml
[daemons.flask]
run = "flask run --reload"
watch = ["app/**/*.py", "templates/**/*.html", "requirements.txt"]
ready_port = 5000

Go Service

toml
[daemons.server]
run = "go run ./cmd/server"
watch = ["**/*.go", "go.mod", "go.sum"]
ready_port = 8080

Multi-Service Setup

toml
[daemons.postgres]
run = "postgres -D /var/lib/pgsql/data"
ready_port = 5432
# No watch - database doesn't need hot reload

[daemons.api]
run = "npm run dev"
depends = ["postgres"]
watch = ["src/**/*.ts", "package.json"]
ready_http = "http://localhost:3000/health"

[daemons.worker]
run = "npm run worker"
depends = ["postgres"]
watch = ["src/worker/**/*.ts", "package.json"]

Combining with Other Features

With Ready Checks

File watching works well with ready checks to ensure the daemon is fully restarted:

toml
[daemons.api]
run = "npm run dev"
watch = ["src/**/*.ts"]
ready_http = "http://localhost:3000/health"  # Wait for health endpoint

With Auto Start/Stop

Combine with shell hook for full development workflow automation:

toml
[daemons.api]
run = "npm run dev"
watch = ["src/**/*.ts"]
auto = ["start", "stop"]  # Auto-start when entering directory

With Retry

If your daemon might fail during restart, add retry:

toml
[daemons.api]
run = "npm run dev"
watch = ["src/**/*.ts"]
retry = 3  # Retry up to 3 times if restart fails

Performance Considerations

  • Debouncing: Changes are debounced for 1 second to avoid rapid restarts during batch saves
  • Directory watching: Only unique parent directories are watched, not individual files
  • Recursive watching: Subdirectories are watched automatically for ** patterns
  • Running daemons only: Stopped daemons ignore file changes

Polling Tuning

Use settings to tune watcher behavior globally:

toml
[settings.supervisor]
watch_poll_interval = "500ms"
watch_interval = "10s"
  • watch_poll_interval: polling scan cadence for watch_mode = "poll" (and auto fallback)
  • watch_interval: supervisor refresh cadence for watch config updates (new/removed watched daemons)

For remote development or network filesystems, values like watch_poll_interval = "100ms" to "1s" are common depending on CPU/IO budget.

Troubleshooting

Files not triggering restart

  1. Check the pattern matches your files (patterns are case-sensitive)
  2. Ensure the daemon is running (pitchfork list)
  3. Check supervisor logs for watch registration messages

Too many restarts

  1. Add more specific patterns to avoid matching build artifacts
  2. Exclude directories like node_modules, target, .git:
    toml
    watch = ["src/**/*.ts"]  # Only watch src/, not node_modules

Restart delay

File changes are debounced for 1 second. If you're making rapid edits, only the final state triggers a restart.

Released under the MIT License.

MIT LicenseCopyright © 2026en.dev