infinity-harness 2.2.1 → 2.3.1
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 +134 -0
- package/README.md +153 -29
- package/extensions/infinity-harness/index.ts +770 -51
- package/harness/docs/agents/researcher.md +14 -0
- package/harness/docs/phases/research.md +64 -0
- package/harness/skills/grilling.md +1 -1
- package/harness/skills/research.md +1 -1
- package/package.json +1 -1
- package/src/approval.ts +194 -0
- package/src/core/brief.ts +51 -2
- package/src/core/config.ts +32 -13
- package/src/core/fsx.ts +10 -0
- package/src/core/gates.ts +15 -0
- package/src/core/init.ts +43 -2
- package/src/core/paths.ts +14 -0
- package/src/core/settings.ts +56 -0
- package/src/core/types.ts +65 -2
- package/src/handoff.ts +197 -0
- package/src/intake.ts +263 -0
- package/src/loop.ts +88 -10
- package/src/remote.ts +22 -1
- package/src/runState.ts +121 -0
- package/src/ui/dashboard.ts +140 -16
- package/src/ui/planTree.ts +287 -0
- package/src/ui/theme.ts +15 -0
- package/src/ui/widget.ts +230 -67
- package/src/ui/wizard.ts +195 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,140 @@ 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.1] — 2026-08-24
|
|
8
|
+
|
|
9
|
+
*(2.3.0 was staged at the registry and never completed; 2.3.1 is that release plus the last two
|
|
10
|
+
fixes below, and is the first version of this work anyone can install.)*
|
|
11
|
+
|
|
12
|
+
Five bugs were reported against 2.1.0 by someone actually using the thing. Every one of them was
|
|
13
|
+
real, none of them could be seen by a test that mocks pi, and finding out why led to the change
|
|
14
|
+
that matters most in this release: **the suite now drives a real `pi` process.**
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **A fresh pi session per boundary.** A harness that never starts a new session is a harness whose
|
|
19
|
+
context window only ever grows: by the tenth task the model is re-reading the history of the
|
|
20
|
+
first nine in order to do the tenth. It pays for those tokens on every call, compacts them into a
|
|
21
|
+
lossy summary once the window fills, and on a small model simply drowns.
|
|
22
|
+
|
|
23
|
+
Nothing the harness knows was ever in the conversation — the plan, the phase, the gate history,
|
|
24
|
+
the retry budgets and the escalation ladder are all files. So a session boundary costs one thing:
|
|
25
|
+
the brief, which is what the agent should have been working from anyway. `session.handoff` is
|
|
26
|
+
`phase` by default, `task` for the cleanest possible context, `off` for the old behaviour; any of
|
|
27
|
+
them also hands off early once the context passes `session.contextThreshold`, because a handoff
|
|
28
|
+
that arrives after compaction has arrived too late to be the thing that prevented it.
|
|
29
|
+
|
|
30
|
+
- **A run that outlives its sessions.** `harness/run.json` holds whether a run is armed, its id, and
|
|
31
|
+
how many sessions it has spent. `/reload`, `/resume`, closing the terminal, and every handoff now
|
|
32
|
+
resume the same run instead of quietly starting a new one with fresh budgets.
|
|
33
|
+
|
|
34
|
+
- **A start-up wizard that asks what is being built.** Choosing "autopilot" used to start the run
|
|
35
|
+
immediately, with no idea and no scope, so the first thing the harness did was invent a project
|
|
36
|
+
and start building it. Autopilot was being read as "you decide everything, including what I
|
|
37
|
+
want". Two questions were tangled together and are now separate: *what are we building* (asked in
|
|
38
|
+
both modes) and *who signs off on what* (the mode's actual meaning).
|
|
39
|
+
|
|
40
|
+
- **Approval gates on RESEARCH, DEFINE and PLAN.** The gate is a good referee for execution and a
|
|
41
|
+
poor one for intent: it can prove a feature has acceptance criteria and cannot prove they are the
|
|
42
|
+
right ones. In copilot all three are yours. In autopilot you tick the ones you want and forfeit
|
|
43
|
+
the rest — forfeiting all three is the walk-away setting. `/infinity:approve` continues;
|
|
44
|
+
`/infinity:approve <what is wrong>` sends the phase back carrying your words. A rejection is
|
|
45
|
+
pinned to the state of the project when you made it, so you are not asked the same question again
|
|
46
|
+
until the agent has actually changed something.
|
|
47
|
+
|
|
48
|
+
- **An optional RESEARCH phase**, before DEFINE, with its own role, gate and phase doc. The human
|
|
49
|
+
gives an idea; the model comes back with prior art, the constraints that are real, at least two
|
|
50
|
+
options with what each costs, a recommendation, what would falsify it, and the questions only a
|
|
51
|
+
human can answer — which become the DEFINE interview.
|
|
52
|
+
|
|
53
|
+
- **All five plan levels on screen.** Goal → sprint → feature → task → subtask. Only two of them
|
|
54
|
+
used to reach the human: the widget drew features and tasks, goals were a single title line, and
|
|
55
|
+
sprints appeared *nowhere*, so a plan organised into sprints looked exactly like a plan that was
|
|
56
|
+
not. `src/ui/planTree.ts` is one shared model of the plan's shape; the widget windows it and the
|
|
57
|
+
dashboard renders all of it as collapsible tiers with counts at every level. A feature pointing
|
|
58
|
+
at a goal that has since been deleted is still drawn — a task nobody can see is a task that gets
|
|
59
|
+
stuck forever.
|
|
60
|
+
|
|
61
|
+
- **A scrollable plan widget.** Nine rows of a sixty-row plan read as a truncation, because the
|
|
62
|
+
other fifty-one were unreachable without opening the dashboard. It is a window now: `alt+j` /
|
|
63
|
+
`alt+k` scroll, `alt+o` expands, and `/infinity:scroll up|down|top|bottom|expand|collapse|follow`
|
|
64
|
+
does the same without a keyboard. (`alt+`, not `ctrl+`: pi already binds ctrl+j, ctrl+k and
|
|
65
|
+
ctrl+o in its editor, and a widget is not worth shadowing an editor key for.)
|
|
66
|
+
|
|
67
|
+
- **`scripts/rig/` — the suite drives a real pi.** A scripted OpenAI-compatible model server plus an
|
|
68
|
+
RPC client that types prompts and slash commands, answers `ctx.ui.select` dialogs, and reads back
|
|
69
|
+
the widget, the status line and the notifications a human would actually see. The new `realpi`
|
|
70
|
+
e2e scenario covers startup, the wizard, a run spanning several real sessions, real
|
|
71
|
+
auto-compaction, an approval round-trip, and `pi -p` not hanging.
|
|
72
|
+
|
|
73
|
+
- Three commands: `/infinity:approve`, `/infinity:handoff`, `/infinity:scroll`. Two settings groups:
|
|
74
|
+
**Your approvals** and **Sessions**.
|
|
75
|
+
|
|
76
|
+
### Fixed
|
|
77
|
+
|
|
78
|
+
- **The harness did not survive compaction.** Its rules lived in the transcript, and a transcript is
|
|
79
|
+
what compaction summarises: the agent came out the other side still holding the plan (it is on
|
|
80
|
+
disk) but no longer knowing it was supposed to work from it, stop at a failing gate, or never
|
|
81
|
+
mark its own work complete. Those rules now go in the **system prompt**, via
|
|
82
|
+
`before_agent_start`, which is rebuilt every turn and is never summarised. The post-compaction
|
|
83
|
+
re-brief is also delivered as `steer` rather than `nextTurn` when a turn is running — `nextTurn`
|
|
84
|
+
waits for a human to type, which in an unattended run never happens, so the message that was
|
|
85
|
+
supposed to rescue the agent sat in a queue while it carried on without it.
|
|
86
|
+
|
|
87
|
+
- **The loop did not survive its own handoff.** "Is a run armed?" was a `let` inside the extension
|
|
88
|
+
closure, so it died with the pi session that held it. Worse, the run id was a `randomUUID()` per
|
|
89
|
+
session: every new session looked like a brand-new run to `loadLoopState`, resetting the iteration
|
|
90
|
+
ceiling, the wall-clock budget, the no-progress streak and the escalation ladder — every guard
|
|
91
|
+
that makes walking away safe, reset by the mechanism that makes walking away possible.
|
|
92
|
+
|
|
93
|
+
- **`pi -p` hung forever on a harness project.** The session-start brief was queued with
|
|
94
|
+
`deliverAs: "nextTurn"`, which waits for a user prompt. Print mode never has one. Every headless
|
|
95
|
+
run hung at startup and nothing in the suite could see it, because nothing in the suite ran pi.
|
|
96
|
+
|
|
97
|
+
- **A second, hand-written copy of `PHASE_ROLE`** in `core/config.ts`. Adding a phase compiled
|
|
98
|
+
cleanly and then silently reported the wrong role for it.
|
|
99
|
+
|
|
100
|
+
- **A rejected approval could spin forever.** The first version of the fix returned early from the
|
|
101
|
+
loop when a rejection was still outstanding, which skipped the no-progress detector — an unbounded
|
|
102
|
+
loop, the one thing this product exists to prevent. It falls through the normal failure path now,
|
|
103
|
+
so strikes, budgets and the escalation ladder all apply, and a run whose agent ignores a rejection
|
|
104
|
+
stops and says exactly that.
|
|
105
|
+
|
|
106
|
+
- **Commands that dead-ended before init.** `/infinity:next` printed a full page of pipeline
|
|
107
|
+
instructions for a pipeline that did not exist; `/infinity:scroll` said nothing at all. All
|
|
108
|
+
fifteen commands that need a harness now say so and name `/infinity:init`.
|
|
109
|
+
|
|
110
|
+
- **The phase picker did not offer RESEARCH** — a feature nobody could find.
|
|
111
|
+
|
|
112
|
+
- **A handoff in a one-shot `pi -p` run replaced the session out from under the instance that
|
|
113
|
+
asked for it**, so every handler afterwards touched a torn-down context and pi reported
|
|
114
|
+
"This extension ctx is stale after session replacement" on every turn. A headless run has no
|
|
115
|
+
next turn to hand anything to, so it does not hand off — and the extension now stops touching
|
|
116
|
+
pi the moment its session is shut down, whatever the reason.
|
|
117
|
+
|
|
118
|
+
- **A new phase counted as a stall.** The first failure of a phase was compared against the
|
|
119
|
+
fingerprint taken when the *previous* phase passed — identical, because nothing had happened
|
|
120
|
+
yet — so the run spent `retry` and `reframe` on the opening turn of every single phase, and
|
|
121
|
+
arrived at the rungs that matter with the cheap ones already gone. A stall is the agent
|
|
122
|
+
producing nothing when asked; a fresh brief has not asked yet.
|
|
123
|
+
|
|
124
|
+
- **The gate history counted every pass twice.** `runChecks` recorded the verdict and
|
|
125
|
+
`transitionPhase` recorded it again, so the history read `define:pass → define:pass`, which says
|
|
126
|
+
a phase had to be attempted twice — the opposite of what happened. Repeated *failures* are still
|
|
127
|
+
every one of them: that is the fact a human comes back to read.
|
|
128
|
+
|
|
129
|
+
### Changed
|
|
130
|
+
|
|
131
|
+
- The dashboard shows every subtask, not only the active task's. The widget has nine rows and a job
|
|
132
|
+
to do with them; the browser has a whole page and a scrollbar, and hiding four of the five plan
|
|
133
|
+
levels there made it a worse copy of the widget rather than the place you go for the full picture.
|
|
134
|
+
- The widget carries `session N` once a run has spanned more than one, and says loudly when a phase
|
|
135
|
+
is waiting for your signature — a run parked on a human otherwise looks identical to a run that
|
|
136
|
+
quietly died.
|
|
137
|
+
- `describeInit` no longer tells you to describe what you are building. The wizard just asked.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
7
141
|
## [2.2.1] — 2026-08-23
|
|
8
142
|
|
|
9
143
|
### Fixed
|
package/README.md
CHANGED
|
@@ -9,26 +9,31 @@ stops with a clear reason when it genuinely needs you.
|
|
|
9
9
|
```
|
|
10
10
|
╭──────────────────────────────────────────────────────────────────────────╮
|
|
11
11
|
│ ∞ INFINITY ──────────────────────────────────────────────── BUILD rev 42 │
|
|
12
|
-
│
|
|
12
|
+
│ ◈ Ship the payments rewrite behind a flag │
|
|
13
13
|
│ │
|
|
14
14
|
│ ● define ─ ● plan ─ ◉ BUILD ─ ○ verify ─ ○ review ─ ○ ship │
|
|
15
15
|
│ │
|
|
16
16
|
│ ▰▰▰▰▰▰▰▰▰▰▰▱▱▱▱▱▱▱▱▱▱▱▱▱ 45% 5/11 tasks · 1/2 features │
|
|
17
|
-
│ ⚠ 1 blocked · ↷ 1 rework · retry 2/10
|
|
17
|
+
│ ⚠ 1 blocked · ↷ 1 rework · retry 2/10 · session 7 │
|
|
18
18
|
│ │
|
|
19
|
-
│
|
|
20
|
-
│
|
|
21
|
-
│
|
|
22
|
-
│
|
|
23
|
-
│
|
|
24
|
-
│
|
|
25
|
-
│
|
|
26
|
-
│
|
|
27
|
-
│
|
|
28
|
-
│
|
|
19
|
+
│ ▤ Checkout 5/11 │
|
|
20
|
+
│ ▸ feature-002 · Checkout flow 2/5 │
|
|
21
|
+
│ ● 4 validate cart totals against catalogue prices │
|
|
22
|
+
│ ● 5 apply stacked discount codes with precedence rules ← #4 │
|
|
23
|
+
│ ◐ 6 handle partial refunds across split tenders ← #4, #5 │
|
|
24
|
+
│ ✓ unit tests for tender split │
|
|
25
|
+
│ ▸ integration test against sandbox │
|
|
26
|
+
│ · audit log entries │
|
|
27
|
+
│ ○ 7 emit refund webhook ← #6 │
|
|
28
|
+
│ ⚠ 8 reconcile ledger nightly ← #6 │
|
|
29
|
+
│ ⋯ 3 below alt+j/k scroll · alt+o expand │
|
|
29
30
|
╰──────────────────────────────────────────────────────────────────────────╯
|
|
30
31
|
```
|
|
31
32
|
|
|
33
|
+
All five levels of the plan — goal, sprint, feature, task, subtask — with the window
|
|
34
|
+
centred on the work. `alt+j` / `alt+k` scroll it, `alt+o` expands it, and
|
|
35
|
+
`/infinity:dashboard` shows the whole thing in a browser.
|
|
36
|
+
|
|
32
37
|
---
|
|
33
38
|
|
|
34
39
|
## Why it exists
|
|
@@ -37,15 +42,23 @@ Left alone, a coding agent drifts. It declares work finished that isn't, forgets
|
|
|
37
42
|
did, re-solves the same problem three different ways, and — worst of all — keeps going long after it
|
|
38
43
|
stopped making progress. Pair it with a small or cheap model and all of that gets worse.
|
|
39
44
|
|
|
40
|
-
infinity-harness fixes that by taking
|
|
45
|
+
infinity-harness fixes that by taking three decisions away from the model:
|
|
41
46
|
|
|
42
47
|
1. **When work is done.** A deterministic gate decides, not the agent. Same tree, same verdict, every
|
|
43
48
|
time. No agent marks its own homework.
|
|
44
49
|
2. **What happens next.** The phase pipeline is forward-only and one step at a time. The agent cannot
|
|
45
50
|
decide it's bored of BUILD and jump to SHIP.
|
|
51
|
+
3. **What to remember.** The plan, the phase and every budget live in files, so the run starts a
|
|
52
|
+
**fresh pi session at each boundary** instead of dragging the whole history of the run into every
|
|
53
|
+
request. Small models stop drowning; long runs stop turning into summaries of summaries.
|
|
54
|
+
|
|
55
|
+
Everything else — the retries, the model routing, the escalation ladder — exists to keep those
|
|
56
|
+
decisions honest over a very long run.
|
|
46
57
|
|
|
47
|
-
|
|
48
|
-
|
|
58
|
+
And one decision stays yours: **what gets built**. The gate can prove a feature has acceptance
|
|
59
|
+
criteria; it cannot prove they are the right ones. So the run stops and asks you to sign off
|
|
60
|
+
RESEARCH, DEFINE and PLAN — always in copilot, and in autopilot for whichever of them you choose to
|
|
61
|
+
keep.
|
|
49
62
|
|
|
50
63
|
## Install
|
|
51
64
|
|
|
@@ -83,9 +96,18 @@ Then, once, in that project:
|
|
|
83
96
|
/infinity:init
|
|
84
97
|
```
|
|
85
98
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
99
|
+
It detects your stack and its lint/test/build commands, then asks you five questions:
|
|
100
|
+
|
|
101
|
+
| | |
|
|
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. |
|
|
107
|
+
| **When should it start a fresh session?** | Every phase (default) · every task · never |
|
|
108
|
+
|
|
109
|
+
Then it writes `harness/` — the config, an empty plan, the phase and role docs, and starters
|
|
110
|
+
for the documents the review gate will demand — and hands the model its first brief. It never
|
|
89
111
|
overwrites a file that already exists, and `/infinity:init force` restores anything you
|
|
90
112
|
deleted without touching what you wrote.
|
|
91
113
|
|
|
@@ -95,7 +117,10 @@ the craft skills that match the work, and what to do next. Do the work, then:
|
|
|
95
117
|
```
|
|
96
118
|
/infinity:validate run the gate for this phase
|
|
97
119
|
/infinity:run hand it the wheel: validate → advance → re-brief, until done or stuck
|
|
120
|
+
/infinity:approve sign off the phase waiting for you — or send it back with a note
|
|
98
121
|
/infinity:status where the run is right now
|
|
122
|
+
/infinity:scroll move the plan widget: up · down · top · bottom · expand · follow
|
|
123
|
+
/infinity:handoff continue this run in a fresh session, by hand
|
|
99
124
|
/infinity:config change any setting, including which model runs which tier
|
|
100
125
|
/infinity:models what models pi has, and how they are being routed
|
|
101
126
|
/infinity:dashboard open the live web view
|
|
@@ -107,6 +132,61 @@ the craft skills that match the work, and what to do next. Do the work, then:
|
|
|
107
132
|
|
|
108
133
|
`/infinity:run` is the point of the tool. It keeps the loop turning without you.
|
|
109
134
|
|
|
135
|
+
## Who decides what
|
|
136
|
+
|
|
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.
|
|
139
|
+
|
|
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 |
|
|
145
|
+
|
|
146
|
+
When a phase you signed up for passes its gate, the run **stops and asks you** rather than
|
|
147
|
+
advancing. Approving continues it; answering with a sentence sends the phase back carrying your
|
|
148
|
+
words, so it is redone against your objection rather than redone identically:
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
/infinity:approve
|
|
152
|
+
/infinity:approve the criteria say nothing about refunds
|
|
153
|
+
```
|
|
154
|
+
|
|
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.
|
|
158
|
+
|
|
159
|
+
## One run, many sessions
|
|
160
|
+
|
|
161
|
+
A harness that never starts a new pi session is a harness whose context window only ever grows.
|
|
162
|
+
By the tenth task the model is re-reading the history of the first nine in order to do the
|
|
163
|
+
tenth — paying for those tokens on every call, compacting them into a lossy summary once the
|
|
164
|
+
window fills, and, on a small model, simply drowning.
|
|
165
|
+
|
|
166
|
+
Nothing the harness knows lives in the conversation. The plan, the phase, the gate history, the
|
|
167
|
+
retry budgets and the escalation ladder are all files under `harness/`, so a session boundary
|
|
168
|
+
costs one thing: the brief — which is what the agent should have been working from anyway.
|
|
169
|
+
|
|
170
|
+
So the run hands itself to a fresh session at each boundary, and the replacement picks up
|
|
171
|
+
exactly where the last one stopped:
|
|
172
|
+
|
|
173
|
+
| Setting | Fresh session when |
|
|
174
|
+
|---|---|
|
|
175
|
+
| `phase` *(default)* | the pipeline advances a phase, or a goal pass finishes |
|
|
176
|
+
| `task` | that, plus every time the run moves to a different task |
|
|
177
|
+
| `off` | never — one session for the whole run |
|
|
178
|
+
|
|
179
|
+
Any of them also hands off early once the context passes `session.contextThreshold` (0.7 by
|
|
180
|
+
default), because a handoff that arrives after compaction has arrived too late to be the thing
|
|
181
|
+
that prevented it.
|
|
182
|
+
|
|
183
|
+
The run itself — its id, its wall-clock budget, its iteration ceiling, its no-progress strikes
|
|
184
|
+
and its position on the escalation ladder — lives in `harness/run.json` and is the same run
|
|
185
|
+
across every session it spans. `/reload`, `/resume`, closing the terminal and reopening it all
|
|
186
|
+
resume the same run rather than quietly starting a new one with fresh budgets.
|
|
187
|
+
|
|
188
|
+
The widget shows `session 7` once a run has spanned more than one.
|
|
189
|
+
|
|
110
190
|
### The first pass through
|
|
111
191
|
|
|
112
192
|
DEFINE wants acceptance criteria on every feature, so start by telling it what you are building.
|
|
@@ -144,6 +224,8 @@ valid; the menu is the same data with prompts and bounds checking attached.
|
|
|
144
224
|
|---|---|
|
|
145
225
|
| **Models** | Which model runs each difficulty tier, the master model, consultation budget |
|
|
146
226
|
| **Pipeline** | Which phases run, copilot vs autopilot, role strictness, pause |
|
|
227
|
+
| **Your approvals** | Which of RESEARCH / DEFINE / PLAN stop and wait for your signature |
|
|
228
|
+
| **Sessions** | Fresh session per phase or per task, the context threshold, the carry note |
|
|
147
229
|
| **Project commands** | lint / test / coverage / build — what the gate actually runs |
|
|
148
230
|
| **Gates** | Enable, coverage threshold, placeholder rejection |
|
|
149
231
|
| **Continuous run** | Iteration ceiling, wall-clock budget, no-progress strikes |
|
|
@@ -152,11 +234,12 @@ valid; the menu is the same data with prompts and bounds checking attached.
|
|
|
152
234
|
## The pipeline
|
|
153
235
|
|
|
154
236
|
```
|
|
155
|
-
define → plan → build → verify → [simplify] → review → ship
|
|
237
|
+
[research] → define → plan → build → verify → [simplify] → review → ship
|
|
156
238
|
```
|
|
157
239
|
|
|
158
240
|
| Phase | What it's for | Gate opens when |
|
|
159
241
|
|---|---|---|
|
|
242
|
+
| **research** | Find out what it actually has to be *(opt-in)* | `harness/docs/RESEARCH.md` says something a human could argue with |
|
|
160
243
|
| **define** | Write down what's being built and how you'll know it's done | Every feature has acceptance criteria |
|
|
161
244
|
| **plan** | Break features into ordered, dependency-aware tasks | Tasks exist and criteria are set |
|
|
162
245
|
| **build** | Implement, one task at a time, tests alongside | Lint, tests, coverage pass; no placeholders; every task complete |
|
|
@@ -165,7 +248,14 @@ define → plan → build → verify → [simplify] → review → ship
|
|
|
165
248
|
| **review** | Judge it as if someone else wrote it | Rubric, README, architecture doc and decisions are real; branch level with upstream |
|
|
166
249
|
| **ship** | Tag, changelog, leave it clean | Clean tree, tagged, changelog, README, licence, no placeholders |
|
|
167
250
|
|
|
168
|
-
Enable or disable phases in `harness/config.json` under `phases.enabled
|
|
251
|
+
Enable or disable phases in `harness/config.json` under `phases.enabled`, or in the wizard.
|
|
252
|
+
RESEARCH and SIMPLIFY are off by default.
|
|
253
|
+
|
|
254
|
+
RESEARCH runs before anything is specified, and answers the question DEFINE assumes: is this the
|
|
255
|
+
right thing to build at all? It writes prior art, the constraints that are real, at least two
|
|
256
|
+
options with what each costs, a recommendation, what would make that recommendation wrong, and the
|
|
257
|
+
questions only you can answer — which become the DEFINE interview. Turn it on when the human gave
|
|
258
|
+
an idea rather than a specification.
|
|
169
259
|
|
|
170
260
|
## When it gets stuck
|
|
171
261
|
|
|
@@ -259,11 +349,22 @@ The agent edits it by submitting the **complete** task list through the `infinit
|
|
|
259
349
|
|
|
260
350
|
## Watching it work
|
|
261
351
|
|
|
262
|
-
**In the terminal** — the widget above updates on every turn
|
|
263
|
-
|
|
352
|
+
**In the terminal** — the widget above updates on every turn, showing all five levels of the plan:
|
|
353
|
+
goal, sprint, feature, task, subtask. It is a *window*, not a truncation — the rows above and
|
|
354
|
+
below are counted, and one keypress away:
|
|
355
|
+
|
|
356
|
+
| Key | |
|
|
357
|
+
|---|---|
|
|
358
|
+
| `alt+j` / `alt+k` | scroll the plan down / up |
|
|
359
|
+
| `alt+o` | expand — every subtask, three times the rows |
|
|
360
|
+
| `/infinity:scroll follow` | back to tracking the active task |
|
|
361
|
+
|
|
362
|
+
It is responsive down to ~58 columns, degrades to ASCII when the locale isn't UTF-8, and drops
|
|
363
|
+
colour under `NO_COLOR`.
|
|
264
364
|
|
|
265
365
|
**In a browser** — `/infinity:dashboard` serves a live page on loopback: phase rail, stacked progress
|
|
266
|
-
meters that show stuck work as colour rather than absence, the
|
|
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
|
|
267
368
|
verdict. It refreshes itself every 5 seconds and reconnects with backoff if the run ends.
|
|
268
369
|
|
|
269
370
|
The dashboard is strictly read-only and binds to `127.0.0.1`. It never writes, and never bumps
|
|
@@ -345,8 +446,12 @@ infinity-harness/
|
|
|
345
446
|
│ ├── core/ types · paths · fsx · config · phases · gates · brief
|
|
346
447
|
│ │ · featureList (the SSOT) · lock · exec
|
|
347
448
|
│ │ · skills (match) · skillsAudit (guard)
|
|
348
|
-
│ ├── ui/ theme ·
|
|
449
|
+
│ ├── ui/ theme · planTree (the five levels, once)
|
|
450
|
+
│ │ · widget (terminal) · dashboard (web) · wizard · config
|
|
349
451
|
│ ├── loop.ts the continuous-run driver and its stop conditions
|
|
452
|
+
│ ├── runState.ts is a run armed, and which run is it — on disk, across sessions
|
|
453
|
+
│ ├── handoff.ts when to continue in a fresh session, and what to tell it
|
|
454
|
+
│ ├── approval.ts · intake.ts human sign-off · what the start-up wizard's answers mean
|
|
350
455
|
│ ├── escalate.ts the ladder's actuator: chooses a rung and takes it
|
|
351
456
|
│ ├── goal.ts the outer loop: is the thing asked for actually done?
|
|
352
457
|
│ ├── taskList.ts atomic plan editor
|
|
@@ -358,11 +463,15 @@ infinity-harness/
|
|
|
358
463
|
├── harness/
|
|
359
464
|
│ ├── features/feature-list.json the plan
|
|
360
465
|
│ ├── config.json pipeline state and settings
|
|
466
|
+
│ ├── run.json the armed run — survives every session it spans
|
|
361
467
|
│ ├── model-router.json optional routing
|
|
362
468
|
│ ├── docs/ architecture · decisions · phase and role docs
|
|
363
469
|
│ └── skills/ 28 craft skills the brief points at
|
|
364
|
-
├── tests/
|
|
365
|
-
└── scripts/
|
|
470
|
+
├── tests/ 31 files, plain node:assert
|
|
471
|
+
└── scripts/
|
|
472
|
+
├── run-tests.mjs
|
|
473
|
+
├── e2e.mjs 16 scenarios, including one against a real pi process
|
|
474
|
+
└── rig/ the real-pi driver: a scripted model + the RPC protocol
|
|
366
475
|
```
|
|
367
476
|
|
|
368
477
|
The extension is deliberately thin. Every decision lives in `src/`, where it's typed and tested —
|
|
@@ -372,13 +481,28 @@ there is one implementation, and the adapter calls it.
|
|
|
372
481
|
|
|
373
482
|
```bash
|
|
374
483
|
npm install
|
|
375
|
-
npm run check
|
|
376
|
-
npm test
|
|
377
|
-
npm run e2e
|
|
484
|
+
npm run check # tsc --noEmit, strict
|
|
485
|
+
npm test # 31 test files
|
|
486
|
+
npm run e2e # 16 end-to-end scenarios
|
|
487
|
+
npm run e2e -- --only realpi # just the ones that drive a real pi process
|
|
488
|
+
npm run e2e -- --list # what the scenarios are
|
|
378
489
|
```
|
|
379
490
|
|
|
380
491
|
Tests are plain `node:assert` run under `--experimental-strip-types`. No framework, no build step.
|
|
381
492
|
|
|
493
|
+
The scenario worth knowing about is **`realpi`**. Everything else drives our own modules, or drives
|
|
494
|
+
the adapter against a *fake* pi — a fair test of our contracts and a poor test of pi's. Every bug
|
|
495
|
+
that has reached a user so far lived in the gap between the two: a BOM that made every config read
|
|
496
|
+
fail, a run that ended at its first session handoff, a brief queued in a delivery mode that
|
|
497
|
+
deadlocks `pi -p`.
|
|
498
|
+
|
|
499
|
+
`realpi` closes the gap. `scripts/rig/` starts a real `pi --mode rpc` against a scripted model
|
|
500
|
+
server and speaks the RPC protocol to it — typing prompts and slash commands, answering wizard
|
|
501
|
+
dialogs, and reading back the widget and notifications a human would actually see. It covers
|
|
502
|
+
startup, the wizard, a run spanning several real sessions, real auto-compaction, an approval
|
|
503
|
+
round-trip, and `pi -p` not hanging. When something is wrong in the product rather than in a
|
|
504
|
+
module, this is the scenario that notices.
|
|
505
|
+
|
|
382
506
|
## Licence
|
|
383
507
|
|
|
384
508
|
MIT
|