Repository navigation
pi-dispatch 5.0 FOOM
pi-dispatch-5.0-readme.mp4
One minute, with sound. The screens show sample data.
Working with a coding agent usually means sitting next to it. You type, it works, you check, you type again. That is the right way to start, but one person can only watch so much.
I want pi-dispatch to help people get up from that chair at their own pace, one kind of work at a time, from in the loop to near the loop to out of the loop. Where this is heading is what I call dark engineering. A dark factory runs with the lights off because nobody needs to stand on the floor, and I think software work can go the same way, with you looking after a swarm of agents rather than watching one.
I started where most people start, reading every step the agent took. The first thing I stopped watching was small, repetitive work, because I could check afterwards what each run had loaded and what it cost, and the result came back as a change I could read before it shipped.
5.0 makes that whole trip possible from one web page, which 4.x did not have. Early on you watch a job live, and with steering on for its trigger you can send it a message while it works. Once a kind of work is going well, it runs by itself and stops to ask when it needs you. The question waits for two weeks by default, and you can answer one on an issue from the page, on your phone too. After that, jobs start from a schedule or an issue, a second agent can review what came back, and you look at the result. The Zero touch page shows how often each project's runs needed a person, so you step back when the number says you can, and nothing moves a project for you.
The overview page, with sample data: what needs you, what is waiting and why, what is running, and what it has cost today.
The spending limits hold with nobody watching, and every job stays in its own sealed box. On a GitHub or GitLab project the work stops today at a proposed change. pi-dispatch never merges it, but a job's token could, so require a person's review in your branch protection and what ships stays your decision.
It is free and open source, and it runs on your own computer or server. Install it here.
What else is new
The web console is the biggest change, and every page of it fits a phone. A run's page now says what that run actually loaded, so a flow that was never found or an extension that failed no longer hides behind a clean exit. A trigger's page says what its jobs get on each of your machines, and you can change it right there with a preview in words and one Confirm, down to leaving one extension or one tool out of that trigger's jobs.
Runs got sturdier too. With run.recover, a crashed run can continue from its checkpoint instead of starting over. On an issue whose trigger keeps its session, you can fork a run from an earlier point, on another model if you like, and an agent can stop to ask permission for a named action and wait for a person.
For running many at once, a job can name what it needs (a planner, an editor) and you choose the model per project, with fallbacks for when one is rate limited. Watch rules turn findings in your logs and alerts into a read-only investigation or an issue. The Updates page shows what has a newer version: a new pi arrives through a release, and a person can try a new extension version on one job and then adopt it. Sandboxes open from the console, and there is an optional gateway for reaching their terminal in a browser. OpenShell joins Docker and Podman as a place to run jobs, and jobs now run on pi 1.5.0, with Radius supported under a cost cap.
Upgrading from 4.x: read this first
Follow the upgrade guide. In short: pause, wait for running jobs, then move the job image, every worker, the receivers, the console and every /dispatch, and resume. Install one exact version everywhere.
Why this is a major version
/dispatch insightsno longer writesinsights.html, so its--no-openand--full-pathsand the settingPI_GRAPH_DIRare gone. A leftoverPI_GRAPH_DIRis silently ignored. The command now prints the console's address.PI_MODEL,PI_PROVIDERand the overlay's model and provider are shape-checked. A value that used to be accepted now refuses at boot or refuses jobs.- Every job publishes a redacted live transcript to Valkey for up to 24 hours (
PI_LIVE_TRANSCRIPTS=0turns it off), and run progress keys (PI_RUN_PROGRESS). - The console binds a port, and with
run.recovera retry can continue a run. PI_REPORT_PROGRESS,PI_RECOVERINGandPI_STEERare reserved, so a trigger's env that used them is refused.- The receiver needs the new worker, and a console answer needs a worker of the same release.
Before you upgrade
- A top-level
versionkey that earlier releases ignored, insettings.json, the pause windows file or the triggers file, is now read. A hand-added one that is not an integer of 1 or more stops the worker or refuses jobs. Above 1 insettings.jsonholds every job asnewer-release, and above 1 in the pause windows file or above 2 in the triggers file stops the worker at its next start. Remove a hand-addedversion. - Cron ids over 176 characters are refused. Shorten them first.
- An Updates canary queued from the console runs as the trigger's ordinary paid job on a 4.x worker. Upgrade every worker before using the Updates page.
run.excludeExtensionsandrun.excludeExtensionToolsneed every worker, receiver and console on 5.0.0. A 4.x worker drops both and runs the job wider than the file says, on a clean record. A 4.x panel,/dispatchor one-shot disarm strips the file's stamp, and a 5.0.0 receiver or worker then refuses that file until a write from the 5.0.0 console or/dispatchputs the stamp back. The console refuses the change while a live worker cannot read them. A hand edit is not stopped, though doctor warns.- An
up-made Valkey container keeps:8until it is recreated. Doctor'sstate.oldernames it, with the fix. A Podman unit moves withservice install --force.
What changes for jobs you already run
- A chained child inherits
packages. A follow-up job of a"packages": falsetrigger now loses the staged packages it used to load. - Jobs move from pi 1.2.0 to 1.5.0. pi 1.5.0 converts tool arguments: every tool the runner defines refuses a wrong type first, and MCP tools receive the converted value.
- OpenRouter costs are billed totals, so a job on a BYOK key counts upstream inference against its cap.
- 129 catalog models are gone since 4.3.1 (123 chat, 2 image, 4 classifier) and 192 are new. Check triggers and agents naming a removed model, among them Radius
gpt-5.5,gpt-5.4,gpt-5.4-miniorgpt-5.3-codex, or OpenRouteropenai/o1,openai/o3-mini,openai/o4-mini,openai/gpt-3.5-turbooropenai/gpt-4-turbo. A trigger whosewatch.decidenames a removed model refuses the triggers file. - 4.3.1's GitLab and Forgejo docs said those forges send a delivery answered 503 again. GitHub, GitLab and Forgejo never do that on their own, and the docs now say where to send one again. The receiver answers 503 when it did before. Past one replica, its
enqueue_failedline carriesqueuedandreplicas. - A forge without an action list gets a refusal that names the trigger and the forge, where it would have thrown a
TypeError. No configuration reaches this today. - Capacity insights no longer count an older job's slot time as a new job's under a reused job id.
pi-dispatch service restart --drainnow also pauses, waits for and resumes the host's own queue whenPI_WORKER_NAMEis set. A queue paused before the drain stays paused. It refuses before pausing anything when this shell and the deployment.envdisagree onPI_WORKER_NAME.
Rolling back to 4.3.1
- Take
run.excludeExtensionsandrun.excludeExtensionToolsoff every trigger first. 4.x runs those triggers' jobs with what the keys took away. - 4.3.1 drops unknown settings keys (
secretBundlesincluded) when its/dispatchpanel writessettings.json. It also writes the triggers file astriggersalone. - Run record
.tmpcrash leftovers stay in the logs folder. Delete them by hand. - A rollback ends with
pi-dispatch resume, since the pause lives in Valkey. - 4.3.1 never touches
console-audit/: it has no web console, and its sweep reads only the top of the logs folder.
By package
@edgehero/pi-dispatch: many new subpaths, among them./job-data-version,./retention,./bullmq-internalsand./model-attempts. A new dependency,@earendil-works/pi-tui, pinned exactly. New commandschatandsteer. New trigger fieldsrun.progress,run.statusComment,run.recoverandrun.steer, among others. New settings:PI_LIVE_TRANSCRIPTS,PI_RUN_PROGRESS,PI_CHECKPOINTS_DIR(checkpoints hold transcripts and trees for up to 7 days),PI_CONSOLE_AUDIT_RETENTION_DAYS(defaults toPI_LOG_RETENTION_DAYS, and 0 keeps it forever),PI_RUN_MIRROR_MAX_RUNS(5,000 by default, 1,000 to 20,000, and in a fleet the lowest wins), and the shell-onlyPI_CONSOLE_TOKENandPI_CONSOLE_URL. New defer reasonnewer-release. New doctor idssettings.unknown-keys,fleet.store-versions,fleet.versions,dollars.window-reset(it counts only records from this release on) andstate.older. Run records gainv,dollars.reservedIn,jobCreatedAtandloaded. Valkey is pinned tovalkey/valkey:8.1.@edgehero/pi-dispatch-receiver: the worker range is^5.0.0. An older receiver drops the new run fields and thesecretBundleskey, and the new worker refuses those jobs astrigger-skew.@edgehero/pi-dispatch-admin: thepi-dispatch-consolecommand and itsPI_CONSOLE_*settings,/dispatch console,/dispatch chat, the PARKED view,tandT, andpi-dispatch service install --console. On stored state from a newer release: an audit row or a token role this console does not know is kept and marked, or signs in nowhere; a newer run record shows by its core facts; a job with adataVersionit cannot read cannot be re-run or answered here; a retained workspace with a newer manifest readsmanifest-newerand is not reopenable. It also names a scheduler whose id is 177 to 200 characters long, so you can remove it.@edgehero/pi-dispatch-sandbox-gateway: its first release. WithPI_LOGS_DIRunset, it writes under~/.pi-dispatch/logs, so run it as the worker's account.- The job image,
ghcr.io/edgehero/pi-job:5.0.0: new capabilities, among themreportProgress,recover,steer,sandboxLayout,observableRunnerandloadExclusions, and the labeldev.pi-dispatch.net-binaries. An older image is refused before it spends (job-image-*-unsupported) where a job needs one of them. A job withrun.excludeToolsin a scope with a role map needs this image even if it never starts a child. If you build your own image from ours, rebuild it from this release.@earendil-works/pi-agent-coreis pinned exactly.:latestcarries this runner. - OpenShell:
PI_OPENSHELL_ENGINEandPI_OPENSHELL_GATEWAY, and the console and panel show its runs. The venue is refused unless the host'sptrace_scopeis exactly 1, and an older image is refused before it spends.
Security
GHSA-4qvc-f352-mm29, a console issue fixed in #729. 5.0.0 is its patched version, and no earlier release contains the console.
Full changelog: v4.3.1...v5.0.0
Upgrading: https://github.com/edgehero/pi-dispatch/blob/v5.0.0/docs/upgrading.md