Skip to content

v2.28.0: Argv-array run commands and cron timing in status

Choose a tag to compare

@jdx jdx released this 27 Sep 10:40
· 139 commits to main since this release
Immutable release. Only release title and notes can be modified.
9b4077a

Daemons can now set run to an argv array so they start without a shell, and pitchfork status shows when a cron daemon last ran and when it runs next. This release also fixes how config changes reach cron daemons that are already running, stops file watching from using 100% CPU on large trees, and fixes several Windows problems with quoting, mise = true, and non-UTF-8 log output.

Added

  • Argv-array run to start a daemon without a shell (#918) — @JamBalaya56562. run can now be an array: the program, then its arguments. Pitchfork starts the program directly, so quotes, spaces, $, % and & reach it unchanged, whatever shell is configured and on every platform. The tracked PID is the program itself, including on Windows, where the string form records cmd.exe.

    [daemons.api]
    run = ["node", "my server.js", "--title", "API \"v2\""]

    Each argument is rendered as a template separately, and a rendered value stays a single argument. With mise = true the program runs as mise x -- <program> <args...>. An empty array or one that starts with "exec" is rejected. Shell features such as &&, pipes and $VAR expansion still need the string form. On Windows, a program named without an extension is only found as an .exe. Batch scripts need their extension (for example ["npm.cmd", "run", "server"]) and still run through cmd.exe. pitchfork daemons --json reports run exactly as written in the config, as either a string or an array. The string form works the same as before.

  • Cron timing in pitchfork status (#902) — @jdx. For scheduled daemons, status now shows the cron expression, the last scheduled start and the next scheduled time, each with a relative time:

    Cron: 0 0 2 * * *
    Last run: 2026-09-21 02:00:03 (7h 41m ago)
    Next run: 2026-09-22 02:00:00 (in 16h 18m)
    

    Last run only counts scheduled starts that actually launched a process. Manual starts and skipped runs don't update it, and runs from before this upgrade aren't recovered. If a scheduled time has already passed, for example because the supervisor was stopped, Next run labels it overdue. The TUI detail pane shows the same timing. The CLI JSON and HTTP API entries now include cron_schedule, cron_last_run and cron_next_run (RFC 3339). CLI JSON leaves out fields that have no value, and the HTTP API returns them as null.

Fixed

  • Cron config changes now reach daemons that are already running (#928) — @JamBalaya56562. Before, a started daemon kept its old schedule until it was restarted. Now, if you change the expression or retrigger, remove the cron line, or delete the daemon, the change takes effect on the next schedule check. If a project's config fails to parse, pitchfork leaves its schedules as they are. Deleting a project's last daemon or its whole config file isn't detected; use pitchfork disable in that case.
  • Templates and top-level [env] now apply to boot-started daemons and to cron daemons that were never started by hand (#923) — @JamBalaya56562. Before, {{ ... }} reached these daemons unrendered and the top-level [env] was not applied. boot_start daemons now also start in depends order, so a template can use the port of a boot daemon it depends on.
  • File watching no longer spins the supervisor on large trees (#921) — @jdx. A pattern for a single file, like watch = ["SUMMARY.md"], used to watch the whole project recursively. On Linux this could keep the supervisor at 100% CPU, and on macOS it could cause Too many open files. Patterns now watch only the directories they can match. Only a ** component still watches recursively, starting at the directory before it (for example src/**/*.rs watches the src tree). Also in this change:
    • Recursive watches no longer re-scan the tree in a loop when events are dropped.
    • Removing watch from the config now takes effect.
    • Directories created or moved into a watched location trigger restarts for the matching files inside them.
    • A directory that fails to register, for example after hitting fs.inotify.max_user_watches, is retried with backoff (starting at 10s, up to 5 minutes) instead of being silently dropped.
  • pty = true daemons keep logging after non-UTF-8 output (#929) — @JamBalaya56562. A line that wasn't valid UTF-8 used to stop the log reader. On Linux the daemon could then stall writing to its PTY, and on Windows it could fail. Every line is now logged.
  • Windows: non-UTF-8 daemon output is decoded with the console code page (#916) — @JamBalaya56562. Messages from console programs, such as a CP932 error from cmd on a Japanese system, now show up correctly in pitchfork logs instead of as replacement characters.
  • Windows: double quotes in run scripts now survive cmd.exe (#920) — @JamBalaya56562. A quoted program path such as '"C:\Program Files\app\app.exe" --name "a b"' now starts correctly instead of arriving with \" escapes. The same fix covers ready_cmd, health_cmd, lifecycle hooks and the log archive hook. Daemons with mise = true don't get this fix yet. A run string that only worked because of the old \" escaping may now behave differently.
  • Windows: mise = true now finds mise.exe on PATH (#922) — @JamBalaya56562. Before, mise = true was silently ignored unless general.mise_bin was set. An explicit general.mise_bin still takes priority.

Changed

  • Faster startup on Linux (#932) — @jdx. The Linux GNU release binaries (x86_64, aarch64) are now linked as non-PIE, which saves about 0.6 ms on every command, including the shell-activation cd hook. The tradeoff: ASLR no longer covers pitchfork's own code and data, though the heap, stack and shared libraries are still randomized. musl, macOS, Windows and cargo install builds are unchanged.

Full Changelog: v2.27.0...v2.28.0

💚 Sponsor pitchfork

pitchfork is built and maintained by @jdx, an open source developer at entire.io, the title sponsor of his open source work.

If pitchfork has a place in your development workflow, please consider becoming an individual or company sponsor. Your support funds ongoing development and helps keep pitchfork fast, free, and independent.