infinity-harness 2.3.0 → 2.4.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 CHANGED
@@ -4,7 +4,74 @@ All notable changes to this project are documented here.
4
4
  Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow
5
5
  [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [2.3.0] — 2026-08-24
7
+ ## [2.4.0] — 2026-08-24
8
+
9
+ Two settings that were one switch each, and one switch turned out to be the wrong shape for both
10
+ questions.
11
+
12
+ ### Added
13
+
14
+ - **A mode per phase, not a mode per run.** "copilot" and "autopilot" could not say "let it define
15
+ and plan on its own but show me the review", and that is a thing people want. Every phase now
16
+ carries its own mode: `autopilot` advances when the gate passes, `copilot` stops and waits for
17
+ your signature. The two familiar words survive as two named points in that space rather than the
18
+ only two points in it, and every phase except INIT can be a checkpoint — the three that decide
19
+ *what gets built* are the ones that usually pay for themselves, but that is a default rather than
20
+ a limit.
21
+
22
+ - **Five workflows ship, and you can build your own.** `copilot`, `autopilot`, `spec and ship`
23
+ (you sign the scope going in and the release coming out), `research first`, and `every gate`.
24
+ Building one is its own short flow: pick the phases, then say for each whether it stops for you.
25
+ Name it and it is kept — in `~/.pi/agent/infinity-harness/`, with *you* rather than with the
26
+ project, because a workflow you designed is worth as much on the next one. It is then the first
27
+ thing offered there.
28
+
29
+ Built-ins are read-only, and their names cannot be taken. "copilot" has to mean the same thing in
30
+ every conversation about this tool; someone who wants a different copilot makes their own and
31
+ gives it their own name.
32
+
33
+ - **`/infinity:workflow`** — choose one, build one, switch by name (`/infinity:workflow
34
+ spec-and-ship`), or `list` what is available and what you are on. `/infinity:config` →
35
+ **Workflow** edits one phase at a time. All of it changes at any time and takes effect at the next
36
+ gate: three phases into a run is exactly when someone realises they do want to see the review.
37
+
38
+ - **Display templates.** Shipping all five plan levels to everyone was the wrong answer for the same
39
+ reason shipping two was: one person works in sprints and never opens a subtask, the next has no
40
+ sprints and lives in the subtask list. Four ship — `focus`, `everything`, `overview` (the shape,
41
+ no tasks), `worklist` (tasks only, no rail) — and anything else is chosen level by level: the
42
+ five plan levels, the `done/total` counts, the `← #3` dependency labels, the acceptance criteria,
43
+ the phase rail, the progress meter, the alert strip, and how many rows the terminal shows before
44
+ it scrolls. Name what you end up with and it is saved with you like a workflow.
45
+
46
+ - **`/infinity:display`** — pick a template, choose level by level, switch by name, or `list`.
47
+ `/infinity:config` → **Display** edits the same things one at a time.
48
+
49
+ - **The widget and the dashboard read the same setting.** Configure how you like to read a plan
50
+ once, not twice.
51
+
52
+ ### Changed
53
+
54
+ - `harness/config.json` gains `phaseModes`, `workflow` and `display`. A 2.3 config is migrated on
55
+ read: its three-phase `approvals` becomes the equivalent modes and is labelled with the workflow
56
+ it amounts to, so a project mid-run keeps exactly the approvals it was configured with and nobody
57
+ has to edit JSON to upgrade. The legacy field is kept in step on write.
58
+ - Hiding a plan level hides the row, never the work beneath it: turn off sprints on a plan organised
59
+ into sprints and the features move up one indent rather than vanishing, and task numbers do not
60
+ shift, so `← #3` still points at the same task. A task nobody can see is a task that gets stuck
61
+ forever.
62
+
63
+ ### Fixed
64
+
65
+ - **`initHarness` ignored a caller that passed the old `approvals` shape** once `phaseModes`
66
+ existed, silently producing an autopilot run. It falls back to `approvals` when no modes are
67
+ given — the same rule `loadConfig` applies to an older file.
68
+
69
+ ---
70
+
71
+ ## [2.3.1] — 2026-08-24
72
+
73
+ *(2.3.0 was staged at the registry and never completed; 2.3.1 is that release plus the last two
74
+ fixes below, and is the first version of this work anyone can install.)*
8
75
 
9
76
  Five bugs were reported against 2.1.0 by someone actually using the thing. Every one of them was
10
77
  real, none of them could be seen by a test that mocks pi, and finding out why led to the change
@@ -106,6 +173,23 @@ that matters most in this release: **the suite now drives a real `pi` process.**
106
173
 
107
174
  - **The phase picker did not offer RESEARCH** — a feature nobody could find.
108
175
 
176
+ - **A handoff in a one-shot `pi -p` run replaced the session out from under the instance that
177
+ asked for it**, so every handler afterwards touched a torn-down context and pi reported
178
+ "This extension ctx is stale after session replacement" on every turn. A headless run has no
179
+ next turn to hand anything to, so it does not hand off — and the extension now stops touching
180
+ pi the moment its session is shut down, whatever the reason.
181
+
182
+ - **A new phase counted as a stall.** The first failure of a phase was compared against the
183
+ fingerprint taken when the *previous* phase passed — identical, because nothing had happened
184
+ yet — so the run spent `retry` and `reframe` on the opening turn of every single phase, and
185
+ arrived at the rungs that matter with the cheap ones already gone. A stall is the agent
186
+ producing nothing when asked; a fresh brief has not asked yet.
187
+
188
+ - **The gate history counted every pass twice.** `runChecks` recorded the verdict and
189
+ `transitionPhase` recorded it again, so the history read `define:pass → define:pass`, which says
190
+ a phase had to be attempted twice — the opposite of what happened. Repeated *failures* are still
191
+ every one of them: that is the fact a human comes back to read.
192
+
109
193
  ### Changed
110
194
 
111
195
  - The dashboard shows every subtask, not only the active task's. The widget has nine rows and a job
package/README.md CHANGED
@@ -100,11 +100,10 @@ It detects your stack and its lint/test/build commands, then asks you five quest
100
100
 
101
101
  | | |
102
102
  |---|---|
103
- | **How involved do you want to be?** | copilot you approve the definition and the plan · autopilot you choose what to approve, if anything |
104
- | **What are you building?** | One or two sentences. Asked in *both* modes, because a run with no goal has no business inventing one. |
105
- | **Research it first?** | Adds an optional RESEARCH phase before DEFINE: prior art, constraints, options with costs, a recommendation, and the questions only you can answer. |
106
- | **Which phases do you sign?** *(autopilot only)* | RESEARCH, DEFINE, PLAN — tick any, all or none. None is the walk-away setting. |
103
+ | **Which workflow?** | A built-in, one you saved, or *build one* pick the phases, then say for each whether it stops for you |
104
+ | **What are you building?** | One or two sentences. Asked whatever the workflow, because a run with no goal has no business inventing one. |
107
105
  | **When should it start a fresh session?** | Every phase (default) · every task · never |
106
+ | **How much of the plan on screen?** | A display template — `focus`, `everything`, `overview`, `worklist`, or level by level |
108
107
 
109
108
  Then it writes `harness/` — the config, an empty plan, the phase and role docs, and starters
110
109
  for the documents the review gate will demand — and hands the model its first brief. It never
@@ -134,14 +133,45 @@ the craft skills that match the work, and what to do next. Do the work, then:
134
133
 
135
134
  ## Who decides what
136
135
 
137
- The two words are about **who signs off**, not about how autonomous the agent is. Both modes
138
- run the same pipeline, the same gates and the same loop.
136
+ "copilot" and "autopilot" used to be one switch, and one switch is the wrong shape for the
137
+ question. What people actually want is per-phase: let the model define and plan on its own but
138
+ show me the review; or grill me on the definition and then leave me alone until it ships. Two
139
+ words cannot say that.
139
140
 
140
- | | copilot | autopilot |
141
- |---|---|---|
142
- | RESEARCH, DEFINE, PLAN | you approve each one | you pick which, if any |
143
- | Everything after PLAN | the gate decides | the gate decides |
144
- | When it is right | you care what gets built | you have said what you want and you are leaving |
141
+ So the setting is a **mode per phase**, and the two familiar words are two named points in that
142
+ space rather than the only two points in it.
143
+
144
+ | Mode | When a phase's gate passes |
145
+ |---|---|
146
+ | `autopilot` | it advances |
147
+ | `copilot` | it stops and waits for your signature |
148
+
149
+ Five workflows ship with the package, and none of them can be edited — `copilot` has to mean the
150
+ same thing in every conversation about this tool:
151
+
152
+ | Workflow | Stops at |
153
+ |---|---|
154
+ | **copilot** | DEFINE, PLAN |
155
+ | **autopilot** | nothing |
156
+ | **spec and ship** | DEFINE, SHIP — you sign the scope going in and the release coming out |
157
+ | **research first** | adds a RESEARCH phase, and stops on all three thinking phases |
158
+ | **every gate** | every phase. Slowest, and the one you want on something that matters |
159
+
160
+ Anything else you build yourself: pick the phases, then say for each whether it stops for you. Give
161
+ it a name and it is saved with *you*, not with the project, so it is the first thing offered on your
162
+ next one.
163
+
164
+ ```
165
+ /infinity:workflow choose one, or build one
166
+ /infinity:workflow spec-and-ship switch to a named one, no menu
167
+ /infinity:workflow list what is available, and what you are on now
168
+ ```
169
+
170
+ Any of it changes at any time and takes effect at the next gate — three phases into a run is
171
+ exactly when someone realises they do want to see the review after all. `/infinity:config` →
172
+ **Workflow** edits one phase at a time.
173
+
174
+ ### Signing a phase
145
175
 
146
176
  When a phase you signed up for passes its gate, the run **stops and asks you** rather than
147
177
  advancing. Approving continues it; answering with a sentence sends the phase back carrying your
@@ -152,9 +182,9 @@ words, so it is redone against your objection rather than redone identically:
152
182
  /infinity:approve the criteria say nothing about refunds
153
183
  ```
154
184
 
155
- A rejection is pinned to the state of the project when you made it, so the run will not ask you
156
- the same question again until the agent has actually changed something in response. If it never
157
- does, the run stops and says so instead of nagging forever.
185
+ A rejection is pinned to the state of the project when you made it, so the run will not ask you the
186
+ same question again until the agent has actually changed something in response. If it never does,
187
+ the run stops and says so instead of nagging forever.
158
188
 
159
189
  ## One run, many sessions
160
190
 
@@ -224,7 +254,8 @@ valid; the menu is the same data with prompts and bounds checking attached.
224
254
  |---|---|
225
255
  | **Models** | Which model runs each difficulty tier, the master model, consultation budget |
226
256
  | **Pipeline** | Which phases run, copilot vs autopilot, role strictness, pause |
227
- | **Your approvals** | Which of RESEARCH / DEFINE / PLAN stop and wait for your signature |
257
+ | **Workflow** | The mode for each phase which of them stop and wait for your signature |
258
+ | **Display** | Which plan levels and which chrome the widget and the dashboard draw |
228
259
  | **Sessions** | Fresh session per phase or per task, the context threshold, the carry note |
229
260
  | **Project commands** | lint / test / coverage / build — what the gate actually runs |
230
261
  | **Gates** | Enable, coverage threshold, placeholder rejection |
@@ -349,7 +380,7 @@ The agent edits it by submitting the **complete** task list through the `infinit
349
380
 
350
381
  ## Watching it work
351
382
 
352
- **In the terminal** — the widget above updates on every turn, showing all five levels of the plan:
383
+ **In the terminal** — the widget updates on every turn, showing the plan as deep as you asked for:
353
384
  goal, sprint, feature, task, subtask. It is a *window*, not a truncation — the rows above and
354
385
  below are counted, and one keypress away:
355
386
 
@@ -362,14 +393,43 @@ below are counted, and one keypress away:
362
393
  It is responsive down to ~58 columns, degrades to ASCII when the locale isn't UTF-8, and drops
363
394
  colour under `NO_COLOR`.
364
395
 
365
- **In a browser** — `/infinity:dashboard` serves a live page on loopback: phase rail, stacked progress
366
- meters that show stuck work as colour rather than absence, the whole plan as a collapsible
367
- goal → sprint → feature → task → subtask tree with counts at every level, and the last gate
368
- verdict. It refreshes itself every 5 seconds and reconnects with backoff if the run ends.
396
+ **In a browser** — `/infinity:dashboard` serves a live page on loopback: phase rail, stacked
397
+ progress meters that show stuck work as colour rather than absence, the plan as a collapsible tree
398
+ with counts at every level, and the last gate verdict. It refreshes itself every 5 seconds and
399
+ reconnects with backoff if the run ends.
369
400
 
370
401
  The dashboard is strictly read-only and binds to `127.0.0.1`. It never writes, and never bumps
371
402
  `baseRevision` — opening it can't perturb the run you're watching.
372
403
 
404
+ ### What they show is yours to choose
405
+
406
+ Two people watching the same run want different things on screen. One works in sprints and never
407
+ opens a subtask; the next has no sprints and lives in the subtask list. So it is a setting, and
408
+ **the widget and the dashboard read the same one** — configure how you like to read a plan once,
409
+ not twice.
410
+
411
+ | Template | |
412
+ |---|---|
413
+ | **focus** *(default)* | every level, with subtasks on the task being worked |
414
+ | **everything** | all five levels, every subtask on every task, a taller window |
415
+ | **overview** | goals, sprints and features with their counts. No tasks — the shape, not the work |
416
+ | **worklist** | tasks only. No grouping rows, no rail — for when you already know the plan |
417
+
418
+ ```
419
+ /infinity:display pick a template, or choose level by level
420
+ /infinity:display overview switch straight to one
421
+ /infinity:display list what is available, and what you are on now
422
+ ```
423
+
424
+ Choosing level by level also lets you turn off the phase rail, the progress meter, the alert strip,
425
+ the `done/total` counts, the `← #3` dependency labels and the acceptance criteria, and set how many
426
+ rows the terminal shows before it scrolls. Name what you end up with and it is saved with you,
427
+ offered on your next project. `/infinity:config` → **Display** edits the same things one at a time.
428
+
429
+ Hiding a level never hides what is under it: turn off sprints on a plan organised into sprints and
430
+ the features move up one indent, they do not vanish. A task nobody can see is a task that gets
431
+ stuck forever.
432
+
373
433
  ## Craft skills
374
434
 
375
435
  28 short documents on how to do the work well — how to write a test worth
@@ -447,10 +507,12 @@ infinity-harness/
447
507
  │ │ · featureList (the SSOT) · lock · exec
448
508
  │ │ · skills (match) · skillsAudit (guard)
449
509
  │ ├── ui/ theme · planTree (the five levels, once)
510
+ │ │ · display (what to draw, and the templates)
450
511
  │ │ · widget (terminal) · dashboard (web) · wizard · config
451
512
  │ ├── loop.ts the continuous-run driver and its stop conditions
452
513
  │ ├── runState.ts is a run armed, and which run is it — on disk, across sessions
453
514
  │ ├── handoff.ts when to continue in a fresh session, and what to tell it
515
+ │ ├── workflow.ts a mode per phase, the built-ins, and the ones you save
454
516
  │ ├── approval.ts · intake.ts human sign-off · what the start-up wizard's answers mean
455
517
  │ ├── escalate.ts the ladder's actuator: chooses a rung and takes it
456
518
  │ ├── goal.ts the outer loop: is the thing asked for actually done?
@@ -467,7 +529,10 @@ infinity-harness/
467
529
  │ ├── model-router.json optional routing
468
530
  │ ├── docs/ architecture · decisions · phase and role docs
469
531
  │ └── skills/ 28 craft skills the brief points at
470
- ├── tests/ 31 files, plain node:assert
532
+
533
+ │ ~/.pi/agent/infinity-harness/ the workflows and display templates you saved —
534
+ │ they belong to you, not to a project
535
+ ├── tests/ 33 files, plain node:assert
471
536
  └── scripts/
472
537
  ├── run-tests.mjs
473
538
  ├── e2e.mjs 16 scenarios, including one against a real pi process
@@ -482,7 +547,7 @@ there is one implementation, and the adapter calls it.
482
547
  ```bash
483
548
  npm install
484
549
  npm run check # tsc --noEmit, strict
485
- npm test # 31 test files
550
+ npm test # 33 test files
486
551
  npm run e2e # 16 end-to-end scenarios
487
552
  npm run e2e -- --only realpi # just the ones that drive a real pi process
488
553
  npm run e2e -- --list # what the scenarios are