@edgehero/pi-dispatch-admin 4.3.1 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,34 +1,55 @@
1
1
  <p align="center">
2
- <img src="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/banner.png?v=2.0.0" alt="pi-dispatch: run the pi coding agent as a self-hosted service" width="880">
2
+ <picture>
3
+ <source media="(prefers-reduced-motion: reduce) and (prefers-color-scheme:light)" srcset="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/banner-light-still.png?v=2026-11-05">
4
+ <source media="(prefers-reduced-motion: reduce)" srcset="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/banner-still.png?v=2026-11-04b">
5
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/banner-light.png?v=2026-11-05">
6
+ <img src="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/banner.png?v=2026-11-04b" alt="An animation of the pi-dispatch banner: go from sitting next to one AI coding agent to running many in the background. In the loop, near the loop, out of the loop, dark engineering. On a lit floor you stand beside one agent. As the lights go off, more agents start, and you walk away to the one page that stays lit, whose counts follow the floor. Spending limits that hold, a sealed box for every job, and you decide what ships." width="880">
7
+ </picture>
3
8
  </p>
4
9
 
5
- # pi-dispatch: run the pi coding agent as a self-hosted service
10
+ # pi-dispatch: go from sitting next to one AI coding agent to running many in the background
6
11
 
7
- **Let a coding agent work on your repositories while you are not watching, without surprise bills and
8
- without giving it the keys to your machine.**
12
+ [pi](https://github.com/earendil-works/pi) is an open source coding agent that you normally run in a terminal. pi-dispatch runs it for you
13
+ in the background: on a schedule, on your repo's issues and pull requests, or from the command line. Each job happens in a sealed box that is
14
+ thrown away afterwards, stops at the spending limit you set, and shows up live on one web page. You start in the loop, watching it work. You
15
+ move to near the loop, where it asks when it needs you, and to out of the loop, where a second agent reviews the work and then you decide, until you are looking after a swarm of
16
+ agents rather than one: dark engineering. pi-dispatch never merges anything, so what ships stays a person's decision. It runs on a provider key or a subscription you already have, falls back to other models you
17
+ list, and brings your own pi setup and extensions along with `pi-dispatch import-pi`. The [main README](https://github.com/edgehero/pi-dispatch#readme)
18
+ explains all of it.
9
19
 
10
- [pi](https://github.com/earendil-works/pi) is an open source coding agent that you normally run in a
11
- terminal. It has no job queue, no spend limit and, by its own README, no permission system. pi-dispatch
12
- adds exactly those, so pi can run unattended: on a cron schedule, on your repo's issues and PRs, or from
13
- the command line. Every job runs in its own container. Spend is checked before a single token is spent:
14
- job counts and a daily token count for the whole deployment, job counts per repo, folder or project, and
15
- dollars per day, week or month for the deployment and per repo, folder, project or model, plus an optional
16
- dollar cap per job. Everything the agent did, and what it cost, is
17
- recorded, graphed and priced.
20
+ <p align="center">
21
+ <picture>
22
+ <source media="(prefers-reduced-motion: reduce) and (prefers-color-scheme:dark)" srcset="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/explain/how-close-you-stay-dark-still.png?v=2026-11-04">
23
+ <source media="(prefers-reduced-motion: reduce)" srcset="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/explain/how-close-you-stay-still.png?v=2026-11-04">
24
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/explain/how-close-you-stay-dark.png?v=2026-11-04">
25
+ <img src="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/explain/how-close-you-stay.png?v=2026-11-04" alt="An animation of one loop of work drawn three times, one above the other, under the headline: decide how closely you watch. In the loop, you are on the track: you watch it work and step in, and a message from you crosses to the agent. Near the loop, you stand just beside it: it works alone and stops to ask when it needs you, and it waits until you answer. Out of the loop, you are far away: it starts without you, a second agent reviews it, and only the change, reviewed by AI, travels to you, and then you decide. At every stage: a spending limit, a sealed box, and the final say stays yours." width="820">
26
+ </picture>
27
+ </p>
18
28
 
19
- On a forge you stay in control at both ends. A job starts only when someone with write access to the repo
20
- asks for one, with a label, an `@pi` comment or a review. What comes back is a pull request that you
21
- review and merge yourself, because pi-dispatch never merges anything. It is not another agent to compare
22
- with the one you use. It is the queue, the budget and the box around the pi you already run.
29
+ <p align="center">
30
+ <picture>
31
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/console/console-overview-dark.png?v=2026-11-03">
32
+ <img src="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/console/console-overview.png?v=2026-11-03" alt="The web console's overview page: what needs you, what is waiting and why, what is running, what today has cost, and a timeline of every project's runs" width="820">
33
+ </picture>
34
+ </p>
23
35
 
24
- > This npm package, **`@edgehero/pi-dispatch-admin`**, is the **operator console**, a pi extension. The
25
- > service itself is [`@edgehero/pi-dispatch`](https://www.npmjs.com/package/@edgehero/pi-dispatch)
26
- > (worker and CLI) and [`@edgehero/pi-dispatch-receiver`](https://www.npmjs.com/package/@edgehero/pi-dispatch-receiver)
27
- > (the webhook edge). The [main repo](https://github.com/edgehero/pi-dispatch) has the job image, the
28
- > docs (Docker, Podman, egress, every forge) and SECURITY.md.
36
+ > This npm package, **`@edgehero/pi-dispatch-admin`**, holds the two ways to work with a deployment: the **web console**
37
+ > (`pi-dispatch-console`, above) and the **`/dispatch` panel**, a pi extension. The service itself is
38
+ > [`@edgehero/pi-dispatch`](https://www.npmjs.com/package/@edgehero/pi-dispatch) (worker and CLI) and
39
+ > [`@edgehero/pi-dispatch-receiver`](https://www.npmjs.com/package/@edgehero/pi-dispatch-receiver) (the webhook edge). The
40
+ > [main repo](https://github.com/edgehero/pi-dispatch) has the job image, the docs (Docker, Podman, egress, every forge) and SECURITY.md.
29
41
 
30
42
  ## How it works
31
43
 
44
+ <p align="center">
45
+ <picture>
46
+ <source media="(prefers-reduced-motion: reduce) and (prefers-color-scheme:dark)" srcset="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/explain/one-job-dark-still.png?v=2026-11-04">
47
+ <source media="(prefers-reduced-motion: reduce)" srcset="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/explain/one-job-still.png?v=2026-11-04">
48
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/explain/one-job-dark.png?v=2026-11-04">
49
+ <img src="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/explain/one-job.png?v=2026-11-05" alt="An animation of one job in five steps, under the headline: you pay for AI only while the agent works. Something starts it: a schedule, an issue, or you. It waits in line, and nothing runs yet. It is checked: over a limit, it is refused. The agent works in a sealed box, and if it needs you it stops to ask. You decide on a proposed change: you accept it, not pi-dispatch. A strip under the steps shows no AI cost in the first three and the last, and AI cost only where the agent works. A job crosses the strip and it fills only there. A second job is refused at the check." width="820">
50
+ </picture>
51
+ </p>
52
+
32
53
  Every trigger produces the same job, through the same path: one queue, one container, one budget.
33
54
 
34
55
  ```
@@ -82,7 +103,7 @@ default and goes through an allowlist proxy, and the allowed hosts are yours to
82
103
  ## Triggers: what starts a job
83
104
 
84
105
  Every trigger is one `{ on, run }` entry in a single `triggers.json`. The worker reads it live for cron,
85
- the receiver reads it live for forge webhooks, and the console can edit it. **`on` is what fires it;
106
+ the receiver reads it live for forge webhooks, and the panel and the web console can edit it. **`on` is what fires it;
86
107
  `run` is the skill it runs.**
87
108
 
88
109
  | `on.type` | Fires on | What the agent gets as its task |
@@ -124,37 +145,56 @@ Four things to know before you build on it:
124
145
  persists. A forge job gets a fresh clone that is thrown away with the container
125
146
  ([`docs/workflows.md`](https://github.com/edgehero/pi-dispatch/blob/main/docs/workflows.md)).
126
147
 
127
- ## The console: `/dispatch`
148
+ ## The panel: `/dispatch`
128
149
 
129
150
  One command puts a live terminal view over the whole deployment:
130
151
 
131
152
  <p align="center">
132
- <img src="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/dispatch-dashboard.png?v=2026-10-14" alt="The /dispatch panel: status, spend meters, dollar windows, triggers with a portfolio trigger, pause windows, scoped limits with their dollar caps, held and failed jobs, runs with their projects and the u hosts key, and settings" width="820">
153
+ <picture>
154
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/dispatch-dashboard-light.png?v=2026-11-05">
155
+ <img src="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/dispatch-dashboard.png?v=2026-10-22-710" alt="The /dispatch panel: status, spend meters, dollar windows, triggers with a portfolio trigger, pause windows, scoped limits with their dollar caps, held and failed jobs, runs with their projects and the u hosts key, and settings" width="820">
156
+ </picture>
133
157
  </p>
134
158
 
135
159
  - **MCP servers, read-only.** A trigger that names MCP servers says so on its row (`[mcp ...]`), and its
136
160
  drill-in shows each one as the overlay offers it now: where it runs, how its tools are reached, and the
137
- variable names it is handed, or why every job of it would be refused. No tool and no key changes them.
161
+ variable names it is handed, or why every job of it would be refused. No `dispatch_*` tool and no panel key changes them: a person
162
+ switches a trigger's servers on its page in the web console, or in the file.
138
163
  - **Status and spend.** Queue and worker state, day, week and month spend meters, a daily token counter,
139
- and the run history with tokens and cost per job. `Enter` on a run opens its full record, `x` on a
140
- running job cancels it after asking, and `b` on an opened run reopens its workspace.
141
- - **Insights, the one analytics page.** Press `i` (or type `/dispatch insights`) and one self contained
142
- page opens in your browser. It shows the budget dials, plan verdicts against API rates, daily,
164
+ and the run history with tokens and cost per job. Each running job shows where it is: its turn, steps done and
165
+ failed, the tool running and for how long, and the phase it reported (or, when its worker has written nothing for
166
+ 3 minutes, that the worker may be gone). `Enter` on a run opens its full record, `x`
167
+ on a running job cancels it after asking, and `b` on an opened run reopens its workspace.
168
+ - **A run's chat.** `/dispatch chat <run-id | issue-or-PR-url | session-key>` opens the run the way it can be talked
169
+ to now: a running job opens on its live transcript, and `Esc` lands on its row, where `t` and `T` steer it; a
170
+ parked run shows its question and asks for your answer, then queues it after a confirm; a finished run opens in
171
+ your own pi as a fork, on this host, with its tools off. It is a command you type, never a model callable tool
172
+ ([`docs/chat.md`](https://github.com/edgehero/pi-dispatch/blob/main/docs/chat.md#in-pi-dispatch-chat)).
173
+ - **Insights, the one analytics page.** It is `/insights` in the web console (below); press `i` (or type
174
+ `/dispatch insights`) and the panel shows its address. It shows the budget dials, plan verdicts against API rates, daily,
143
175
  cumulative and per flow spend charts, five breakdowns (by flow, trigger, model, repo and project), the
144
176
  budget split with each project's share, spend and floor and the split's history, how busy each host was
145
- (jobs only), and the trigger and flow topology with spend on each trigger. A plan covered run never shows as $0.00, and an estimate is
177
+ (jobs only), and the trigger and flow topology with spend on each trigger, plus a what if form that re-prices a
178
+ flow on another model. A plan covered run never shows as $0.00, and an estimate is
146
179
  always marked as one ([`docs/insights.md`](https://github.com/edgehero/pi-dispatch/blob/main/docs/insights.md)).
147
180
 
148
181
  <p align="center">
149
- <img src="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/insights-view.png?v=2026-10-14" alt="The insights page: KPI tiles, budget dials, the budget split, a plan verdict, spend charts, the five breakdowns, how busy each host was, and the topology with spend badges" width="820">
182
+ <picture>
183
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/console/console-spend-dark.png?v=2026-11-05">
184
+ <img src="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/console/console-spend.png?v=2026-11-03" alt="The Spend page: KPI tiles, budget dials, the budget split, a plan verdict, spend charts, the five breakdowns, how busy each host was, and the topology with spend badges" width="820">
185
+ </picture>
150
186
  </p>
151
187
 
152
188
  - **Triggers, editable live.** Add, edit and delete triggers without a restart. Drill-ins show what
153
189
  fires each one, what it runs and who may fire it. A one-shot shows armed or spent. A spent entry
154
190
  stays in the list, matches nothing, and is re-armed when you delete its `on.disarmed` mark from the file.
155
- Triggers that run third party code or a custom image carry a badge. Turning either on or off stays an
156
- edit to the reviewed `triggers.json`, which neither the console nor a model callable tool makes for you.
157
- A portfolio manager's cron trigger carries `[portfolio]`: its jobs write the budget split.
191
+ Triggers that run third party code or a custom image carry a badge. No panel key and no model callable tool turns
192
+ either on or off. The staged packages are a person's switch on the trigger's page in the web console, or an edit to
193
+ the reviewed `triggers.json`, and a custom image stays an edit to that file.
194
+ A portfolio manager's cron trigger carries `[portfolio]`: its jobs write the budget split. The trigger tools can
195
+ turn on `progress` (the job gets a `report_progress` tool to name its phases) and `statusComment` (one forge comment
196
+ the worker edits as the run goes, numbers only), and `recover` (a run the worker loses continues from its last
197
+ checkpoint), behind your confirm.
158
198
  - **Quiet hours.** Pause windows per folder or repo, timezone aware. A paused job waits, never drops, and
159
199
  costs nothing.
160
200
  - **Scoped limits.** Job caps per repo, folder or project (day, week, month), refused before any spend, plus a
@@ -184,13 +224,16 @@ One command puts a live terminal view over the whole deployment:
184
224
  It counts jobs only: a machine busy with other work reads as idle.
185
225
 
186
226
  <p align="center">
187
- <img src="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/dispatch-hosts.png?v=2026-10-14" alt="The panel's hosts view: three machines, each with its slots in use, the memory and CPU its budget has promised, its running jobs with project, size and age, a stale host with an orphaned container, and the last 7 days as busy share, jobs at once, time full, the wait and the top projects" width="820">
227
+ <picture>
228
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/dispatch-hosts-light.png?v=2026-11-05">
229
+ <img src="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/dispatch-hosts.png?v=2026-10-26" alt="The panel's hosts view: three machines, each with its slots in use, the memory and CPU its budget has promised, its running jobs with project, size and age, a host with an orphaned container, and the last 7 days as busy share, jobs at once, time full, the wait and the top projects, then each host's last doctor run with its failing and warning checks" width="820">
230
+ </picture>
188
231
  </p>
189
232
 
190
233
  - **The budget split.** With an allocation envelope (a dollar total per window and a floor per project), `b`
191
234
  in the list shows each project's share and spend, the applied plan with the reasons it gave, and the history.
192
- `r` on a history row reverts to it after a yes or no. `dispatch_priorities_set` sets a plan of weights with
193
- no confirm, because it can only move money inside the envelope; `dispatch_envelope_set` changes the envelope
235
+ `r` on a history row reverts to it after a yes or no. `dispatch_priorities_set` sets a plan of weights inside the envelope,
236
+ confirmed in an interactive session or delegated headless with the explicit process grant; `dispatch_envelope_set` changes the envelope
194
237
  behind your confirm; `dispatch_allocations` reads the split. pi's own `write` and `edit` tools are blocked on
195
238
  the envelope, `projects.json`, `scoped-limits.json`, `triggers.json` and the settings file
196
239
  ([`docs/allocation.md`](https://github.com/edgehero/pi-dispatch/blob/main/docs/allocation.md)).
@@ -198,7 +241,10 @@ One command puts a live terminal view over the whole deployment:
198
241
  plan. A run's detail names the plan a portfolio run wrote and the dollars it settled.
199
242
 
200
243
  <p align="center">
201
- <img src="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/dispatch-allocation.png?v=2026-10-14" alt="The panel's budget split view: the weekly envelope, each project's floor, weight, share and spend, the headroom, the applied plan with its reasons, and the history across two hosts with a revert and a refused plan" width="820">
244
+ <picture>
245
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/dispatch-allocation-light.png?v=2026-11-05">
246
+ <img src="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/dispatch-allocation.png?v=2026-10-14" alt="The panel's budget split view: the weekly envelope, each project's floor, weight, share and spend, the headroom, the applied plan with its reasons, and the history across two hosts with a revert and a refused plan" width="820">
247
+ </picture>
202
248
  </p>
203
249
 
204
250
  - **The portfolio manager.** A weekly flow you own reads the budget and writes a plan of weights. The
@@ -209,22 +255,60 @@ One command puts a live terminal view over the whole deployment:
209
255
  anything waits (the target, the condition and how long), and a **failed** section for jobs the queue
210
256
  marked failed after their last attempt. `dispatch_waits` lists held jobs and `dispatch_wait_cancel` stops one behind your confirm
211
257
  ([`docs/wait-for.md`](https://github.com/edgehero/pi-dispatch/blob/main/docs/wait-for.md)).
212
- - **AI operable, with a human gate.** Model callable tools can change limits (global and scoped) and
213
- manage triggers and pause windows. Every **config** change asks the operator in a prompt the model
214
- cannot answer, and is refused when no operator is present. `dispatch_pause` and `dispatch_resume` skip
215
- that confirm on purpose: they are reversible and spend nothing.
216
- - **One tool is not money safe.** `dispatch_run` queues a **paid** run that edits a local folder in place
217
- with no undo, without a confirm. Six separate limits bound it instead: the `PI_DISPATCH_RUN_ROOTS` folder
218
- allowlist, a committed per flow `ai-trigger: allow` opt in (read at a commit fixed before the agent
219
- starts), a dirty tree refusal with no force option, no spend settings on the tool, a per hour rate limit
220
- and the worker's daily cap. It cannot run commands, and a chained job asking for a `command` is refused.
221
- Read [`SECURITY.md`](https://github.com/edgehero/pi-dispatch/blob/main/SECURITY.md) before you enable it.
222
- The bundled `operate-pi-dispatch` skill teaches the agent these gates.
258
+ - **AI operable, with explicit authority.** Every model write uses the same action policy as the browser.
259
+ Interactive sessions confirm every change, including pause, priorities and paid starts. Headless sessions
260
+ need `PI_DISPATCH_AGENT_WRITES=1` in the actual pi process before it starts, and can use only unattended
261
+ actions. That includes explicit cap decreases, adding ordinary restrictive limit rows and pauses,
262
+ turning existing run flags off, cancellation, failed-job removal and bounded priorities. Scope, size,
263
+ minimums, inherited limits and mixed widening requests stay confirmed. The deployment file and pointer
264
+ cannot grant this authority. Answers, draft decisions, standing-answer adoption and forge reruns remain person actions, and no
265
+ `dispatch_*` tool can set a trigger's job cap, allowed models, fallbacks, MCP servers, tool exclusions, staged packages, extension exclusions or extension tool exclusions, while `dispatch_trigger_edit` can still move its flow, provider and model behind a confirm. A pi process's own `bash`, `write` and
266
+ `edit` tools are outside this policy, so an unattended one must run with them disabled
267
+ ([`SECURITY.md`](https://github.com/edgehero/pi-dispatch/blob/main/SECURITY.md)). Tool writes are audited as agents; human-confirmed intervention is tracked separately.
268
+ - **Paid starts stay bounded.** `dispatch_run`, Fire now and local or cron reruns need explicit valid
269
+ `PI_DISPATCH_RUN_ROOTS` in the pi process environment. Fire now and reruns also require an explicit valid
270
+ `PI_DISPATCH_RUN_PER_HOUR`. `dispatch_run` keeps its default of three starts per hour when that value is
271
+ absent or invalid; a valid zero disables it. They check the
272
+ current committed flow's `ai-trigger: allow`, a clean tree and the shared hourly allowance again before
273
+ enqueue. They accept no spend settings, cannot run commands or portfolio flows, and still pass the
274
+ worker's budget gates. A paid run edits its folder in place. Read
275
+ [`SECURITY.md`](https://github.com/edgehero/pi-dispatch/blob/main/SECURITY.md) before enabling it.
276
+ The bundled `operate-pi-dispatch` skill explains each action mark and refusal.
277
+ - **Agent reads expose operational facts.** Failed jobs, all waiting jobs, hosts and setup have dedicated
278
+ read tools. Runs report local retention when known; hosts report budgets, holds, CPU reserve, orphans,
279
+ kept sandboxes, doctor counts and qualified venue declarations. Costs include running holds and bounded
280
+ what-if estimates. Model results omit private job/operator text, question and draft content, variable
281
+ names, host paths and what a run loaded. Setup suggestions come from the trusted command catalogue.
223
282
  - **Logs stay put.** Raw container output shows only in the panel's viewer, never in model context.
224
283
 
284
+ **A web console as well.** The same package installs `pi-dispatch-console`, a separate process that serves a live web
285
+ console for the deployment on loopback or on a private unix socket, behind a named token per person. It shows the
286
+ whole fleet as it changes: an overview of what needs you, what waits and why, and the last hours as a timeline (on a
287
+ deployment that has not run yet, what stands before its first job), every run with filters and what it loaded (a run that
288
+ finished without its flow or with a failed extension says so), one search by
289
+ repository, target or job id, the last 24 hours counted by outcome and paging, a card for each run waiting for an
290
+ answer, spend and insights by range, queues, hosts and schedules, the configuration, what a trigger's jobs get and what a project's runs load on each host, and its own audit
291
+ log, plus `/api/state` as JSON for scripts. It also has Models (roles, fallbacks and canary comparisons), Updates (what jobs run and what is
292
+ newer), Watch (findings from your alerts), Sandboxes (kept workspaces and shells, and what pi can load in one), Zero touch (how often runs needed a person) and
293
+ Setup (a live checklist for a new deployment). It reads through the same code as the panel, so the two never disagree;
294
+ the panel shows the waiting runs too.
295
+ It can act as well as show: cancel, retry, remove and re-run jobs, answer a parked run, pause the fleet or one queue,
296
+ change what a trigger's jobs get and edit the configuration, each previewed (with how to undo it), confirmed and recorded in one audit log that holds
297
+ the panel's own writes too, and after each change the page names it, who made it and its audit row, with an Undo
298
+ where there is a way back. When `serve` starts it prints how to sign in (the commands that make a token or a one time
299
+ link, never a token), and `pi-dispatch-console link --name <you> --port <n>` prints the link for an SSH tunnel's local
300
+ port. The sign-in page says why a session ended. Every running job's progress shows in its row on the fleet page
301
+ and on its run page, and its transcript, redacted, streams live
302
+ on its run page for operators, and the panel's live tail
303
+ (`l`) reads the same transcript for a run on any host. Nothing listens unless you start it. In pi,
304
+ `/dispatch console [page] [--link]` prints a page's address, says whether the console is running, makes a one time
305
+ sign-in link for an operator token (shown only to you, and recorded in the audit log first), and opens your browser
306
+ when the session is local (not over SSH; `--no-open` keeps it closed). See
307
+ [`docs/console.md`](https://github.com/edgehero/pi-dispatch/blob/main/docs/console.md).
308
+
225
309
  ## More than one machine
226
310
 
227
- The console reads the whole deployment, not one host. The status line names the workers once they have
311
+ The panel reads the whole deployment, not one host. The status line names the workers once they have
228
312
  names. The run detail names the machine that ran a job. The pause switch stops every queue, and the
229
313
  scheduler view spans hosts. On a single host none of that shows, because there is nothing to tell apart.
230
314
  The HOSTS view (`u`) shows each machine's slots, budget and running jobs now and how busy it was over the last 7
@@ -238,20 +322,18 @@ See [`docs/multi-host.md`](https://github.com/edgehero/pi-dispatch/blob/main/doc
238
322
  pi install npm:@edgehero/pi-dispatch-admin # then, in pi: /dispatch
239
323
  ```
240
324
 
241
- **This is the default way to set up pi-dispatch.** With nothing configured, `/dispatch` starts a guided
242
- setup, in this order:
243
-
244
- 1. an opening choice and a deployment folder;
245
- 2. a container runtime check (Docker, or rootless Podman on Linux), with pointers per OS if it is missing.
246
- It runs **first** on purpose, so no bandwidth is spent where `up` cannot work;
247
- 3. a consented npm install of the pinned runtime;
248
- 4. `pi-dispatch up`, running its own prompts in your terminal (Valkey with its password, the egress proxy,
249
- the config files);
250
- 5. the deployment pointer, so `/dispatch` finds this deployment from any directory;
251
- 6. a notice naming the file your provider key belongs in;
252
- 7. optional: the worker as a service, GitHub App credentials (`setup github`, the one step that mints a
253
- private key), a trigger edge (receiver service, docker compose profile or the polling command), and a
254
- first **cron** trigger for the repo you are in.
325
+ **This is the default way to set up pi-dispatch.** With nothing configured, `/dispatch` offers
326
+ **Finish setup in browser**, checks Docker or rootless Podman (and OpenShell when configured), installs
327
+ exact worker, admin and pi packages in a durable deployment folder, then runs the consented
328
+ `up --console` pass. It offers a deployment pointer and opens `/setup` with a private one-use link.
329
+ The checklist uses actual heartbeat and doctor evidence, keeps Starting distinct from Ready, and offers
330
+ individually previewed and confirmed service actions, a create-only provider key field and editable
331
+ first-trigger recipes. [First run](../docs/console.md#first-run) explains the explicit local host grant,
332
+ read-only/viewer/agent views, key and invitation privacy, and terminal recovery.
333
+
334
+ **Guided setup** retains the terminal workflow: runtime check and pinned install, `up`, deployment pointer,
335
+ provider-key guidance, optional worker service, GitHub credentials, receiver or polling, and a first local
336
+ cron trigger. GitHub setup asks for a webhook URL or `--no-webhook`; browser App creation remains open.
255
337
 
256
338
  Every step says what it will do, asks first and can be declined. Nothing is written into your repo, and no
257
339
  credential passes through a dialog. A deployment whose queue is only down keeps the unreachable banner:
@@ -267,10 +349,13 @@ when that file is yours and nobody else can write it. A key your env sets differ
267
349
  warning, never with its value. The switches that grant a capability (`PI_BACKENDS`, `PI_EGRESS`,
268
350
  `DOCKER_HOST`, `PI_DISPATCH_RUN_ROOTS`) are never read from a file.
269
351
 
270
- `dispatch_run` does nothing until you set one more variable yourself. `PI_DISPATCH_RUN_ROOTS` is empty by
271
- default, and an empty allowlist refuses every folder. The deployment pointer cannot set it (it carries
272
- paths, never capability grants), so widening that allowlist is always your own env edit. No allowlist
273
- reaches commands either: a `run.command` fires from the reviewed triggers file only.
352
+ Paid model starts need explicit valid `PI_DISPATCH_RUN_ROOTS` in the actual pi process environment.
353
+ Fire now and local or cron reruns also require explicit valid `PI_DISPATCH_RUN_PER_HOUR`; `dispatch_run`
354
+ defaults to three starts per hour when that value is absent or invalid, and zero disables it.
355
+ Headless mutation additionally requires
356
+ `PI_DISPATCH_AGENT_WRITES=1`. None is loaded from the deployment pointer or its `.env`. A reviewed external
357
+ skill may use private owner context to propose a permitted operation, but it cannot grant authority or
358
+ send an answer. Upgrade the host runtime and console together before using an agent token.
274
359
 
275
360
  ## Get the whole thing
276
361
 
@@ -279,3 +364,36 @@ reaches commands either: a `run.command` fires from the reviewed triggers file o
279
364
  MIT, self hosted. Read [`SECURITY.md`](https://github.com/edgehero/pi-dispatch/blob/main/SECURITY.md)
280
365
  before you rely on it: it states plainly what is and is not defended. Short version: the trust model is a
281
366
  GitHub Action's. Whoever can merge to your default branch can instruct the agent.
367
+
368
+ ## Configuration in the browser
369
+
370
+ The [operator console](../docs/console.md#configuration-and-trigger-pages) includes a Pulse Configuration
371
+ page, a page per trigger and a structured editor for five trigger kinds. Edit and Delete work from each
372
+ row, with a diff, confirmation and Undo. Human row numbers count from 1; tool indexes remain zero-based.
373
+ The editor and its JSON fallback preserve the add tool's secret-bundle opt-out.
374
+
375
+ **What its jobs get**, on a trigger's page, says what a job of it would start with on each host, with a label for each host, and under each row what
376
+ a recent run really had.
377
+
378
+ There a person changes the flow, the provider and model, the job cap, the allowed models and fallbacks, the MCP
379
+ servers, the tools, the all-or-nothing switch for staged packages, each extension the trigger leaves out and each extension's tool it removes, with one preview that
380
+ says each change in words, one Confirm, and Undo.
381
+
382
+ An extension left out does not load, and a tool removed leaves the rest of its extension running. Neither stops what an agent that can run commands, write files or edit files can reach
383
+ ([what exclusion does not stop](../docs/exclude-tools.md#what-exclusion-does-not-stop)). Every running machine must run a release that can read these two settings: the
384
+ [upgrade notes](../docs/upgrading.md#what-a-fleet-needs-before-a-trigger-leaves-something-out) say which release, and what to do until then. While a running worker cannot read them, the page refuses the change and names it.
385
+
386
+ A viewer reads the same rows with no controls, an agent's page draws no card, and no tool reaches the action. The file works as it
387
+ always has ([`docs/console.md`](../docs/console.md#what-a-triggers-jobs-get)).
388
+
389
+ `dispatch_trigger_edit` also takes `maxTurns` and the four run-option flags. `dispatch_trigger_fire(index)`
390
+ shares the console's Fire now planner, reserve and refusals. It fires a served cron trigger after the same fresh folder, committed flow, clean tree and hourly checks
391
+ as `dispatch_run`. Interactive callers confirm; headless callers need the process write grant and both
392
+ paid-start grant values in the pi or console process environment.
393
+ Viewers see trigger facts and runs without private prompt text or write controls.
394
+
395
+ The Triggers page groups rules by schedule and forge, with retained history, spend and a timezone-aware
396
+ schedule view. Its phone and viewer layouts keep the same facts readable. **Check an event** uses the
397
+ receiver filters to explain a hypothetical match without a forge call, queue write or spend. It is a
398
+ viewer read, available even on a read-only console; entered permissions remain assumptions and comment
399
+ text is neither saved nor logged. Rules and filters still work without JavaScript.