Skip to content

Commit d826df9

Browse files
committed
docs: one analytics story, and the images catch up with the consolidated surface (issue #181)
The last slice of #181: every doc and both READMEs now describe the one analytics surface. - docs/costs.md and docs/graph.md lose their view/command sections and survive as the semantics references behind what the insights page draws; docs/insights.md speaks the bare grammar, gains the budget and trend-line reading bullets, and points the what-if at insights whatif; demo.md's shot list gains the i beat and the exact new footer; workflows.md and launch-kit.md updated. - README.md: the intro bullet, the when-to-use paragraph (bare /dispatch insights, budget dials named as the one real lever), the admin-panel section rewritten around the i key and the page, the command list, and the usage-ledger sentence. admin/README.md: the three analytics bullets merge into one insights story. Dash rule holds in both. - Images: costs-view.svg/png DELETED (the view is gone); dispatch-dashboard.svg's footer line rewritten to the shipped footer (i insights; row width preserved at 80 chars inside borders) and its PNG re-rendered at the exact prior 1803x1811; insights-view.png regenerated from the page WITH the budget panel, cumulative line and flow multiples; graph-view.png kept byte- unchanged as the topology close-up. Changed references bump to ?v=0.12.0. Specs UNCHANGED, checked: this slice states what the code slices shipped and changes no behaviour. Suite green in the CI posture: 2192 tests, 0 skipped, live Valkey. Signed-off-by: Rob Boerman <robboerman@live.nl>
1 parent 8d88229 commit d826df9

13 files changed

Lines changed: 90 additions & 174 deletions

README.md

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@ did and what it spent, and shuts the container down. A durable queue absorbs bur
1313
checked before a single token is spent, and a live admin panel shows everything and can turn the whole
1414
thing off.
1515

16-
![The /dispatch dashboard overlay, theme-colored: live queue state, day/week/month spend meters plus a daily token counter, the unified triggers pane (cron, label, comment, pull_request; selectable and editable), scheduled pause windows, and the interactive runs list, in one framed TUI](docs/images/dispatch-dashboard.svg?v=0.5.0)
17-
18-
![The COSTS view, verdict-first cost analytics: per-plan SAVING/LOSING verdicts against API rates, a daily spend sparkline, per-flow, per-trigger, per-model and per-repo spend, subscription amortization with peak-window facts, and a what-if that re-prices a flow under another model, every estimate visibly marked](docs/images/costs-view.svg?v=0.11.0)
16+
![The /dispatch dashboard overlay, theme-colored: live queue state, day/week/month spend meters plus a daily token counter, the unified triggers pane (cron, label, comment, pull_request; selectable and editable), scheduled pause windows, and the interactive runs list, in one framed TUI](docs/images/dispatch-dashboard.svg?v=0.12.0)
1917

2018
![Transcript of /dispatch status, runs, and triggers: queue counts, the run-history table with per-job token and cost accounting, and the unified {on,run} triggers list](docs/images/dispatch-commands.svg?v=0.5.0)
2119

@@ -25,9 +23,9 @@ README, no permission system. pi-dispatch is exactly that missing operational la
2523
- **The container is the boundary.** Every job runs `--cap-drop=ALL`, non-root, ephemeral, with its
2624
instructions mounted read-only. That is pi's missing permission system, enforced by Docker.
2725
- **Spend is bounded before a container starts**: a per-job turn budget plus daily, weekly and monthly
28-
caps, checked before a single token is spent. And analyzed after: the panel's COSTS view shows spend
29-
per flow, trigger, model, day and repo, what a subscription actually saves, and what a flow would
30-
cost on another model ([`docs/costs.md`](docs/costs.md)).
26+
caps, checked before a single token is spent. And analyzed after: the insights page shows spend
27+
per flow, trigger, model, day and repo, what a subscription actually saves, what a flow would
28+
cost on another model, and the budget dials themselves ([`docs/costs.md`](docs/costs.md)).
3129
- **The image is yours to shape.** Bake a project's toolchain into [`image/Dockerfile`](image/Dockerfile);
3230
it ships Playwright and Chromium, so a flow can build a frontend, screenshot it, and iterate on the
3331
rendered result. Any trigger can name its own image with `run.image`
@@ -55,10 +53,11 @@ here it is just how the pieces fit). You **design** loops as triggers plus commi
5553
**graph** shows the loops you actually built (what triggers what, what chained to what, where a skill's
5654
own text says it might loop, [`docs/graph.md`](docs/graph.md)); and **insights** prices them (what each
5755
trigger and flow costs, whether a subscription pays off, drawn as charts beside that same topology,
58-
[`docs/insights.md`](docs/insights.md)). One `/dispatch insights html` gives you the whole picture as a
59-
single file your browser opens from disk:
56+
[`docs/insights.md`](docs/insights.md)). One `/dispatch insights` gives you the whole picture as a
57+
single file your browser opens from disk, budget dials included, because the caps are the one lever
58+
that actually changes what all of this costs:
6059

61-
![The insights page: KPI tiles, a plan verdict card, the daily spend chart, per-flow/per-trigger/per-model/per-repo breakdowns with plan-covered buckets drawn as chips instead of dollar bars, and the trigger/flow topology with spend badged onto the triggers that earned it](docs/images/insights-view.png?v=0.11.0)
60+
![The insights page: KPI tiles, the budget dials, a plan verdict card, the daily and cumulative spend charts, per-flow trend panels, the four breakdowns with plan-covered buckets drawn as chips instead of dollar bars, and the trigger/flow topology with spend badged onto the triggers that earned it](docs/images/insights-view.png?v=0.12.0)
6261

6362
## Quickstart
6463

@@ -407,16 +406,15 @@ Steer the running worker without stopping it, from any terminal:
407406
## The admin panel
408407

409408
The dashboard shown at the top of this README is a **pi extension**: it loads into your own interactive
410-
pi session. No daemon, no web app, no network port. Beside the dashboard, `/dispatch graph` renders the
411-
whole trigger and flow topology: what triggers what, what chained to what in the recorded runs, what a
412-
skill's own text says it might chain to, plus orphan skills and dangling triggers. It comes as a
413-
dashboard view (`g`), as plain text, and as `/dispatch graph html`, a self contained page your browser
414-
opens from disk (still no server and no port) with the topology drawn Node-RED style
415-
([`docs/graph.md`](docs/graph.md)). Trigger rows carry their schedule (next fire, or overdue) and
416-
their window spend, and `/dispatch insights html` combines this topology with the cost analytics on
417-
one page ([`docs/insights.md`](docs/insights.md), shown [above](#when-to-use-it)).
409+
pi session. No daemon, no web app, no network port. Analytics live on the insights page: pressing `i`
410+
(or typing `/dispatch insights`) writes one self contained file and opens your browser (still no
411+
server and no port), with the whole trigger and flow topology drawn Node-RED style, what triggers
412+
what, what chained to what in the recorded runs, what a skill's own text says it might chain to,
413+
orphan skills and dangling triggers flagged, each cron's next fire or overdue state, and spend badged
414+
onto the triggers that earned it ([`docs/graph.md`](docs/graph.md) explains every edge;
415+
[`docs/insights.md`](docs/insights.md) the page, shown [above](#when-to-use-it)).
418416

419-
![The trigger and flow graph as /dispatch graph html draws it: cron and forge triggers wired to their flows, an observed chain edge carrying its run count and recency, a potential mention, a skill with its prose loop grouped inside it, cron re-arm loops with their schedules, an orphan skill dimmed, the forge group naming the repos its runs hit, and the legend stating the chain caps and honesty counters](docs/images/graph-view.png?v=0.11.0)
417+
![The topology pane of the insights page: cron and forge triggers wired to their flows, an observed chain edge carrying its run count and recency, a potential mention, a skill with its prose loop grouped inside it, cron re-arm loops with their schedules, an orphan skill dimmed, the forge group naming the repos its runs hit, and the legend stating the chain caps and honesty counters](docs/images/graph-view.png?v=0.12.0)
420418

421419
```bash
422420
pi install npm:@edgehero/pi-dispatch-admin # then, in pi: /dispatch
@@ -436,13 +434,13 @@ banner: setup is offered when there is nothing, never over an outage.
436434

437435
Inside the panel: `p`/`r` pause and resume the queue, arrows and `Enter` drill into triggers and runs,
438436
`a`/`e`/`x` add, edit and delete triggers (validated, atomic, reloaded live by both services), `s` edits
439-
a limit, `w` manages quiet hours, `c` opens the COSTS view (its `f` key cycles spend by flow, model,
440-
trigger and repo). `Enter` on a run opens its full record:
437+
a limit, `w` manages quiet hours, `i` opens the insights page. `Enter` on a run opens its full
438+
record:
441439

442440
![The RUN_DETAIL drill-in, a colored post-mortem of one run's PII-free record: outcome, target, timing with duration, turns/exit/budget slot, tokens and cost, and a chain line naming spawned children](docs/images/dispatch-run-detail.svg)
443441

444-
The same surface exists as plain commands (`/dispatch status | runs | logs | budget | triggers | costs |
445-
graph | insights | run | pause | resume | set | unset`), all local, no model involvement.
442+
The same surface exists as plain commands (`/dispatch status | runs | logs | budget | triggers |
443+
insights | run | pause | resume | set | unset`), all local, no model involvement.
446444

447445
### Operating pi-dispatch from your AI
448446

@@ -525,7 +523,7 @@ Same machinery, per-forge correctness differences, each with a full setup doc:
525523

526524
Every job writes a durable, id-only record under `PI_LOGS_DIR` (never issue or comment text; raw logs
527525
are opt-in via `PI_CAPTURE_JOB_LOGS=1` and stay host-side). Each record carries a per-model **usage
528-
ledger**, which is what the COSTS view, `/dispatch costs`, and the what-if re-pricing fold over. Declare
526+
ledger**, which is what the insights page, `dispatch_costs`, and the what-if re-pricing fold over. Declare
529527
what your subscriptions cost in `subscriptions.json` and the screen shows whether they actually save
530528
money; without it, zero-rate runs show `$0 (unrated)`, never "free" ([`docs/costs.md`](docs/costs.md)).
531529

admin/README.md

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -55,26 +55,14 @@ Four forges: GitHub, GitLab, Forgejo (and Gitea), Azure DevOps. **Who may fire a
5555
One command puts a live TUI over the whole deployment:
5656

5757
<p align="center">
58-
<img src="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/dispatch-dashboard.png?v=0.5.0" alt="The /dispatch panel: status, spend meters, triggers, runs, and settings" width="820">
58+
<img src="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/dispatch-dashboard.png?v=0.12.0" alt="The /dispatch panel: status, spend meters, triggers, runs, and settings" width="820">
5959
</p>
6060

6161
- **Status and spend.** Queue and worker state, day/week/month spend meters, a daily token counter, and a run-history table with per-job tokens and cost.
62-
- **Costs, analyzed honestly.** The COSTS view (`c`) shows spend per flow, model, trigger, repo and day, what each declared subscription actually saves against API rates, and a what-if that re-prices a flow under another model. Every dollar carries its class: a plan-covered run never renders as $0.00, and an estimate is always marked as one.
62+
- **Insights, the one analytics page.** Press `i` on the panel (or type `/dispatch insights`) and a single self contained page opens in your browser: the budget dials (the one lever that actually changes what all of this costs), per-plan verdicts against API rates, daily, cumulative and per-flow spend charts, the four breakdowns (flow, trigger, model, repo), and the whole trigger and flow topology with spend badged onto the triggers that earned it. Every dollar carries its class: a plan-covered run never renders as $0.00, and an estimate is always marked as one. Design your agent loops as triggers and skills, see the loops you actually built, and see what each one costs, all in one place ([`docs/insights.md`](https://github.com/edgehero/pi-dispatch/blob/main/docs/insights.md)).
6363

6464
<p align="center">
65-
<img src="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/costs-view.png?v=0.11.0" alt="The COSTS view: per-plan verdicts against API rates, a daily spend sparkline, spend by flow, trigger, model and repo, and subscription amortization" width="820">
66-
</p>
67-
68-
- **The topology, as a graph.** The GRAPH view (`g`) and `/dispatch graph` show what triggers what, what chained to what in the recorded runs, and what a skill's own text says it might chain to, with orphan skills and dangling triggers flagged, each cron's next fire or overdue state, and each trigger's window spend. `/dispatch graph html` draws the same picture Node-RED style in your browser, from one self contained file on disk: no server, no port, and the page reloads itself when you regenerate it.
69-
70-
<p align="center">
71-
<img src="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/graph-view.png?v=0.11.0" alt="The trigger and flow graph: triggers wired to their flows, an observed chain edge with its count and recency, a potential mention, a skill with its prose loop grouped inside it, cron re-arm loops, an orphan skill dimmed, the forge group naming the repos its runs hit, and the legend stating the chain caps and honesty counters" width="820">
72-
</p>
73-
74-
- **One page for both questions.** `/dispatch insights html` writes a single self contained page: the topology with spend badged onto its triggers, beside the cost analytics drawn as charts (daily spend, the four breakdowns, plan verdict cards). Design your agent loops as triggers and skills, see the loops you actually built, and see what each one costs, all in one place ([`docs/insights.md`](https://github.com/edgehero/pi-dispatch/blob/main/docs/insights.md)).
75-
76-
<p align="center">
77-
<img src="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/insights-view.png?v=0.11.0" alt="The insights page: KPI tiles, a plan verdict card, the daily spend chart, the four breakdowns with plan-covered buckets drawn as chips instead of dollar bars, and the topology with spend badges" width="820">
65+
<img src="https://raw.githubusercontent.com/edgehero/pi-dispatch/main/docs/images/insights-view.png?v=0.12.0" alt="The insights page: KPI tiles, a plan verdict card, the daily spend chart, the four breakdowns with plan-covered buckets drawn as chips instead of dollar bars, and the topology with spend badges" width="820">
7866
</p>
7967

8068
- **Triggers, editable live.** cron, label, comment and pull_request triggers with colored drill-ins showing what fires each one, what it runs, and its trust model. Added, edited and deleted without a restart. Triggers that run third-party code or a custom image are badged; opting in or out of either stays an edit to the reviewed `triggers.json`, which neither the console nor a model-callable tool will make for you.

docs/costs.md

Lines changed: 23 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,24 @@
11
# Cost analytics
22

33
Every run records what it spent (`docs`: run history; `specs`: `REQ-TOKEN-ACCOUNTING-AND-CAPS`). The
4-
costs surface makes that history analyzable: what a flow costs, what a month costs per model, what a
4+
cost analytics make that history analyzable: what a flow costs, what a month costs per model, what a
55
subscription is actually saving, and what a flow *would* cost on a different model. It informs; it
66
changes nothing — no auto-switching, no vendor API calls, no database (`REQ-COST-ANALYTICS`,
77
`DES-COST-FOLD-BY-SCAN`).
88

9-
## The COSTS view
10-
11-
Press `c` on the dashboard (`/dispatch`). The view is verdict-first:
12-
13-
```
14-
┌ pi-dispatch ── COSTS · Aug 2026 (mtd) ──────────────────────────────────────────┐
15-
│ VERDICT kimi-allegro is SAVING ~$4.89 est. this month │
16-
│ plan price (prorated) $99.00 → $39.60 · plan runs @ API ~$44.49 est. │
17-
│ daily ▁▁▂▃▂▅▇▃▂▁·▁▂▂▃█▄▂▁▁▂▃▂▁▁▂▄▃▂▁ Σ ≥$12.41 · max $3.10/d │
18-
│ FLOW RUNS TOKENS COST API-EQUIV │
19-
│ › triage 41 12.4M ≥$8.02 — │
20-
│ nightly-sync 28 6.1M plan:kimi ~$3.90 est. │
21-
│ plans kimi-allegro $99/mo · 28 runs · ~$3.54 est./run amortized │
22-
│ peak 5h rolling window: 9 runs, 12.4M tok — limit undisclosed by vendor │
23-
│ ~ estimates at pi-ai 0.80.7 · 2 runs unmetered · 3 not repriceable │
24-
│ [↑↓] row [f] table [t] 7d/30d/mtd [w] what-if [esc] back │
25-
└─────────────────────────────────────────────────────────────────────────────────┘
26-
```
27-
28-
Keys: `t` cycles the window (7d / 30d / month-to-date), `f` cycles the rollup table (by flow, by
29-
model, by trigger, by repo), `w` opens the what-if on the selected flow (press again to cycle
30-
candidate models; `/` type-to-filters the full priced catalog), `Esc` backs out one layer at a time.
31-
32-
The **by-trigger** table answers "which trigger burns the most" and "what did its failures cost":
33-
each row is a `triggers.json` entry (attributed by the same persisted index-and-type join the graph
34-
view uses), with a FAIL count and, when failures spent anything, the failed share beside the total.
35-
Runs no trigger claims stay visible as their own rows, never blended in: `(chained runs)` for
36-
children spawned by another run, `(manual/local)` for CLI dispatches, `(unattributed)` for forge runs
37-
whose recorded trigger no longer matches the current file. The **by-repo** table groups spend by the
38-
target repository (issue and MR numbers stripped), with `local:<folder>` targets as their own rows.
9+
The surface is the **insights page** ([`insights.md`](insights.md)): `/dispatch insights` writes and
10+
opens one self-contained file with the plan verdicts, the daily and cumulative spend charts, the
11+
per-flow trend panels, and the four breakdowns (by flow, by trigger, by model, by repo) — beside the
12+
trigger/flow topology those numbers come from. This document explains the semantics behind every
13+
dollar that page draws.
14+
15+
The **by-trigger** breakdown answers "which trigger burns the most" and "what did its failures
16+
cost": each row is a `triggers.json` entry (attributed by the persisted index-and-type join the
17+
topology uses). Runs no trigger claims stay visible as their own rows, never blended in:
18+
`(chained runs)` for children spawned by another run, `(manual/local)` for CLI dispatches,
19+
`(unattributed)` for forge runs whose recorded trigger no longer matches the current file. The
20+
**by-repo** breakdown groups spend by the target repository (issue and MR numbers stripped), with
21+
`local:<folder>` targets as their own rows.
3922

4023
## How to read the numbers
4124

@@ -100,17 +83,17 @@ second caveat too: same token profile, different tokenizers — directional only
10083
history gets one offer: the `$0.5–$5/job` band recorded at `OQ-002`, scaled by the flow's run count and
10184
labeled `unmeasured (OQ-002)`.
10285

103-
## Without the TUI
86+
## The surfaces
10487

105-
- `/dispatch insights html` — the browser surface: the same fold drawn as charts (daily spend,
106-
the four breakdowns, plan verdict cards) beside the trigger/flow topology, in one self-contained
107-
file ([`insights.md`](insights.md)).
108-
- `/dispatch costs [7d|30d|mtd]` — the same fold, plain text, same labels.
109-
- `/dispatch costs whatif <provider>/<model> --flow <flow>` — scripting-friendly what-if; unknown
110-
models get closest-match suggestions (this is the full-catalog path). `--flow` is **required**: the
111-
estimate scores one flow's median run, not a portfolio, so the command refuses without it.
88+
- `/dispatch insights [7d|30d|mtd]` — the page: the fold drawn as charts beside the trigger/flow
89+
topology, in one self-contained file your browser opens from disk ([`insights.md`](insights.md)).
90+
Over SSH the file still writes and its URL still prints.
91+
- `/dispatch insights whatif <provider>/<model> --flow <flow>` — the what-if: re-prices a flow's
92+
recorded token profiles under another model. Unknown models get closest-match suggestions, and
93+
tab completion offers the full priced catalog. `--flow` is **required**: the estimate scores one
94+
flow's median run, not a portfolio, so the command refuses without it.
11295
- The `dispatch_costs` tool returns the fold as JSON in which **every monetary value carries its
113-
`class`** — a model reading it can no more launder an estimate into a fact than the screen can.
96+
`class`** — a model reading it can no more launder an estimate into a fact than the page can.
11497

11598
## Environment
11699

0 commit comments

Comments
 (0)