bullswarm 0.32.0 → 0.33.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/CHANGELOG.md +295 -0
- package/GOAL.md +1 -1
- package/README.md +66 -10
- package/data/openrouter-benchmarks.json +7979 -7867
- package/data/plan-prices.json +10 -0
- package/docs/design/dashboard-prototype.html +914 -0
- package/docs/design/owner-review-2026-09-18/budget.jpeg +0 -0
- package/docs/design/owner-review-2026-09-18/history-unknown-project.jpeg +0 -0
- package/docs/design/owner-review-2026-09-18/home-phone-landscape.jpeg +0 -0
- package/docs/design/owner-review-2026-09-18/home-phone-portrait.jpeg +0 -0
- package/docs/design/owner-review-2026-09-18/round2-budget-codex-row.png +0 -0
- package/docs/design/owner-review-2026-09-18/round2-budget-phone.jpeg +0 -0
- package/docs/design/owner-review-2026-09-18/round2-help-tab.png +0 -0
- package/docs/design/owner-review-2026-09-18/round2-models-lines.png +0 -0
- package/docs/design/owner-review-2026-09-18/round2-runs-duration-cut.png +0 -0
- package/docs/design/owner-review-2026-09-18/round2-trends-30d-horizontal-split.png +0 -0
- package/docs/design/owner-review-2026-09-18/round2-trends-desktop.png +0 -0
- package/docs/design/owner-review-2026-09-18/round2-trends-phone.png +0 -0
- package/docs/design/owner-review-2026-09-18/run-page-budget.jpeg +0 -0
- package/docs/design/owner-review-2026-09-18/runs-list.jpeg +0 -0
- package/docs/design/owner-review-2026-09-18/stats-pools.jpeg +0 -0
- package/docs/design/owner-review-2026-09-18/stats-trends-spent.jpeg +0 -0
- package/docs/design/prototype-frames/README.md +12 -0
- package/docs/design/prototype-frames/budget-120.tagged.txt +40 -0
- package/docs/design/prototype-frames/budget-120.txt +40 -0
- package/docs/design/prototype-frames/budget-55.tagged.txt +26 -0
- package/docs/design/prototype-frames/budget-55.txt +26 -0
- package/docs/design/prototype-frames/fleet-120.tagged.txt +40 -0
- package/docs/design/prototype-frames/fleet-120.txt +40 -0
- package/docs/design/prototype-frames/fleet-55.tagged.txt +26 -0
- package/docs/design/prototype-frames/fleet-55.txt +26 -0
- package/docs/design/prototype-frames/help-120.tagged.txt +40 -0
- package/docs/design/prototype-frames/help-120.txt +40 -0
- package/docs/design/prototype-frames/help-55.tagged.txt +26 -0
- package/docs/design/prototype-frames/help-55.txt +26 -0
- package/docs/design/prototype-frames/history-120.tagged.txt +40 -0
- package/docs/design/prototype-frames/history-120.txt +40 -0
- package/docs/design/prototype-frames/history-55.tagged.txt +26 -0
- package/docs/design/prototype-frames/history-55.txt +26 -0
- package/docs/design/prototype-frames/home-120.tagged.txt +40 -0
- package/docs/design/prototype-frames/home-120.txt +40 -0
- package/docs/design/prototype-frames/home-55.tagged.txt +26 -0
- package/docs/design/prototype-frames/home-55.txt +26 -0
- package/docs/design/prototype-frames/run-120.tagged.txt +40 -0
- package/docs/design/prototype-frames/run-120.txt +40 -0
- package/docs/design/prototype-frames/run-55.tagged.txt +26 -0
- package/docs/design/prototype-frames/run-55.txt +26 -0
- package/docs/design/prototype-frames/stats-models-120.tagged.txt +40 -0
- package/docs/design/prototype-frames/stats-models-120.txt +40 -0
- package/docs/design/prototype-frames/stats-models-55.tagged.txt +26 -0
- package/docs/design/prototype-frames/stats-models-55.txt +26 -0
- package/docs/design/prototype-frames/stats-overview-120.tagged.txt +40 -0
- package/docs/design/prototype-frames/stats-overview-120.txt +40 -0
- package/docs/design/prototype-frames/stats-overview-55.tagged.txt +26 -0
- package/docs/design/prototype-frames/stats-overview-55.txt +26 -0
- package/docs/design/prototype-frames/stats-pools-120.tagged.txt +40 -0
- package/docs/design/prototype-frames/stats-pools-120.txt +40 -0
- package/docs/design/prototype-frames/stats-pools-55.tagged.txt +26 -0
- package/docs/design/prototype-frames/stats-pools-55.txt +26 -0
- package/docs/design/prototype-frames/stats-projects-120.tagged.txt +40 -0
- package/docs/design/prototype-frames/stats-projects-120.txt +40 -0
- package/docs/design/prototype-frames/stats-projects-55.tagged.txt +26 -0
- package/docs/design/prototype-frames/stats-projects-55.txt +26 -0
- package/docs/design/prototype-frames/stats-trends-120.tagged.txt +40 -0
- package/docs/design/prototype-frames/stats-trends-120.txt +40 -0
- package/docs/design/prototype-frames/stats-trends-55.tagged.txt +26 -0
- package/docs/design/prototype-frames/stats-trends-55.txt +26 -0
- package/docs/design/prototype-frames/step-120.tagged.txt +40 -0
- package/docs/design/prototype-frames/step-120.txt +40 -0
- package/docs/design/prototype-frames/step-55.tagged.txt +26 -0
- package/docs/design/prototype-frames/step-55.txt +26 -0
- package/docs/design/prototype-shots/Screenshot 2026-09-17 at 9.14.40/342/200/257AM.png +0 -0
- package/docs/design/prototype-shots/Screenshot 2026-09-17 at 9.15.23/342/200/257AM.png +0 -0
- package/docs/design/prototype-shots/Screenshot 2026-09-17 at 9.15.31/342/200/257AM.png +0 -0
- package/docs/design/prototype-shots/Screenshot 2026-09-17 at 9.15.39/342/200/257AM.png +0 -0
- package/docs/design/prototype-shots/Screenshot 2026-09-17 at 9.15.45/342/200/257AM.png +0 -0
- package/docs/design/prototype-shots/Screenshot 2026-09-17 at 9.15.50/342/200/257AM.png +0 -0
- package/docs/design/prototype-shots/Screenshot 2026-09-17 at 9.16.02/342/200/257AM.png +0 -0
- package/docs/design/prototype-shots/Screenshot 2026-09-17 at 9.16.07/342/200/257AM.png +0 -0
- package/docs/design/prototype-shots/Screenshot 2026-09-17 at 9.16.18/342/200/257AM.png +0 -0
- package/docs/design/prototype-shots/Screenshot 2026-09-17 at 9.16.23/342/200/257AM.png +0 -0
- package/docs/design/prototype-shots/Screenshot 2026-09-17 at 9.16.27/342/200/257AM.png +0 -0
- package/docs/guide/observing.md +104 -59
- package/docs/guide/routing.md +81 -10
- package/docs/plans/dashboard-0.33-fidelity.goal.txt +13 -0
- package/docs/plans/dashboard-0.33-fidelity.md +283 -0
- package/docs/plans/dashboard-0.33-fidelity.program.json +220 -0
- package/docs/plans/dashboard-0.33-fidelity.rev2.json +338 -0
- package/docs/plans/dashboard-0.33-review.goal.txt +10 -0
- package/docs/plans/dashboard-0.33-review.program.json +117 -0
- package/docs/plans/dashboard-0.33.goal.txt +16 -0
- package/docs/plans/dashboard-0.33.md +315 -0
- package/docs/plans/dashboard-0.33.program.json +293 -0
- package/docs/plans/fidelity.goal.txt +1 -0
- package/docs/plans/fidelity.program.json +35 -0
- package/docs/reference/cli.md +67 -22
- package/docs/reference/configuration.md +1 -1
- package/docs/reference/providers.md +5 -5
- package/docs/workflow-design.md +1 -1
- package/mods/bullswarm/README.md +7 -6
- package/mods/bullswarm/hooks/pane.tsx +20 -2
- package/mods/bullswarm/hooks/pools.ts +2 -0
- package/mods/bullswarm/hooks/register.ts +14 -2
- package/mods/bullswarm/types/index.d.ts +4 -0
- package/package.json +1 -1
- package/providers/contrib/README.md +1 -1
- package/providers/contrib/command-code/provider.mjs +13 -5
- package/providers/contrib/{opencode2 → opencode}/connector.json +2 -1
- package/providers/contrib/{opencode2 → opencode}/provider.mjs +3 -3
- package/skill/references/providers.md +1 -1
- package/src/cli.js +56 -8
- package/src/help.js +49 -17
- package/src/lib/cli-flags.js +2 -1
- package/src/lib/config.js +73 -2
- package/src/lib/forecast.js +4 -2
- package/src/lib/prices.js +148 -0
- package/src/lib/project.js +81 -0
- package/src/lib/route.js +173 -46
- package/src/lib/spend.js +36 -1
- package/src/lib/state.js +417 -3
- package/src/lib/strategy.js +2 -2
- package/src/lib/usage.js +21 -3
- package/src/meters/framework.js +55 -1
- package/src/meters/registry.js +172 -14
- package/src/provider-kit.js +9 -3
- package/src/providers/claude-code/provider.mjs +28 -6
- package/src/providers/codex/provider.mjs +9 -4
- package/src/providers/grok/provider.mjs +9 -4
- package/src/strategy-cli.js +70 -5
- package/src/workflow/budget-model.js +567 -0
- package/src/workflow/budget-view.js +172 -0
- package/src/workflow/cli.js +55 -3
- package/src/workflow/dash-kit.js +1012 -0
- package/src/workflow/dashboard.js +2632 -423
- package/src/workflow/fleet-view.js +270 -0
- package/src/workflow/goal.js +54 -0
- package/src/workflow/history-view.js +548 -0
- package/src/workflow/history.js +295 -0
- package/src/workflow/rollup.js +462 -0
- package/src/workflow/runs-cli.js +109 -0
- package/src/workflow/stats-model.js +962 -0
- package/src/workflow/stats-view.js +1675 -0
- package/src/workflow/status.js +5 -0
- package/src/workflow/usage-view.js +107 -14
- package/src/workflow/v2-dispatch.js +183 -26
- package/src/workflow/v2-outcome.js +4 -1
- package/src/workflow/v2-runtime.js +55 -11
- package/src/workflow/v2-state.js +7 -1
- package/src/workflow/watch-cli.js +43 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,300 @@
|
|
|
1
1
|
# bullswarm changelog
|
|
2
2
|
|
|
3
|
+
## 0.33.0 — the dashboard release
|
|
4
|
+
|
|
5
|
+
- dashboard: the phone `Home` no longer hides data behind its width. The
|
|
6
|
+
`budget · this week` block draws every pool the desktop draws — four today —
|
|
7
|
+
or ends with `+N more` when the rows genuinely do not fit, and its names are
|
|
8
|
+
wide enough that `claude-code:wati` and `claude-code` read as two pools
|
|
9
|
+
rather than one truncated one. The by-pool, by-model and by-project lists
|
|
10
|
+
keep at least their top three rows (`+N more` for the rest) and always paint
|
|
11
|
+
the whole percentage, never `24…`. The summary figures sit one per line, so
|
|
12
|
+
`Busiest project` and `Favourite model` are whole at 55 columns, and the
|
|
13
|
+
spent tile's empty state fits the phone row.
|
|
14
|
+
- dashboard, **keys corrected**: `h` opens **Home** and `?` opens **Help**.
|
|
15
|
+
In 0.32.0 both opened Help, and an earlier 0.33.0 entry wrongly listed them
|
|
16
|
+
as unchanged. `r` `b` `s` `y` `f` keep the pages they opened. The key table,
|
|
17
|
+
the nav tail (`[Top] [End] [?.Help]`), the Help page, the README and the
|
|
18
|
+
observing guide all say the same thing, and tests pin both bindings.
|
|
19
|
+
- dashboard: a finished run the history index has not covered yet is named by
|
|
20
|
+
the project its `goal.json` working directory belongs to — the same
|
|
21
|
+
derivation `bullswarm workflow reindex` uses — instead of reading
|
|
22
|
+
`unknown project`. `unknown project` now means only what it says: no working
|
|
23
|
+
directory was recorded for that run.
|
|
24
|
+
- dashboard: the stacked column charts on `Home` (spent per day) and `Stats`
|
|
25
|
+
`Trends` are drawn to eighth-block precision. The top cell of a bar is one of
|
|
26
|
+
`▁▂▃▄▅▆▇█`, so a `≈$2.93` bar sits below its own `≈$3.00` tick instead of
|
|
27
|
+
overshooting it; the axis top and the row count are chosen together so every
|
|
28
|
+
tick label lands on a row with even spacing; and every non-zero pool slice
|
|
29
|
+
gets at least one eighth-block, smallest on top, so `codex` and
|
|
30
|
+
`command-code` appear on any day they spent anything.
|
|
31
|
+
- dashboard: `Stats` `Pools` drops the shared unlabelled “licence used per day,
|
|
32
|
+
by pool” line chart. Each pool now carries its own seven-day sparkline on its
|
|
33
|
+
own row — one glyph per day of end-of-day usage, `▏` on a day the quota
|
|
34
|
+
window rolled over — under one caption saying that a drop after `▏` is the
|
|
35
|
+
window resetting. A reset is read from the recorded `resets_at` moving, never
|
|
36
|
+
guessed from a falling reading. The row tails (`≈ $3.06 API`, `✓ 100%`) are
|
|
37
|
+
measured before the meter is sized, so nothing truncates at 170 or 200
|
|
38
|
+
columns.
|
|
39
|
+
- dashboard: `Budget` reads in plain words. Each pool is a header
|
|
40
|
+
(`name · weekly plan · resets <day time> (in Nd Nh)`) over four labelled
|
|
41
|
+
rows: `used` (the meter, a whole percent, and `N% of the window gone → on
|
|
42
|
+
track`), `by bullswarm` (this tool's share of the whole plan, with the
|
|
43
|
+
measured minutes and `other tools N%`), `room` (`about N more medium runs
|
|
44
|
+
before the reset`) and `so far` (≈ money and the two biggest workflows).
|
|
45
|
+
Figures are whole numbers. The subscription line appears only where a price
|
|
46
|
+
is declared — the `Subscription rate: —` rows are gone — and
|
|
47
|
+
`workflows 131.24% · rest 0% · workflows exceeds the reported meter` is
|
|
48
|
+
replaced by one footnote in words when the measured share exceeds the meter.
|
|
49
|
+
The page-foot notes are one short block.
|
|
50
|
+
- dashboard: **Runs and History are one page.** `Runs` opens on an `active`
|
|
51
|
+
block — every running or waiting run with its plan strip and per-step bar,
|
|
52
|
+
drawn exactly as `Home`'s running section draws it — and History's
|
|
53
|
+
day-grouped table below it: a day header with its count and ≈ total, then one
|
|
54
|
+
row per run with status glyph, short id, project, goal, duration, ≈ cost and
|
|
55
|
+
time, under the selection cursor, so `Enter` and the digits open a run and
|
|
56
|
+
older days load as the reader scrolls. The `agents` and `run it` blocks moved
|
|
57
|
+
to `Help`. The `History` tab is gone from the tab row — the tabs are Home,
|
|
58
|
+
Runs, Budget, Stats, Fleet — and **`y` jumps to the first day header** of
|
|
59
|
+
Runs. The one-second refresh keeps the table cursor where the reader put it
|
|
60
|
+
(it used to snap back to the in-flight run, so `Enter` opened the wrong
|
|
61
|
+
workflow).
|
|
62
|
+
- dashboard: the second owner-review round, from phone screenshots of the
|
|
63
|
+
0.33.0 preview. `Stats` `Models` draws stacked columns per day and model
|
|
64
|
+
instead of a three-row line chart that flattened every model under four
|
|
65
|
+
hours onto the zero line (Opus ran 29, 9, 897, 75, 278 and 686 minutes on
|
|
66
|
+
six consecutive days and showed on one). Axis labels mark the bottom of
|
|
67
|
+
their row, so a bar of 15 rises half a row above `14` instead of reading as
|
|
68
|
+
16. Phone columns are equal width and the charts use the rows the screen
|
|
69
|
+
has. A column never lays two colours side by side in one row: slices too
|
|
70
|
+
small for their own eighth merge into one grey `other` slice, counted in the
|
|
71
|
+
legend. Each pool and model keeps one colour on every page and period. Under
|
|
72
|
+
a column, totals keep one blank cell apart and a long duration falls back to
|
|
73
|
+
whole hours. `Budget`: a pool whose meter never moved during its measured
|
|
74
|
+
runs says `share unknown · meter did not move during 32 measured runs`
|
|
75
|
+
instead of `≈ 0%`; credits join the `used` row (`0 of 70 credits`); a pool
|
|
76
|
+
with nothing left says `no room left before the reset`. The Runs day table
|
|
77
|
+
never cuts a duration (`3h21m`, not `3h2…`). The tab row stays five tabs on
|
|
78
|
+
the Help page. Charts draw from fourteen hues and never give two series in
|
|
79
|
+
one chart the same colour (the 30-day Trends had three purples and the
|
|
80
|
+
Models chart seven models in two colours); slices stack smallest at the
|
|
81
|
+
bottom, biggest on top; the legend wraps to name every series instead of
|
|
82
|
+
hiding the rest behind `+N more`. The mouse now lights the clickable row
|
|
83
|
+
under the pointer in reverse video, the way the Mod pane does (a whole row
|
|
84
|
+
when it is the row's only target, just the button when several share a
|
|
85
|
+
row); the TUI asks the terminal for motion reports and releases them on the
|
|
86
|
+
way out. Only list rows light up (a run in the table, a step in a plan);
|
|
87
|
+
chart columns, tiles, meters and tabs do not, and inside a lit row only the
|
|
88
|
+
words reverse — a step's bar and the plan strip's `──○──` connectors keep
|
|
89
|
+
their colours. Home's breakdown percents sit right-aligned in one column, so `2%`
|
|
90
|
+
lines up under `19%`.
|
|
91
|
+
- dashboard, **no longer laggy**: a CPU profile of the idle TUI showed it busy
|
|
92
|
+
61% of the time. Every one-second tick re-discovered Claude accounts through
|
|
93
|
+
the macOS keychain (`security`, 100–300 ms, blocking), re-ran the pool-rename
|
|
94
|
+
migration check over the whole state.json, and on Runs re-read all 300 run
|
|
95
|
+
directories. Usage now reloads every 10 s, the keychain read is cached for a
|
|
96
|
+
minute, the migration check is remembered per file fingerprint, the run
|
|
97
|
+
catalogue rebuilds only when an active run changes or 15 s pass, and the
|
|
98
|
+
unknown-project fallback asks `git` once per working directory. Idle busy
|
|
99
|
+
share after: 14%. The painter now rewrites only the rows that changed
|
|
100
|
+
since the last frame (a spinner tick is a few dozen bytes instead of the
|
|
101
|
+
whole 120×40 screen), which is what a phone or a remote terminal feels.
|
|
102
|
+
- dashboard: no page draws an empty track where it has no data. The `Run`
|
|
103
|
+
page's budget block is titled `licence this run used`, shows whole percents
|
|
104
|
+
(`≈ 0.4% of the weekly plan`, as a one-cell `▏` sliver rather than an empty
|
|
105
|
+
bar), writes `free model · no licence meter` for an unmetered pool instead of
|
|
106
|
+
a dotted track and a `—`, and collapses to a single sentence when no pool is
|
|
107
|
+
metered. The plan strip's pool row prints the pool name alone when the cell
|
|
108
|
+
cannot hold pool and model. A paused run's live block says
|
|
109
|
+
`paused · bullswarm workflow resume <id> continues it` instead of `waiting for
|
|
110
|
+
the next dispatch`, and the ETA footnote is
|
|
111
|
+
`ETA —: <step> has no recorded duration yet` rather than
|
|
112
|
+
`N of N remaining steps recorded no expected duration`. The same rule removed
|
|
113
|
+
the dotted `meter unavailable` tracks from `Stats` `Pools`.
|
|
114
|
+
|
|
115
|
+
- dashboard: the visual-fidelity pass now composes `Home` with a four-column
|
|
116
|
+
7-day breakdown and a budget block, `Run` with a plan strip, per-step bars
|
|
117
|
+
and a `budget` / `live` / `so far` band, `Budget` with seven rows per pool
|
|
118
|
+
plus one consolidated footer, coloured stacked columns on `Stats` `Trends`,
|
|
119
|
+
and fixed columns on `History`, reducing its phone form from two rows per run
|
|
120
|
+
to one at 55 columns.
|
|
121
|
+
- dashboard: the shared palette keeps its four existing meter colours and adds
|
|
122
|
+
seven named roles, including the four-shade heat ramp; `Help` groups the `r`,
|
|
123
|
+
`b`, `s`, `y`, and `f` keys into 35 body rows at 55 columns (from about 51)
|
|
124
|
+
and drops the nonexistent `Budget` sub-tabs.
|
|
125
|
+
- dashboard: the `Run` plan strip closes a fan the way the prototype does —
|
|
126
|
+
each lower branch hangs under the `┬` that opened it, is ruled across to the
|
|
127
|
+
joint, and the last one ends in `┘` under the closing `┬`; it used to draw a
|
|
128
|
+
`┴` with nothing beneath it when the lower branch was the longer name. The
|
|
129
|
+
`Stats` `Models` footnote says `no per-model money` in words instead of
|
|
130
|
+
naming the `apiEquivalentUsd` field.
|
|
131
|
+
- dashboard: the phone layouts now put one item on one row where the page is a
|
|
132
|
+
list — `Stats` `Models`, `Stats` `Projects` (with its sparkline beside the
|
|
133
|
+
name), `Stats` `Pools`, `Fleet` and `History`, plus `Home`'s today tiles and
|
|
134
|
+
per-step bars. `Budget`'s seven-row pool block, `Home`'s `budget · this week`
|
|
135
|
+
pool and the `Runs` list keep their extra lines on purpose.
|
|
136
|
+
- dashboard: `Stats` `Models` draws a worker-minutes-per-day chart whose series
|
|
137
|
+
are coloured to match the model list beneath it, and `Stats` `Projects` draws
|
|
138
|
+
a sparkline beside every project name. At a 200-column frame a project keeps
|
|
139
|
+
name, sparkline and figures on one row, with the sparkline capped at four
|
|
140
|
+
cells per measured day so seven days read as a shape rather than a
|
|
141
|
+
frame-wide run of repeated glyphs.
|
|
142
|
+
- dashboard: `Stats` rows built from the shared `compactRow` now lay their
|
|
143
|
+
fields out on the frame minus their one-cell indent, so the last field no
|
|
144
|
+
longer lost its final character to the frame's own truncation (`p50 5…`
|
|
145
|
+
where `p50 54m` fits).
|
|
146
|
+
- dashboard: every page now composes to a 200-column frame instead of stopping
|
|
147
|
+
at the 120-column composition — measured on the real binary, the widest
|
|
148
|
+
painted row is 200 cells on every page except `Fleet`, which reaches 188.
|
|
149
|
+
- dashboard: `Run` draws a bar for the running step inside the plan strip, using
|
|
150
|
+
an empty indeterminate bar when the step recorded no expected duration, and
|
|
151
|
+
`Step` keeps its task summary short enough that the `output` and `artifacts`
|
|
152
|
+
sections both start inside a 26-row phone frame rather than below it.
|
|
153
|
+
- data: the pass keeps real figures and the `≈`/basis rule. An undeclared
|
|
154
|
+
subscription price, an expected duration, and a per-run licence draw
|
|
155
|
+
deliberately remain blank with their reasons. The months-wide heatmap does
|
|
156
|
+
not move over: `Stats` uses only history that exists and, when there are no
|
|
157
|
+
measured days, renders a blank with `No workflow history yet — the heatmap
|
|
158
|
+
has no measured days.` rather than inventing the prototype's number.
|
|
159
|
+
- docs: `README.md` and the observing guide now describe the shipped
|
|
160
|
+
composition and the same data-honesty rule, and name the three places whose
|
|
161
|
+
phone form deliberately keeps more than one row per item rather than claiming
|
|
162
|
+
a universal one-row layout.
|
|
163
|
+
|
|
164
|
+
- routing: measured pacing rates now charge timed in-flight work at the actual
|
|
165
|
+
`rate × remaining minutes` with no 3-point floor, so an expiring-soon pool
|
|
166
|
+
with a known burn rate is not demoted by a tie-breaker meant for unmeasured
|
|
167
|
+
pools. `config.inflightPenaltyPct` remains the per-agent fallback for pools
|
|
168
|
+
without a measured rate (and for in-flight records with unknown duration).
|
|
169
|
+
- workflow: every attempt record now carries `routeWhy` (the router's reason)
|
|
170
|
+
and `routeCandidates` (each pool's effective surplus, urgency state and
|
|
171
|
+
pacing forecast at pick time); `workflow action show --json` and
|
|
172
|
+
`runs result --json` print them, and older state files still load.
|
|
173
|
+
- dashboard: the full-screen surface now has eight pages — Home, Runs, Run,
|
|
174
|
+
Step, Budget, Stats, Fleet, and Help (History is the day table inside Runs,
|
|
175
|
+
see above). Home answers what happened today and what is active; Runs is the
|
|
176
|
+
active block over the day-grouped table; the integration actions sit on Help; Run
|
|
177
|
+
and Step explain a workflow and one action; Budget shows quota, measured
|
|
178
|
+
worker-time share, labelled money, fit, and biggest workflows; Stats covers
|
|
179
|
+
Overview, Trends, Pools, Models, and Projects; History is the dated timeline;
|
|
180
|
+
Fleet shows lane/provider rungs; Help names the controls. Home, Stats, and
|
|
181
|
+
History read the rollup index instead of parsing every run directory on each
|
|
182
|
+
refresh.
|
|
183
|
+
- workflow: every finished V2 run now records a per-run `rollup.json` and
|
|
184
|
+
appends an idempotent line to `~/.bullswarm/history/runs.jsonl`. On the real
|
|
185
|
+
corpus used for the release, `294` run directories yielded `181` indexed
|
|
186
|
+
finished V2 records; `105` legacy and `8` unfinished directories were left
|
|
187
|
+
out. History spans `15` recorded days, and `94` of the `188` V2 results are
|
|
188
|
+
verified.
|
|
189
|
+
- dashboard, **keys rebound** — three keys changed meaning, one is gone, and
|
|
190
|
+
seven are new. Rebound: `r` opened nothing and refreshed the view in 0.32.0
|
|
191
|
+
and now opens **Runs** (the 1 s timer refreshes, so no key needs to);
|
|
192
|
+
`b` was **move out** and now opens **Budget** (`Esc` and `←` are move out);
|
|
193
|
+
`Tab` was **next workflow** and now cycles the current page's **sub-tabs**
|
|
194
|
+
(`Shift+Tab` cycles workflows, as it did). Removed: the Usage page is
|
|
195
|
+
replaced by **Budget** (`b`) and **Fleet** (`f`), so **`u` is gone**, and
|
|
196
|
+
Usage's `l`/`p` lane/provider grouping keys are now **`Tab`** on Fleet.
|
|
197
|
+
New: `s` Stats, `y` History, `f` Fleet, `p` cycles the period, `Home` top,
|
|
198
|
+
`End` bottom, and `ctrl+s` copies the screen. Moved, not rebound: `i`, `/`
|
|
199
|
+
and `a` are **Runs-page** keys now that Home is the prototype's Home.
|
|
200
|
+
Unchanged: `1`–`9`, `Enter`/`→`/`l`, the arrows, `PgUp`, `PgDn` and `q`.
|
|
201
|
+
(Corrected: an earlier draft of this entry said `h`/`?` were unchanged. They
|
|
202
|
+
are not — `h` opened Help in 0.32.0 and now opens **Home**, and `?` alone
|
|
203
|
+
opens **Help**. `y` no longer opens a History page; it opens **Runs** at the
|
|
204
|
+
first day header of its history table. See the two entries below.)
|
|
205
|
+
- accounting: money and licence figures are either measured or carry `≈` with
|
|
206
|
+
their basis. API-equivalent estimates use the recorded per-attempt estimate;
|
|
207
|
+
a licence draw uses the measured pool rate multiplied by measured worker-
|
|
208
|
+
minutes and stays blank when no rate is available; an undeclared subscription
|
|
209
|
+
price stays null. On the release corpus, `113` of `188` V2 runs carried a
|
|
210
|
+
cost figure and the other `75` did not, so no zero was manufactured for them.
|
|
211
|
+
- workflow: `bullswarm workflow reindex [--json] [--force]` backfills finished
|
|
212
|
+
runs from their durable directories, skips legacy and unfinished runs,
|
|
213
|
+
repairs missing index entries, and can rebuild existing rollups with
|
|
214
|
+
`--force`. The JSON form reports `ok`, `indexPath`, `scanned`, `written`,
|
|
215
|
+
`skipped`, `legacy`, `unfinished`, `present`, `failed`, and `failures[]`.
|
|
216
|
+
- docs: the observing guide, README, CLI reference, command help, and Claude
|
|
217
|
+
Mod README now describe the eight pages, the full key map, the measured/
|
|
218
|
+
labelled money rule, and the Mod's smaller Run/Step/Usage-Pools surface.
|
|
219
|
+
|
|
220
|
+
## 0.32.1 — free models first, with graceful failover
|
|
221
|
+
|
|
222
|
+
- meters: rate-limited or failed live reads now persist a per-pool negative-cache hold (honouring `Retry-After` or the five-minute freshness window), and `pools`/the Claude Mod identify the stale snapshot's error and retry time.
|
|
223
|
+
- rename: the OpenCode pool is now `opencode`; the first run migrates saved
|
|
224
|
+
state, routing, provider, and meter names automatically, while historical
|
|
225
|
+
workflow run records keep their recorded `opencode2` name.
|
|
226
|
+
- routing: a pool whose model for the effort tier costs nothing is ranked ahead
|
|
227
|
+
of every metered pool while it is healthy. Free-ness is per (pool, effort
|
|
228
|
+
tier) and comes from the connector — `modelProfiles[].free`, or a model name
|
|
229
|
+
carrying a standalone `free` segment. The free tier sits below the forecast
|
|
230
|
+
gate and the 5-hour headroom tier and above expiring-soon urgency, so an
|
|
231
|
+
expiring metered window can now go unspent while free work runs; the ranking
|
|
232
|
+
among metered pools is unchanged. The reason reads `free pool first: <pool>
|
|
233
|
+
(free model <model>, …) · metered pools ranked below free: <pool> <surplus>`.
|
|
234
|
+
- routing: a pool that stalls, returns a server error, or (on a free pool) hands
|
|
235
|
+
back literally empty output takes a strike. The first is recorded; the second
|
|
236
|
+
consecutive one soft-benches the pool for a 10-minute cooldown, after which it
|
|
237
|
+
returns automatically. The strike count survives the cooldown and is cleared
|
|
238
|
+
only by a success. Auth is untouched: an upstream auth failure still
|
|
239
|
+
quarantines and still spreads across a credential group. An answer the
|
|
240
|
+
verifier judged thin but not empty stays semantic and is not retried
|
|
241
|
+
elsewhere.
|
|
242
|
+
- workflow: a free pool's silence clock is the median wall time of its own
|
|
243
|
+
recorded runs at that (pool, effort) rung — the `p50`, once 3 runs exist there
|
|
244
|
+
— with a 5-minute floor, instead of the one-hour default a metered pool keeps.
|
|
245
|
+
The multiplier on that median is 1 (`FREE_STALL_P50_FACTOR`): a worker silent
|
|
246
|
+
for as long as the whole rung usually takes has stopped working. Stalled
|
|
247
|
+
attempts are excluded from the median so a pool cannot tighten its own
|
|
248
|
+
threshold by stalling.
|
|
249
|
+
- workflow: a stalled attempt ends, keeps its partial output on disk (the retry
|
|
250
|
+
writes a new `-attempt-N` file beside it, never over it), releases its
|
|
251
|
+
in-flight ledger entry, and re-dispatches the same action on the next eligible
|
|
252
|
+
pool in the same run. The attempt record and `attempt.finished` carry
|
|
253
|
+
`stalled`, `partialOutput`, `silentSec` and `willRetry`; a new `pool.benched` event names
|
|
254
|
+
the pool, reason, strike count and deadline; the retry's reason is prefixed
|
|
255
|
+
`fallback from <pool> after stall <n>s`. A free-pool stall (and the
|
|
256
|
+
free-only literally-empty-output provider reclassification) does not spend
|
|
257
|
+
`maxMechanicalRetries`; the tried-set is the bound and each pool is tried at
|
|
258
|
+
most once for the action. A metered-pool stall keeps the mechanical retry
|
|
259
|
+
accounting.
|
|
260
|
+
- workflow: evidence and acceptance steps are exempt from the free tier and
|
|
261
|
+
route on pace as before, with one preference — a pool that wrote the work
|
|
262
|
+
being judged is chosen last, and only when no other pool is eligible, which
|
|
263
|
+
the reason then says (`evidence step: only the writer pool <pool> is
|
|
264
|
+
eligible`). This restores, in prefer-not rather than forbid form, the steering
|
|
265
|
+
removed in `eb83b79`; the reason line now names the exception, which its
|
|
266
|
+
absence was half the reason for that removal.
|
|
267
|
+
- pools: `bullswarm pools` prints `free=<model>` for a pool whose model costs
|
|
268
|
+
nothing (`free=<tier>:<model>` when it differs per effort tier, since `pools`
|
|
269
|
+
names no lane), `BENCHED until <time> (<reason>, <n> strikes)` for a benched
|
|
270
|
+
pool, and `strikes=<n>(<reason>)` for one carrying an uncounted-out strike. It
|
|
271
|
+
sweeps expired benches the same way it sweeps expired quarantines.
|
|
272
|
+
- routing: measured pacing rates now charge timed in-flight work at the actual
|
|
273
|
+
`rate × remaining minutes` with no 3-point floor, so an expiring-soon pool
|
|
274
|
+
with a known burn rate is not demoted by a tie-breaker meant for unmeasured
|
|
275
|
+
pools. `config.inflightPenaltyPct` remains the per-agent fallback for pools
|
|
276
|
+
without a measured rate (and for in-flight records with unknown duration).
|
|
277
|
+
- workflow: every attempt record now carries `routeWhy` (the router's reason)
|
|
278
|
+
and `routeCandidates` (each pool's effective surplus, urgency state and
|
|
279
|
+
pacing forecast at pick time); `workflow action show --json` and
|
|
280
|
+
`runs result --json` print them, and older state files still load.
|
|
281
|
+
|
|
282
|
+
- routing: a pool whose pacing window is about to reset is `draining` only
|
|
283
|
+
when its forecast is at or above 95% *and* ahead of the window's own clock,
|
|
284
|
+
the same clock-relative shape the 5h near-limit line already has. A pool on
|
|
285
|
+
or behind pace keeps spending right up to its reset instead of being ranked
|
|
286
|
+
last by a fixed line (observed 2026-09-16: command-code at 94.9% used with
|
|
287
|
+
98% of the month gone was passed over while +3 points of quota expired).
|
|
288
|
+
The skip reason now reads `expiring but draining (forecast >= 95% and past
|
|
289
|
+
its clock): <pool> <forecast>% (<elapsed>% elapsed)`.
|
|
290
|
+
- workflow goal: refuses to launch a duplicate of a run that is already going.
|
|
291
|
+
Before anything is validated or launched, an ongoing run with the same goal
|
|
292
|
+
text and cwd exits 2, naming that run's shortId, age, and watch command
|
|
293
|
+
(JSON: `{"error":"duplicate-goal",...}`); `--again` starts the copy anyway
|
|
294
|
+
(observed 2026-09-16: a caller whose JSON parser failed on the first
|
|
295
|
+
launch's output retried five seconds later and two identical workflows ran
|
|
296
|
+
side by side in the same directory).
|
|
297
|
+
|
|
3
298
|
## 0.32.0 — the dashboard is the main screen
|
|
4
299
|
|
|
5
300
|
- wording: a program run's dependency levels are called phases everywhere the
|
package/GOAL.md
CHANGED
|
@@ -35,7 +35,7 @@ A working prototype installed at `~/.bullswarm/` with:
|
|
|
35
35
|
2. **Connector registry** (`~/.bullswarm/connectors/*.json`): declarative per-CLI
|
|
36
36
|
spawn command, auth-failure signatures, output extraction, verify contract,
|
|
37
37
|
quirk fields (e.g. PWD resolution). Seeded with codex, grok,
|
|
38
|
-
command-code,
|
|
38
|
+
command-code, opencode — extracted from the proven `/offload` skill.
|
|
39
39
|
3. **Meter layer**: per-pool window definition (5h / weekly / none) with
|
|
40
40
|
programmatic readers where providers expose usage, manual declaration
|
|
41
41
|
(`--meter pool=window,pct`) where they don't. Unmetered pools pace as
|
package/README.md
CHANGED
|
@@ -55,9 +55,10 @@ as a Claude Mod (a plugin of TypeScript function hooks, behind
|
|
|
55
55
|
prompt, the pools named in the model's context, Claude's general-purpose
|
|
56
56
|
subagents routed to whichever pool has surplus and answered with the
|
|
57
57
|
verified output, and the verdict appended to every `bullswarm run` the model
|
|
58
|
-
runs. The Mod is the dashboard's read-only counterpart:
|
|
59
|
-
Usage
|
|
60
|
-
|
|
58
|
+
runs. The Mod is the dashboard's read-only counterpart: its pane shows Run,
|
|
59
|
+
Step, and the Usage/Pools view in the same meter colours. It does not expose
|
|
60
|
+
the dashboard's Home, Runs, Budget, Stats, Fleet, or Help pages, and
|
|
61
|
+
it has no edit or install action. See [mods/bullswarm/README.md](mods/bullswarm/README.md).
|
|
61
62
|
|
|
62
63
|
Three ways to load it:
|
|
63
64
|
|
|
@@ -83,12 +84,67 @@ over the skills-dir link, and Claude says so at startup.
|
|
|
83
84
|
Once setup is complete, bare `bullswarm` opens the dashboard on its Home page.
|
|
84
85
|
Use `bullswarm --setup` or `bullswarm setup` to open setup again, and use
|
|
85
86
|
`bullswarm workflow tui` when you want the explicit dashboard command. The
|
|
86
|
-
pages
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
87
|
+
eight pages answer different questions:
|
|
88
|
+
|
|
89
|
+
| Page | What it answers |
|
|
90
|
+
|---|---|
|
|
91
|
+
| Home | What happened today, what is verified, what measured or labelled money/licence data exists, and what is active or recent; includes pool/model/project breakdowns. |
|
|
92
|
+
| Runs | Which workflows are active or historical — one `active` block and the History day table below it — plus the product commands; the integration line and `/` filter live here, and `?` carries the agents and `run it` blocks. |
|
|
93
|
+
| Run | Where one workflow is in its plan, which workers are live or next, and its ETA and budget shares. |
|
|
94
|
+
| Step | What one action is doing: route, attempt, activity, verdict/failure, prompt, usage, events, output, and artifacts. |
|
|
95
|
+
| Budget | Pool quota windows, measured worker-minutes versus rest, measured or `≈` money, fit, and biggest workflows. |
|
|
96
|
+
| Stats | Runs, spend, worker-minutes, and verification over 7d/30d/all, by pool, model, and project. |
|
|
97
|
+
| Fleet | Lane/provider model and reasoning rungs, records, meter state, and the setup edit hand-off. |
|
|
98
|
+
| Help | Every key, click, layout rule, and dashboard command. |
|
|
99
|
+
|
|
100
|
+
The visual-fidelity pass keeps the same real numbers while composing and
|
|
101
|
+
colouring these pages like the approved prototype. At 55 columns every Home
|
|
102
|
+
today tile and per-step bar, every Stats model, project and its sparkline, every
|
|
103
|
+
Stats and Fleet pool row, and every run row in the Runs history table keeps one
|
|
104
|
+
row per item on the phone; Budget's per-pool block (a header over `used`,
|
|
105
|
+
`by bullswarm`, `room` and `so far`), Home's `budget · this week` pool (meter
|
|
106
|
+
plus a reset line, as the prototype draws it) and the Runs `active` entry are
|
|
107
|
+
the deliberate exceptions. At 200 columns every page composes to the frame
|
|
108
|
+
rather than capping at the 120-column composition. Estimated figures still
|
|
109
|
+
carry `≈` and their basis; a figure that cannot be measured is a line of words
|
|
110
|
+
saying so — no page draws an empty or dotted track for missing data.
|
|
111
|
+
|
|
112
|
+
Every page has a sticky header, a page tab row, and a sticky bottom nav. The
|
|
113
|
+
tab row is five tabs — Home, Runs, Budget, Stats, Fleet — with Run and Step
|
|
114
|
+
marking Runs, and Help shown only while it is open. The shared key table is:
|
|
115
|
+
|
|
116
|
+
| Key | Does |
|
|
117
|
+
|---|---|
|
|
118
|
+
| `r` | open Runs; the view refreshes itself, so `r` is no longer refresh |
|
|
119
|
+
| `b` | open Budget; it is no longer move-out |
|
|
120
|
+
| `s` | open Stats |
|
|
121
|
+
| `y` | open Runs at its History table (the first day header), except that it confirms a pending stop |
|
|
122
|
+
| `f` | open Fleet |
|
|
123
|
+
| `h` | open Home |
|
|
124
|
+
| `?` | open Help |
|
|
125
|
+
| `1`–`9` | open that run from the nav |
|
|
126
|
+
| `Tab` | cycle the current page's sub-tabs |
|
|
127
|
+
| `Shift+Tab` | cycle workflows |
|
|
128
|
+
| `p` | cycle the period on Home and Stats |
|
|
129
|
+
| `Esc` / `←` | move out one page, then Home |
|
|
130
|
+
| `↑`/`k`, `↓`/`j` | move one line |
|
|
131
|
+
| `Enter` / `→` / `l` | open the selected run, step, tab, or action |
|
|
132
|
+
| `PgUp` / `PgDn` | scroll one screen |
|
|
133
|
+
| `Home` / `End` | jump to the top or bottom |
|
|
134
|
+
| `ctrl+s` | copy the screen through OSC 52, falling back to `pbcopy`, `wl-copy`, or `xclip` |
|
|
135
|
+
| `q` | quit the dashboard; workflows keep running |
|
|
136
|
+
|
|
137
|
+
The 0.33.0 rebinding is deliberate: `r` no longer refreshes, `b` no longer
|
|
138
|
+
moves out, and `Tab` no longer cycles workflows. Esc/left moves out, the view
|
|
139
|
+
refreshes itself, and Shift+Tab still cycles workflows. Runs also provides `/`
|
|
140
|
+
(filter), `a` (active/all), and `i` (install); Run provides `o`, `v`, and `t`,
|
|
141
|
+
and Fleet provides `e` for setup. Click tabs, tiles, bars, runs, steps, dates,
|
|
142
|
+
or controls, or use the wheel to scroll.
|
|
143
|
+
|
|
144
|
+
Home, Runs, Budget, and Stats read a per-run rollup that every finishing
|
|
145
|
+
run appends to `~/.bullswarm/history/runs.jsonl`. After upgrading, backfill
|
|
146
|
+
the runs that finished before 0.33.0 once with `bullswarm workflow reindex`;
|
|
147
|
+
legacy runs get a minimal record and only runs still in flight are skipped.
|
|
92
148
|
|
|
93
149
|
One bounded outcome — a task with a clear finish line:
|
|
94
150
|
|
|
@@ -198,7 +254,7 @@ page maps its pages, keys, and mouse controls.
|
|
|
198
254
|
| [Concepts](https://bulls-work.github.io/bullswarm/guide/concepts) | Pools, lanes, surplus, the two windows, verdicts, quarantine, and the run directory |
|
|
199
255
|
| [Run one task](https://bulls-work.github.io/bullswarm/guide/run) | Every `bullswarm run` option, and what each verdict asks you to do |
|
|
200
256
|
| [Workflows](https://bulls-work.github.io/bullswarm/guide/workflows) | Authoring the program `workflow goal` executes: territories, dependencies, integration, acceptance |
|
|
201
|
-
| [Observing runs](https://bulls-work.github.io/bullswarm/guide/observing) | `workflow watch`, the Home/Run/Step/
|
|
257
|
+
| [Observing runs](https://bulls-work.github.io/bullswarm/guide/observing) | `workflow watch`, the Home/Runs/Run/Step/Budget/Stats/Fleet/Help dashboard pages, keys, mouse, and terminal glyphs |
|
|
202
258
|
| [Routing](https://bulls-work.github.io/bullswarm/guide/routing) | How a pool is picked: pace, 5-hour headroom, urgency, load, quarantine |
|
|
203
259
|
| [CLI reference](https://bulls-work.github.io/bullswarm/reference/cli) | Every verb and nested subcommand, with its flags and defaults |
|
|
204
260
|
| [Workflow program](https://bulls-work.github.io/bullswarm/reference/program) | The `bullswarm.workflow.program.v2` document: action fields, kinds, validation rules |
|