infinity-harness 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +114 -0
- package/LICENSE +21 -0
- package/README.md +266 -0
- package/extensions/infinity-harness/index.ts +870 -0
- package/harness/docs/ARCHITECTURE.md +159 -0
- package/harness/docs/CONSTRAINTS.md +19 -0
- package/harness/docs/DECISIONS.md +107 -0
- package/harness/docs/DOMAIN.md +13 -0
- package/harness/docs/agents/evaluator.md +14 -0
- package/harness/docs/agents/generator.md +13 -0
- package/harness/docs/agents/planner.md +13 -0
- package/harness/docs/agents/simplifier.md +13 -0
- package/harness/docs/api-patterns.md +23 -0
- package/harness/docs/phases/build.md +47 -0
- package/harness/docs/phases/define.md +58 -0
- package/harness/docs/phases/plan.md +50 -0
- package/harness/docs/phases/review.md +47 -0
- package/harness/docs/phases/ship.md +43 -0
- package/harness/docs/phases/simplify.md +45 -0
- package/harness/docs/phases/verify.md +46 -0
- package/harness/model-router.json +28 -0
- package/harness/skills/README.md +60 -0
- package/harness/skills/auth-security.md +56 -0
- package/harness/skills/building-mcp-servers.md +70 -0
- package/harness/skills/building-tools.md +60 -0
- package/harness/skills/capability-acquisition.md +72 -0
- package/harness/skills/cli-design.md +55 -0
- package/harness/skills/code-review.md +57 -0
- package/harness/skills/codebase-design.md +70 -0
- package/harness/skills/concurrency-async.md +61 -0
- package/harness/skills/config-and-secrets.md +52 -0
- package/harness/skills/context-hygiene.md +51 -0
- package/harness/skills/databases.md +63 -0
- package/harness/skills/diagnosing-bugs.md +84 -0
- package/harness/skills/domain-modeling.md +65 -0
- package/harness/skills/error-handling-logging.md +56 -0
- package/harness/skills/frontend-ui.md +56 -0
- package/harness/skills/grilling.md +48 -0
- package/harness/skills/http-apis.md +60 -0
- package/harness/skills/performance.md +53 -0
- package/harness/skills/pi-todo-adapted.md +41 -0
- package/harness/skills/planning-tasks.md +86 -0
- package/harness/skills/prototype.md +39 -0
- package/harness/skills/research.md +32 -0
- package/harness/skills/resolving-merge-conflicts.md +30 -0
- package/harness/skills/scope-discipline.md +49 -0
- package/harness/skills/self-review.md +45 -0
- package/harness/skills/stuck-protocol.md +51 -0
- package/harness/skills/tdd.md +80 -0
- package/harness/skills/testing-infra.md +57 -0
- package/harness/skills/writing-skills.md +60 -0
- package/package.json +61 -0
- package/src/core/brief.ts +242 -0
- package/src/core/config.ts +265 -0
- package/src/core/exec.ts +130 -0
- package/src/core/featureList.ts +286 -0
- package/src/core/fsx.ts +119 -0
- package/src/core/gates.ts +444 -0
- package/src/core/lock.ts +192 -0
- package/src/core/paths.ts +95 -0
- package/src/core/phases.ts +143 -0
- package/src/core/settings.ts +445 -0
- package/src/core/types.ts +245 -0
- package/src/goalLoop.ts +628 -0
- package/src/goalSpec.ts +679 -0
- package/src/goalState.ts +338 -0
- package/src/loop.ts +355 -0
- package/src/modelRouter.ts +184 -0
- package/src/remote.ts +244 -0
- package/src/replan.ts +300 -0
- package/src/review.ts +53 -0
- package/src/rework.ts +274 -0
- package/src/taskList.ts +355 -0
- package/src/ui/config.ts +286 -0
- package/src/ui/dashboard.ts +1066 -0
- package/src/ui/theme.ts +317 -0
- package/src/ui/widget.ts +370 -0
- package/src/unstuck.ts +214 -0
- package/src/worker.ts +351 -0
- package/types/proper-lockfile.d.ts +19 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here.
|
|
4
|
+
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow
|
|
5
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [2.0.0] — 2026-08-23
|
|
8
|
+
|
|
9
|
+
Renamed from `pi-harness` to **infinity-harness**, and rebuilt from a working prototype into
|
|
10
|
+
something shippable. This is a breaking release: tool names, command names and the package name all
|
|
11
|
+
changed, and the extension no longer depends on an external repository.
|
|
12
|
+
|
|
13
|
+
### Breaking
|
|
14
|
+
|
|
15
|
+
- **Package renamed** `pi-harness` → `infinity-harness`.
|
|
16
|
+
- **Tools renamed.** `harness_task_list` → `infinity_plan`, `pi_goal_task`/`harness_goal_loop` →
|
|
17
|
+
`infinity_goal`, `pi_harness_remote`/`harness_remote` → `infinity_dashboard`,
|
|
18
|
+
`harness_spawn_worker` → `infinity_spawn_worker`. New: `infinity_brief`, `infinity_validate`,
|
|
19
|
+
`infinity_advance`.
|
|
20
|
+
- **Commands renamed** to the `/infinity:*` namespace, and `/infinity:run` / `/infinity:halt` added.
|
|
21
|
+
- **The `cli`, `prompts` and `skills` symlinks are gone.** They pointed at absolute paths inside a
|
|
22
|
+
sibling `dev-harness` checkout, which made the package impossible to install anywhere else. The
|
|
23
|
+
logic they reached is now owned TypeScript in `src/core/`. Skills ship from `harness/skills/`.
|
|
24
|
+
- **Node 22+ required** (the test and E2E runners use native TypeScript stripping).
|
|
25
|
+
- **Dependencies trimmed** to `proper-lockfile` and `string-width`; `ajv` and `simple-git` were
|
|
26
|
+
declared but unused.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- **Concurrent plan writes could lose edits.** `writeTaskList` read the plan, checked `baseRevision`,
|
|
31
|
+
then wrote — three steps with no mutual exclusion, so two writers that both read revision N both
|
|
32
|
+
passed the check and both wrote N+1. Measured at 2 lost updates in a 6-way fan-out. The whole
|
|
33
|
+
read-apply-write now happens under an exclusive lock, and fails closed rather than racing.
|
|
34
|
+
- **Plan writes silently dropped task fields.** Round-tripping through the extension rebuilt each
|
|
35
|
+
task from a fixed shape, discarding `difficulty`, `modelHint`, `criteria` and anything else. Updates
|
|
36
|
+
now merge onto the stored task, so unknown fields survive.
|
|
37
|
+
- **The tested code was not the shipped code.** The extension carried inlined copies of the plan
|
|
38
|
+
engine and the widget; the test suite exercised `src/`, which the extension never called. One
|
|
39
|
+
implementation now, in `src/`.
|
|
40
|
+
- **Status aliases failed dependency validation.** `rework.ts` and `replan.ts` parsed the plan raw, so
|
|
41
|
+
a task stored as `"done"` never compared equal to `"complete"` and every amendment to such a plan
|
|
42
|
+
was rejected — with a message claiming a task in flight had unresolved dependencies.
|
|
43
|
+
- **A nested lock deadlocked against itself.** The new sync lock used `<path>.lock`, the same
|
|
44
|
+
directory `proper-lockfile` uses, so a caller holding the async lock blocked the event loop waiting
|
|
45
|
+
for a directory it already owned. The sync lock now uses `<path>.ilock`.
|
|
46
|
+
- **Locks were held across whole agent turns** with an 8-second staleness timeout, meaning any turn
|
|
47
|
+
longer than eight seconds left a lock another process could steal. Critical sections are now
|
|
48
|
+
milliseconds.
|
|
49
|
+
- **`require()` in an ESM module** meant the rich tool renderers silently never loaded.
|
|
50
|
+
- **`process.cwd()` in the context hook** instead of the session's project directory.
|
|
51
|
+
- **The widget overran its frame below 40 columns.** The progress row now degrades instead of padding
|
|
52
|
+
past the edge, and unboxed output is clamped to the requested width.
|
|
53
|
+
- **Ambiguous-width glyphs misaligned the widget.** `string-width` reports `⚠ ↷ ▸ ✓ ·` as two columns;
|
|
54
|
+
terminals draw them in one. Width measurement now pins them.
|
|
55
|
+
- **Truncation destroyed ANSI styling**, bleeding colour into the rest of the line.
|
|
56
|
+
- **`gateHistory` grew without bound** over a long run. Capped at 500 entries.
|
|
57
|
+
- **A type-only import of `AddressInfo`** made the dashboard module fail to load under type stripping.
|
|
58
|
+
- **A raw NUL byte in a source file** made `grep` and `file` treat the module as binary.
|
|
59
|
+
- **A model reference reached a shell unvalidated.** It is interpolated into the worker command, so it
|
|
60
|
+
is now checked against a strict character set and refused rather than escaped — a typo cannot
|
|
61
|
+
become a command substitution.
|
|
62
|
+
|
|
63
|
+
### Added
|
|
64
|
+
|
|
65
|
+
- **Continuous run driver** (`src/loop.ts`). `/infinity:run` validates, advances, re-briefs and keeps
|
|
66
|
+
going until the pipeline completes or a guard fires: no-progress detection, wall-clock and
|
|
67
|
+
iteration ceilings, retry budgets, and a human brake (`/infinity:halt`, `paused`, `harness/STOP`).
|
|
68
|
+
Every stop names its reason.
|
|
69
|
+
- **New terminal widget.** Phase rail, progress meter, task window centred on the active task,
|
|
70
|
+
dependency references, subtasks under the task actually being worked. Responsive to ~58 columns,
|
|
71
|
+
ASCII fallback on non-UTF-8 locales, colour degradation from truecolor to none.
|
|
72
|
+
- **New web dashboard.** Same information design for the browser: stacked progress meters that show
|
|
73
|
+
stuck work as colour rather than absence, gate panel, alerts strip, 5-second self-refresh with
|
|
74
|
+
backoff. Read-only, loopback-only, and it never runs the gate.
|
|
75
|
+
- **Deterministic gate suite** with per-phase checks, task-scoped validation, and advisory checks that
|
|
76
|
+
report without blocking.
|
|
77
|
+
- **E2E suite** (`npm run e2e`): 11 scenarios, 79 assertion groups, over real temp projects, real git
|
|
78
|
+
repos and real child processes — including a concurrency fan-out with an unlocked control that
|
|
79
|
+
demonstrates why the lock is load-bearing.
|
|
80
|
+
- **Test runner** (`npm test`): 21 files, plain `node:assert`, no framework.
|
|
81
|
+
- **Full configuration from inside pi.** `/infinity:config` opens an interactive menu covering models,
|
|
82
|
+
pipeline, project commands, gates, loop budgets and retry budgets; `/infinity:config show` prints
|
|
83
|
+
the lot as text and is what runs automatically when the mode has no dialogs. The menu is generated
|
|
84
|
+
from one schema (`src/core/settings.ts`), so an option cannot exist in the file format and be
|
|
85
|
+
missing from the UI.
|
|
86
|
+
- **Model tiers picked from pi's own models.** Config → Models offers the models pi has configured
|
|
87
|
+
and can authenticate — session-scoped ones when scoping is set — for each difficulty tier, the
|
|
88
|
+
master model and the default. Any tier can be handed back to "pi's current model".
|
|
89
|
+
`/infinity:models` shows the available list beside the current routing.
|
|
90
|
+
- Values are bounds-checked before they are written, durations accept `24h` / `90m`, and the phase
|
|
91
|
+
list is toggled item by item and stored in pipeline order rather than click order.
|
|
92
|
+
- `.bak` recovery for a corrupt plan file.
|
|
93
|
+
- A `LockTimeoutError` a caller can actually act on.
|
|
94
|
+
|
|
95
|
+
### Changed
|
|
96
|
+
|
|
97
|
+
- **Model routing ships vendor-neutral.** Every slot is empty by default, meaning "use whatever model
|
|
98
|
+
pi is already configured with". Installing the harness no longer silently redirects work to a
|
|
99
|
+
specific third-party model.
|
|
100
|
+
- **Pi-only.** Support and references for other agent systems were removed; this is a pi extension
|
|
101
|
+
and nothing else.
|
|
102
|
+
- The dashboard refuses to bind to a non-loopback interface without an explicit opt-in, and serves a
|
|
103
|
+
CSP tight enough that an escaping slip cannot become script execution.
|
|
104
|
+
- Documentation rewritten: README, AGENTS.md, and `harness/docs/ARCHITECTURE.md`.
|
|
105
|
+
- **`strict: true`.** The whole tree typechecks under TypeScript strict mode, with ambient types added
|
|
106
|
+
for `proper-lockfile`, which ships none.
|
|
107
|
+
- **Verified installable from npm** (`pi install infinity-harness`). pi loads extensions through
|
|
108
|
+
`jiti`, which transpiles TypeScript at runtime, so the package ships `.ts` with no build step.
|
|
109
|
+
Plain `node` refuses to type-strip inside `node_modules`; pi does not use plain `node` for this.
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
Earlier releases (0.2.0 – 1.2.0) were developed under the `pi-harness` name and are not carried
|
|
114
|
+
forward here; that history is in the git log.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Bakr Bagaber
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
# infinity-harness
|
|
2
|
+
|
|
3
|
+
**A pi extension that keeps an agent building — correctly — for hours or days without you.**
|
|
4
|
+
|
|
5
|
+
Point it at a project, describe the goal, and walk away. infinity-harness drives the agent through a
|
|
6
|
+
gated pipeline, checks the work with deterministic gates rather than the model's own judgement, and
|
|
7
|
+
stops with a clear reason when it genuinely needs you.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
╭──────────────────────────────────────────────────────────────────────────╮
|
|
11
|
+
│ ∞ INFINITY ──────────────────────────────────────────────── BUILD rev 42 │
|
|
12
|
+
│ ▸ Ship the payments rewrite behind a flag │
|
|
13
|
+
│ │
|
|
14
|
+
│ ● define ─ ● plan ─ ◉ BUILD ─ ○ verify ─ ○ review ─ ○ ship │
|
|
15
|
+
│ │
|
|
16
|
+
│ ▰▰▰▰▰▰▰▰▰▰▰▱▱▱▱▱▱▱▱▱▱▱▱▱ 45% 5/11 tasks · 1/2 features │
|
|
17
|
+
│ ⚠ 1 blocked · ↷ 1 rework · retry 2/10 │
|
|
18
|
+
│ │
|
|
19
|
+
│ ▸ feature-002 · Checkout flow │
|
|
20
|
+
│ ● 4 validate cart totals against catalogue prices │
|
|
21
|
+
│ ● 5 apply stacked discount codes with precedence rules ← #4 │
|
|
22
|
+
│ ◐ 6 handle partial refunds across split tenders ← #4, #5 │
|
|
23
|
+
│ ✓ unit tests for tender split │
|
|
24
|
+
│ ▸ integration test against sandbox │
|
|
25
|
+
│ · audit log entries │
|
|
26
|
+
│ ○ 7 emit refund webhook ← #6 │
|
|
27
|
+
│ ⚠ 8 reconcile ledger nightly ← #6 │
|
|
28
|
+
│ ⋯ 3 more │
|
|
29
|
+
╰──────────────────────────────────────────────────────────────────────────╯
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Why it exists
|
|
35
|
+
|
|
36
|
+
Left alone, a coding agent drifts. It declares work finished that isn't, forgets what it already
|
|
37
|
+
did, re-solves the same problem three different ways, and — worst of all — keeps going long after it
|
|
38
|
+
stopped making progress. Pair it with a small or cheap model and all of that gets worse.
|
|
39
|
+
|
|
40
|
+
infinity-harness fixes that by taking two decisions away from the model:
|
|
41
|
+
|
|
42
|
+
1. **When work is done.** A deterministic gate decides, not the agent. Same tree, same verdict, every
|
|
43
|
+
time. No agent marks its own homework.
|
|
44
|
+
2. **What happens next.** The phase pipeline is forward-only and one step at a time. The agent cannot
|
|
45
|
+
decide it's bored of BUILD and jump to SHIP.
|
|
46
|
+
|
|
47
|
+
Everything else — the plan, the retries, the model routing — exists to keep those two decisions
|
|
48
|
+
honest over a very long run.
|
|
49
|
+
|
|
50
|
+
## Install
|
|
51
|
+
|
|
52
|
+
Requires **Node 22+** and [pi](https://github.com/earendil-works/pi-coding-agent).
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
# from npm — project-local, so the team shares it via .pi/settings.json
|
|
56
|
+
pi install npm:infinity-harness -l
|
|
57
|
+
|
|
58
|
+
# or globally
|
|
59
|
+
pi install npm:infinity-harness
|
|
60
|
+
|
|
61
|
+
# straight from the repo
|
|
62
|
+
pi install git:github.com/bakr-bagaber/infinity-harness
|
|
63
|
+
|
|
64
|
+
# or from a checkout
|
|
65
|
+
pi install ./infinity-harness -l
|
|
66
|
+
|
|
67
|
+
pi list # confirm it loaded
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The package ships TypeScript. pi loads extensions through `jiti`, which
|
|
71
|
+
transpiles at runtime, so there is no build step and nothing to compile.
|
|
72
|
+
|
|
73
|
+
## Use it
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
cd your-project
|
|
77
|
+
pi
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
On session start the harness injects a brief — phase, role, current task, acceptance criteria, and
|
|
81
|
+
what to do next. Do the work, then:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
/infinity:validate run the gate for this phase
|
|
85
|
+
/infinity:run hand it the wheel: validate → advance → re-brief, until done or stuck
|
|
86
|
+
/infinity:config change any setting, including which model runs which tier
|
|
87
|
+
/infinity:models what models pi has, and how they are being routed
|
|
88
|
+
/infinity:dashboard open the live web view
|
|
89
|
+
/infinity:halt take the wheel back
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`/infinity:run` is the point of the tool. It keeps the loop turning without you.
|
|
93
|
+
|
|
94
|
+
## Configuration
|
|
95
|
+
|
|
96
|
+
Everything is configurable from inside pi:
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
/infinity:config interactive menu
|
|
100
|
+
/infinity:config show print the whole configuration as text
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The menu is generated from a single schema, so every option the file format
|
|
104
|
+
supports is reachable from the UI — the two cannot drift. Editing
|
|
105
|
+
`harness/config.json` and `harness/model-router.json` by hand stays entirely
|
|
106
|
+
valid; the menu is the same data with prompts and bounds checking attached.
|
|
107
|
+
|
|
108
|
+
| Group | Covers |
|
|
109
|
+
|---|---|
|
|
110
|
+
| **Models** | Which model runs each difficulty tier, the master model, consultation budget |
|
|
111
|
+
| **Pipeline** | Which phases run, copilot vs autopilot, role strictness, pause |
|
|
112
|
+
| **Project commands** | lint / test / coverage / build — what the gate actually runs |
|
|
113
|
+
| **Gates** | Enable, coverage threshold, placeholder rejection |
|
|
114
|
+
| **Continuous run** | Iteration ceiling, wall-clock budget, no-progress strikes |
|
|
115
|
+
| **Retry budgets** | Attempts per task, feature and phase |
|
|
116
|
+
|
|
117
|
+
## The pipeline
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
define → plan → build → verify → [simplify] → review → ship
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
| Phase | What it's for | Gate opens when |
|
|
124
|
+
|---|---|---|
|
|
125
|
+
| **define** | Write down what's being built and how you'll know it's done | Every feature has acceptance criteria |
|
|
126
|
+
| **plan** | Break features into ordered, dependency-aware tasks | Tasks exist and criteria are set |
|
|
127
|
+
| **build** | Implement, one task at a time, tests alongside | Lint, tests, coverage pass; no placeholders; every task complete |
|
|
128
|
+
| **verify** | Prove behaviour; hunt what the tests miss | Tests and coverage pass on a clean tree |
|
|
129
|
+
| **simplify** | Delete more than you add *(opt-in)* | Tests pass, no empty dirs, clean tree |
|
|
130
|
+
| **review** | Judge it as if someone else wrote it | Rubric, README, architecture doc and decisions are real; branch level with upstream |
|
|
131
|
+
| **ship** | Tag, changelog, leave it clean | Clean tree, tagged, changelog, README, licence, no placeholders |
|
|
132
|
+
|
|
133
|
+
Enable or disable phases in `harness/config.json` under `phases.enabled`. SIMPLIFY is off by default.
|
|
134
|
+
|
|
135
|
+
## Knowing when to stop
|
|
136
|
+
|
|
137
|
+
This is the part that makes an unattended run safe. `/infinity:run` halts on any of:
|
|
138
|
+
|
|
139
|
+
| Guard | Default | What it catches |
|
|
140
|
+
|---|---|---|
|
|
141
|
+
| **No progress** | 3 strikes | Gate keeps failing and the working tree hasn't moved — the agent is spinning, not working |
|
|
142
|
+
| **Wall clock** | 24h | A run you forgot about |
|
|
143
|
+
| **Iterations** | 2000 | Runaway loops that stay under the clock |
|
|
144
|
+
| **Retry budget** | 10/task | One impossible task eating the whole run |
|
|
145
|
+
| **Pipeline complete** | — | Final phase passed with every task done |
|
|
146
|
+
| **Human brake** | — | `/infinity:halt`, `/infinity:pause`, or `touch harness/STOP` |
|
|
147
|
+
|
|
148
|
+
Every stop names its reason. You come back to an explanation, not a mystery.
|
|
149
|
+
|
|
150
|
+
Tune the budgets in `harness/config.json`:
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"loop": {
|
|
155
|
+
"maxIterations": 2000,
|
|
156
|
+
"maxWallClockMs": 86400000,
|
|
157
|
+
"noProgressLimit": 3
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## The plan is a file
|
|
163
|
+
|
|
164
|
+
`harness/features/feature-list.json` is the single source of truth. The widget, the dashboard and the
|
|
165
|
+
brief all read it; nothing caches a second copy.
|
|
166
|
+
|
|
167
|
+
The agent edits it by submitting the **complete** task list through the `infinity_plan` tool:
|
|
168
|
+
|
|
169
|
+
- **Omission means deletion.** One unambiguous rule beats incremental edits a model loses track of.
|
|
170
|
+
- **`baseRevision` guards every write.** A stale revision is rejected, so parallel workers can't
|
|
171
|
+
clobber each other.
|
|
172
|
+
- **Unknown fields survive.** An update merges onto the stored task, so `difficulty`, `modelHint`,
|
|
173
|
+
`criteria` and anything added later are never silently dropped.
|
|
174
|
+
- **The dependency graph stays sane.** Cycles and dangling references are rejected at write time; a
|
|
175
|
+
task can't be `complete` while something it depends on isn't.
|
|
176
|
+
|
|
177
|
+
## Watching it work
|
|
178
|
+
|
|
179
|
+
**In the terminal** — the widget above updates on every turn. It's responsive down to ~58 columns,
|
|
180
|
+
degrades to ASCII when the locale isn't UTF-8, and drops colour under `NO_COLOR`.
|
|
181
|
+
|
|
182
|
+
**In a browser** — `/infinity:dashboard` serves a live page on loopback: phase rail, stacked progress
|
|
183
|
+
meters that show stuck work as colour rather than absence, the full task tree, and the last gate
|
|
184
|
+
verdict. It refreshes itself every 5 seconds and reconnects with backoff if the run ends.
|
|
185
|
+
|
|
186
|
+
The dashboard is strictly read-only and binds to `127.0.0.1`. It never writes, and never bumps
|
|
187
|
+
`baseRevision` — opening it can't perturb the run you're watching.
|
|
188
|
+
|
|
189
|
+
## Model routing (optional)
|
|
190
|
+
|
|
191
|
+
Send cheap tasks to a small model and hard ones to a large one. Pick them with `/infinity:config` →
|
|
192
|
+
**Models**: the list offered is the models **pi itself has configured and can authenticate**, so you
|
|
193
|
+
choose from what you already have rather than typing ids from memory. `/infinity:models` shows that
|
|
194
|
+
list alongside the current routing.
|
|
195
|
+
|
|
196
|
+
Routing ships **disabled with every slot empty**, meaning "use whatever model pi is already
|
|
197
|
+
configured with" — installing the harness never silently redirects your work to someone else's
|
|
198
|
+
model. Any tier can be handed back to that default at any time.
|
|
199
|
+
|
|
200
|
+
Resolution order:
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
task.modelHint → byTask → byDifficulty → byFeature → bySprint → byPhase → byRole → default
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
`master` is never assigned directly; it's reachable only through one-step consultation after the
|
|
207
|
+
normal ladder is exhausted.
|
|
208
|
+
|
|
209
|
+
**Reasoning models need headroom.** A reasoning model emits nothing on the content channel until it
|
|
210
|
+
has finished thinking — measured at ~370 reasoning tokens to answer "reply with one word". If you
|
|
211
|
+
route a tier to one, give its workers a generous timeout; a tight budget returns an empty completion
|
|
212
|
+
that looks like a broken endpoint but is only a small cap.
|
|
213
|
+
|
|
214
|
+
## Tools the agent gets
|
|
215
|
+
|
|
216
|
+
| Tool | Purpose |
|
|
217
|
+
|---|---|
|
|
218
|
+
| `infinity_brief` | What am I supposed to be doing right now? |
|
|
219
|
+
| `infinity_plan` | Read or rewrite the task list |
|
|
220
|
+
| `infinity_validate` | Run the gate for this phase |
|
|
221
|
+
| `infinity_advance` | Move to the next phase (refuses on a failing gate) |
|
|
222
|
+
| `infinity_dashboard` | Start/stop/query the web view |
|
|
223
|
+
|
|
224
|
+
## Layout
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
infinity-harness/
|
|
228
|
+
├── extensions/infinity-harness/ pi lifecycle adapter — thin, no logic of its own
|
|
229
|
+
├── src/
|
|
230
|
+
│ ├── core/ types · paths · fsx · config · phases · gates · brief
|
|
231
|
+
│ │ · featureList (the SSOT) · lock · exec
|
|
232
|
+
│ ├── ui/ theme · widget (terminal) · dashboard (web)
|
|
233
|
+
│ ├── loop.ts the continuous-run driver and its stop conditions
|
|
234
|
+
│ ├── taskList.ts atomic plan editor
|
|
235
|
+
│ ├── worker.ts isolated per-task workers
|
|
236
|
+
│ ├── modelRouter.ts difficulty ladder + consultation
|
|
237
|
+
│ ├── rework.ts · replan.ts backward rework with BFS impact · mid-build amendment
|
|
238
|
+
│ ├── unstuck.ts · review.ts escalation strategy matrix · review bounce guard
|
|
239
|
+
│ └── goalLoop.ts · goalState.ts · goalSpec.ts
|
|
240
|
+
├── harness/
|
|
241
|
+
│ ├── features/feature-list.json the plan
|
|
242
|
+
│ ├── config.json pipeline state and settings
|
|
243
|
+
│ ├── model-router.json optional routing
|
|
244
|
+
│ ├── docs/ architecture · decisions · phase and role docs
|
|
245
|
+
│ └── skills/ 29 craft skills the brief points at
|
|
246
|
+
├── tests/ 20 files, plain node:assert
|
|
247
|
+
└── scripts/run-tests.mjs
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
The extension is deliberately thin. Every decision lives in `src/`, where it's typed and tested —
|
|
251
|
+
there is one implementation, and the adapter calls it.
|
|
252
|
+
|
|
253
|
+
## Development
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
npm install
|
|
257
|
+
npm run check # tsc --noEmit
|
|
258
|
+
npm test # 20 test files
|
|
259
|
+
npm run e2e # end-to-end against a live model
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Tests are plain `node:assert` run under `--experimental-strip-types`. No framework, no build step.
|
|
263
|
+
|
|
264
|
+
## Licence
|
|
265
|
+
|
|
266
|
+
MIT
|