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
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pi-todo-adapted
|
|
3
|
+
description: "Atomic infinity_plan pattern with omission deletion, baseRevision optimistic concurrency, cycle/missing-dep checks and compaction-safe replay (adapted from @99percentpeople/pi-todo)"
|
|
4
|
+
tags: [harness, pi-todo, atomic, baseRevision, omission, deletion, compaction, widget, task-list, dependency]
|
|
5
|
+
when: "implementing infinity_plan, atomic revisioning, Pi widget with session persistence or task dependencies"
|
|
6
|
+
phases: [build, verify]
|
|
7
|
+
provenance: { origin: "https://github.com/99percentpeople/pi-extensions", license: MIT, adapted: true, url: "https://github.com/99percentpeople/pi-extensions", contentHash: abf626df6a74a6fb }
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# pi-todo Adapted — Atomic Task List with Compaction-Safe Replay
|
|
11
|
+
|
|
12
|
+
> Adapted from [@99percentpeople/pi-todo](https://github.com/99percentpeople/pi-extensions) (MIT © 99percentpeople). Trimmed to harness core and re-pointed to `harness/features/feature-list.json` + Pi extension `harness:checkpoint`.
|
|
13
|
+
|
|
14
|
+
## Rules
|
|
15
|
+
|
|
16
|
+
- **One-call authoritative list.** Client sends complete desired list; server treats omission as permanent deletion. Inherit omitted fields from previous snapshot; new keys require `subject` + `status`. Validation all-or-nothing.
|
|
17
|
+
- **Optimistic concurrency via baseRevision.** Compare `input.baseRevision` vs current `revision`; reject stale with expected/current numbers; increment revision only on real change; empty no-op preserves revision.
|
|
18
|
+
- **Dependency guarantees.** Every `dependsOn` must exist in resulting snapshot (prune completed→completed soft refs only); detect cycles via DFS; `in_progress`/`completed` requires deps completed. Reject atomically.
|
|
19
|
+
- **ToolResult.details is SSOT for branch/compaction.** Store `{rev, tasks}` in toolResult.details; reconstruct state by scanning session branch for latest valid entry on `session_start`, `session_tree`, `/reload`. Branch-aware replay — each branch has correct snapshot.
|
|
20
|
+
- **Hidden checkpoint for compaction.** On `session_before_compact`, persist `{rev, tasks}` as custom entry `harness:checkpoint` outside context; inject as hidden `[{role:"user", content:[{type:"text", text: hidden}]}]` via `context` event on next prompt (or immediately as steer if overflow/continuation). No extra model turn.
|
|
21
|
+
- **Periodic hidden reminder.** Every N LLM calls (default 3) inject compact reminder with `rev + key/status` list via `context` event; reset counter after successful write, restoration, checkpoint injection, or interval change; suppress for empty/completed plans; not written to session.
|
|
22
|
+
- **Widget renders collapsed window via getWidgetWindowBounds.** Use WIDGET_LIMIT=8, COMPLETED_CONTEXT=3, `+N more`, wrap not truncate, `← #1` deps. State comes from reconstructed session + file; survive /reload and /tree.
|
|
23
|
+
|
|
24
|
+
## Anti-patterns
|
|
25
|
+
|
|
26
|
+
- **Per-field patch calls** — one call must carry full authoritative list; piecemeal updates lose atomicity.
|
|
27
|
+
- **File-only persistence** — file is SSOT but session replay is required for branches/compaction; without details replay, `/tree` drifts.
|
|
28
|
+
- **Eager completed cleanup without dependency check** — completed tasks that still block pending/in_progress must be retained.
|
|
29
|
+
- **Stale revision retry without re-read** — on stale error, re-read current rev/tasks and retry merge.
|
|
30
|
+
|
|
31
|
+
## Checklist
|
|
32
|
+
|
|
33
|
+
- [ ] Stale baseRevision rejected with expected/current message, no mutation
|
|
34
|
+
- [ ] Omitted keys deleted, completed→completed deps pruned, new keys validated
|
|
35
|
+
- [ ] Cycle and missing dep rejected atomically
|
|
36
|
+
- [ ] in_progress requires deps completed (also completed requires deps completed if strict)
|
|
37
|
+
- [ ] Revision increments only on added/updated/removed/reordered; details contain {rev, tasks}
|
|
38
|
+
- [ ] State replays from toolResult.details + harness:checkpoint on session_start / session_tree
|
|
39
|
+
- [ ] Hidden checkpoint stored before compaction and injected via context event after compaction
|
|
40
|
+
- [ ] Periodic reminder every 3 calls injects rev + key/status via context, counter resets correctly
|
|
41
|
+
- [ ] Widget uses rolling window (WIDGET_LIMIT=8) with +N more, wraps long labels, shows ← #1
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: planning-tasks
|
|
3
|
+
description: Break specs into tracer-bullet vertical slices with checkable acceptance criteria
|
|
4
|
+
tags: [plan, planning, slice, ticket, decompose, criteria, backlog, breakdown, refactor]
|
|
5
|
+
when: writing or restructuring the feature list from a spec
|
|
6
|
+
phases: [plan]
|
|
7
|
+
provenance: { origin: "mattpocock/skills", license: MIT, adapted: true }
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Planning Tasks — Tracer-Bullet Vertical Slices
|
|
11
|
+
|
|
12
|
+
> Adapted from [mattpocock/skills](https://github.com/mattpocock/skills) (MIT © Matt Pocock, "to-tickets").
|
|
13
|
+
> Use during: PLAN (writing harness/features/feature-list.json).
|
|
14
|
+
|
|
15
|
+
Break the spec into **tracer-bullet vertical slices** and record them as
|
|
16
|
+
features + tasks in `harness/features/feature-list.json`.
|
|
17
|
+
|
|
18
|
+
## Vertical slice rules
|
|
19
|
+
|
|
20
|
+
- Each slice cuts a narrow but COMPLETE path through every layer (schema,
|
|
21
|
+
logic, interface, tests) — vertical, NOT a horizontal slice of one layer.
|
|
22
|
+
- A completed slice is demoable or verifiable on its own.
|
|
23
|
+
- Each task is sized to fit one working session / fresh context window.
|
|
24
|
+
- Prefactoring goes first: "make the change easy, then make the easy change."
|
|
25
|
+
- Order features so each builds on completed ones — the harness works them
|
|
26
|
+
top to bottom.
|
|
27
|
+
|
|
28
|
+
## Writing the feature list
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"version": "0.1",
|
|
33
|
+
"features": [
|
|
34
|
+
{
|
|
35
|
+
"id": "feature-001",
|
|
36
|
+
"name": "User can create a note",
|
|
37
|
+
"description": "End-to-end: POST /notes → stored → retrievable",
|
|
38
|
+
"passes": false,
|
|
39
|
+
"definitionOfDone": [
|
|
40
|
+
"POST /notes with valid body returns 201 + id",
|
|
41
|
+
"GET /notes/:id returns the stored note",
|
|
42
|
+
"Invalid body returns 400 with error message"
|
|
43
|
+
],
|
|
44
|
+
"tasks": [
|
|
45
|
+
{
|
|
46
|
+
"id": "task-001",
|
|
47
|
+
"description": "Note model + storage with create/get",
|
|
48
|
+
"status": "pending",
|
|
49
|
+
"acceptanceCriteria": [
|
|
50
|
+
"createNote(data) returns note with generated id",
|
|
51
|
+
"getNote(id) returns the created note",
|
|
52
|
+
"getNote(unknown) returns null"
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Rules for criteria:
|
|
62
|
+
|
|
63
|
+
- **acceptanceCriteria** (task) — 1–3 concrete, checkable statements about
|
|
64
|
+
observable behavior. "Works correctly" is not a criterion; "getNote(unknown)
|
|
65
|
+
returns null" is. Gates reject empty or placeholder criteria.
|
|
66
|
+
- **definitionOfDone** (feature) — user-visible outcomes proving the whole
|
|
67
|
+
slice works end-to-end.
|
|
68
|
+
- Name features in **user terms** ("User can X"), not layer terms ("Add DB
|
|
69
|
+
table").
|
|
70
|
+
- Use the project's domain vocabulary (`harness/docs/DOMAIN.md`).
|
|
71
|
+
|
|
72
|
+
## Wide refactors — the exception
|
|
73
|
+
|
|
74
|
+
A **wide refactor** (rename a shared symbol, retype a column) breaks
|
|
75
|
+
thousands of call sites at once; no vertical slice can land green. Sequence
|
|
76
|
+
it as **expand–contract**: one task to add the new form beside the old, then
|
|
77
|
+
migration tasks in batches (per package/directory) that stay green because
|
|
78
|
+
the old form still exists, then one task to delete the old form once no
|
|
79
|
+
caller remains.
|
|
80
|
+
|
|
81
|
+
## Sanity check before finishing PLAN
|
|
82
|
+
|
|
83
|
+
- Does each feature deliver something demoable?
|
|
84
|
+
- Is anything blocked by a feature that comes AFTER it? (Reorder.)
|
|
85
|
+
- Too coarse (task needs multiple sessions) or too fine (trivial edits)?
|
|
86
|
+
- Zero placeholder text left anywhere in the file.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: prototype
|
|
3
|
+
description: Throwaway code that answers a design question fast, then gets deleted
|
|
4
|
+
tags: [prototype, spike, experiment, explore, poc, throwaway, design]
|
|
5
|
+
when: a state model, logic shape, or UI direction cannot be judged on paper
|
|
6
|
+
phases: [build, plan]
|
|
7
|
+
provenance: { origin: "mattpocock/skills", license: MIT, adapted: true }
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Prototype
|
|
11
|
+
|
|
12
|
+
> Adapted from [mattpocock/skills](https://github.com/mattpocock/skills) (MIT © Matt Pocock).
|
|
13
|
+
> Use during: BUILD (or PLAN) when a design question can't be answered on paper.
|
|
14
|
+
|
|
15
|
+
A prototype is **throwaway code that answers a question**. The question
|
|
16
|
+
decides the shape:
|
|
17
|
+
|
|
18
|
+
- **"Does this logic / state model feel right?"** → build a tiny runnable
|
|
19
|
+
script that pushes the state machine through the cases that are hard to
|
|
20
|
+
reason about on paper.
|
|
21
|
+
- **"What should this look like?"** → build several radically different
|
|
22
|
+
variations of the interface, cheaply switchable.
|
|
23
|
+
|
|
24
|
+
## Rules
|
|
25
|
+
|
|
26
|
+
1. **Throwaway from day one, clearly marked.** Name it so a casual reader
|
|
27
|
+
sees it's a prototype (`proto-*`, a `prototypes/` dir) — never mixed
|
|
28
|
+
into production paths.
|
|
29
|
+
2. **One command to run.** Whatever the project's runner supports.
|
|
30
|
+
3. **No persistence by default.** State lives in memory; persistence is
|
|
31
|
+
usually the thing being *checked*, not a dependency.
|
|
32
|
+
4. **Skip the polish.** No tests, no error handling beyond runnability, no
|
|
33
|
+
abstractions. The point is to learn fast.
|
|
34
|
+
5. **Surface the state.** After every action, print the full relevant state
|
|
35
|
+
so the effect of each step is visible.
|
|
36
|
+
6. **Capture it when done.** Fold the validated decision into the real code
|
|
37
|
+
and record it: `infinity-harness decision "state machine X chosen because Y
|
|
38
|
+
(validated by prototype)"`. Then DELETE the prototype — the
|
|
39
|
+
anti-placeholder gate will flag leftovers, and that's by design.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: research
|
|
3
|
+
description: Answer factual questions from primary sources; capture cited findings in the repo
|
|
4
|
+
tags: [research, docs, documentation, investigate, source, facts, api, spec, evidence]
|
|
5
|
+
when: a factual question about an API, library, protocol, or tool blocks progress
|
|
6
|
+
phases: [define, plan, build]
|
|
7
|
+
provenance: { origin: "mattpocock/skills", license: MIT, adapted: true }
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Research
|
|
11
|
+
|
|
12
|
+
> Adapted from [mattpocock/skills](https://github.com/mattpocock/skills) (MIT © Matt Pocock).
|
|
13
|
+
> Use during: DEFINE, or any time a factual question blocks progress.
|
|
14
|
+
|
|
15
|
+
When a question needs investigating (an API's real behavior, a library's
|
|
16
|
+
limits, a protocol detail):
|
|
17
|
+
|
|
18
|
+
1. Investigate against **primary sources** — official docs, source code,
|
|
19
|
+
specs, first-party APIs — never a secondary write-up of them. Follow
|
|
20
|
+
every claim back to the source that owns it.
|
|
21
|
+
2. Write the findings to a single Markdown file under `docs/research/`
|
|
22
|
+
(create it if missing), citing each claim's source.
|
|
23
|
+
3. Keep conclusions separate from evidence: a short "Answer" section up
|
|
24
|
+
top, the sourced detail below.
|
|
25
|
+
4. Record the headline insight so future sessions inherit it:
|
|
26
|
+
`harness/lessons-decisions.md "research: X behaves like Y (see docs/research/...)"`.
|
|
27
|
+
|
|
28
|
+
Rules of evidence:
|
|
29
|
+
|
|
30
|
+
- A claim without a source is a guess. Label guesses as guesses.
|
|
31
|
+
- Version matters: note WHICH version of the tool/API the claim covers.
|
|
32
|
+
- If two sources disagree, the more primary one wins; note the conflict.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: resolving-merge-conflicts
|
|
3
|
+
description: Resolve git merge/rebase conflicts by original intent, verify, and finish
|
|
4
|
+
tags: [git, merge, rebase, conflict, branch, hunk]
|
|
5
|
+
when: an in-progress git merge or rebase has conflicting hunks
|
|
6
|
+
phases: []
|
|
7
|
+
provenance: { origin: "mattpocock/skills", license: MIT, adapted: true }
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Resolving Merge Conflicts
|
|
11
|
+
|
|
12
|
+
> Adapted from [mattpocock/skills](https://github.com/mattpocock/skills) (MIT © Matt Pocock).
|
|
13
|
+
> Use during: any in-progress git merge/rebase conflict.
|
|
14
|
+
|
|
15
|
+
1. **See the current state** of the merge/rebase. Check git history and the
|
|
16
|
+
conflicting files.
|
|
17
|
+
2. **Find the primary sources** for each conflict. Understand deeply why
|
|
18
|
+
each change was made and what the original intent was: read commit
|
|
19
|
+
messages, PRs, the feature list entries, and progress log
|
|
20
|
+
(`harness/progress.md`).
|
|
21
|
+
3. **Resolve each hunk.** Preserve both intents where possible. Where
|
|
22
|
+
incompatible, pick the one matching the merge's stated goal and note the
|
|
23
|
+
trade-off. Do **not** invent new behaviour. Always resolve; never
|
|
24
|
+
`--abort`.
|
|
25
|
+
4. **Run the project's automated checks** — typecheck, then tests, then
|
|
26
|
+
lint (`the infinity_validate tool` runs the configured set). Fix anything the
|
|
27
|
+
merge broke.
|
|
28
|
+
5. **Finish the merge/rebase.** Stage everything and commit. If rebasing,
|
|
29
|
+
continue until all commits are rebased. Record anything surprising:
|
|
30
|
+
`harness/lessons-decisions.md "..."`.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scope-discipline
|
|
3
|
+
description: The contract is the boundary — park ideas, resist drive-by fixes, renegotiate explicitly
|
|
4
|
+
tags: [meta, scope, creep, contract, focus, discipline, playbook]
|
|
5
|
+
when: mid-task ideas, adjacent problems, or "while I'm here" temptations appear
|
|
6
|
+
phases: []
|
|
7
|
+
provenance: { origin: built-in, notes: frontier-playbook }
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Scope Discipline
|
|
11
|
+
|
|
12
|
+
Scope creep is how good sessions produce unshippable diffs. The sprint
|
|
13
|
+
contract and the task's acceptance criteria define what you're building —
|
|
14
|
+
everything else, however good, is NOT NOW.
|
|
15
|
+
|
|
16
|
+
## Rules
|
|
17
|
+
|
|
18
|
+
- **The criteria are the whole job.** Done = criteria met. Not "criteria
|
|
19
|
+
met plus improvements I noticed". Extra behavior nobody asked for is
|
|
20
|
+
scope creep even when it's good — it widens the diff, the review
|
|
21
|
+
surface, and the blast radius.
|
|
22
|
+
- **Park, don't pursue.** Mid-task ideas go to the parking lot in one
|
|
23
|
+
line — `harness/lessons-decisions.md "idea: ..."` or a backlog entry in the
|
|
24
|
+
feature list — and you return to the slice. Parking takes 10 seconds;
|
|
25
|
+
pursuing takes an hour and derails the task.
|
|
26
|
+
- **Drive-by fixes are parked too.** Broken thing found outside the task
|
|
27
|
+
(unless it BLOCKS the task): record it, leave it. One task = one
|
|
28
|
+
concern = one reviewable diff.
|
|
29
|
+
- **Blockers interrupt; everything else waits.** The only legitimate
|
|
30
|
+
mid-task detour is something the acceptance criteria cannot be met
|
|
31
|
+
without. Name it as a blocker (learn), fix the minimum, return.
|
|
32
|
+
- **Renegotiate explicitly, never silently.** If the task turns out
|
|
33
|
+
wrong-sized or the contract missed something real: stop, record it, and
|
|
34
|
+
change the plan through the front door (feature-list edit in PLAN
|
|
35
|
+
terms, or contract re-negotiation) — not by quietly building something
|
|
36
|
+
different from what the contract says.
|
|
37
|
+
- **Simplification has its phase.** Refactoring urges during BUILD get
|
|
38
|
+
parked for SIMPLIFY — the pipeline gives cleanup its own budgeted slot.
|
|
39
|
+
|
|
40
|
+
## The test
|
|
41
|
+
|
|
42
|
+
Before touching a file, ask: *which acceptance criterion needs this
|
|
43
|
+
change?* No answer → you're creeping. Park it.
|
|
44
|
+
|
|
45
|
+
## Checklist
|
|
46
|
+
|
|
47
|
+
- [ ] Diff touches only what the criteria require
|
|
48
|
+
- [ ] Every parked idea captured (learn/backlog), none pursued
|
|
49
|
+
- [ ] Any scope change went through plan/contract, with a decision recorded
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: self-review
|
|
3
|
+
description: Structured pass before claiming done — criteria re-check, real run, leftover hunt
|
|
4
|
+
tags: [meta, review, verify, done, quality, check, playbook]
|
|
5
|
+
when: before running validate on any task — every time
|
|
6
|
+
phases: [build, verify, simplify]
|
|
7
|
+
provenance: { origin: built-in, notes: frontier-playbook }
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Self-Review — Before You Claim Done
|
|
11
|
+
|
|
12
|
+
Frontier models don't submit their first draft; they run this pass. It
|
|
13
|
+
takes two minutes and catches the majority of validate failures before
|
|
14
|
+
they burn a retry.
|
|
15
|
+
|
|
16
|
+
## The pass
|
|
17
|
+
|
|
18
|
+
1. **Re-read the acceptance criteria, one by one, against your diff.**
|
|
19
|
+
For each: point at the line(s) that satisfy it. A criterion you can't
|
|
20
|
+
point at is not met — no matter how done it feels.
|
|
21
|
+
2. **Run the thing once, for real.** Not just the tests — the actual entry
|
|
22
|
+
point (start the server, invoke the CLI, render the page). Tests
|
|
23
|
+
passing while the app crashes on boot is a classic.
|
|
24
|
+
3. **Hunt leftovers:** debug prints, commented-out code, TODO/FIXME stubs,
|
|
25
|
+
hardcoded test values, files you created but abandoned. (The
|
|
26
|
+
anti-placeholder gate will catch some — beat it to the punch.)
|
|
27
|
+
4. **Read the diff as a skeptic:** `git diff` top to bottom. Would a
|
|
28
|
+
reviewer who dislikes you find something? Fix it now.
|
|
29
|
+
5. **Check the blast radius:** what ELSE uses what you touched? One
|
|
30
|
+
caller-grep per changed public symbol.
|
|
31
|
+
|
|
32
|
+
## Rules
|
|
33
|
+
|
|
34
|
+
- Never validate as a formality — validate expecting to find problems.
|
|
35
|
+
- The criteria are the contract; "better than asked" and "close enough to
|
|
36
|
+
asked" are both failures (see scope-discipline.md).
|
|
37
|
+
- If step 2 is impossible (no runnable surface), say so in the commit
|
|
38
|
+
message rather than pretending you ran it.
|
|
39
|
+
|
|
40
|
+
## Checklist
|
|
41
|
+
|
|
42
|
+
- [ ] Every acceptance criterion mapped to specific lines
|
|
43
|
+
- [ ] Entry point actually executed post-change
|
|
44
|
+
- [ ] Leftover grep clean (debug/TODO/dead files)
|
|
45
|
+
- [ ] Diff read end-to-end; caller-grep done per public change
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: stuck-protocol
|
|
3
|
+
description: What to do after repeated failures — stop, write down, reframe once, escalate cleanly
|
|
4
|
+
tags: [meta, stuck, retry, failure, escalate, blocked, playbook]
|
|
5
|
+
when: the same step has failed 2-3 times, or you notice you are looping
|
|
6
|
+
phases: []
|
|
7
|
+
provenance: { origin: built-in, notes: frontier-playbook }
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Stuck Protocol
|
|
11
|
+
|
|
12
|
+
Thrashing — trying variations of the same failing approach — burns retries
|
|
13
|
+
and context while teaching nothing. Frontier models notice the loop and
|
|
14
|
+
break it deliberately.
|
|
15
|
+
|
|
16
|
+
## The trigger
|
|
17
|
+
|
|
18
|
+
**Three failed attempts at the same step = STOP.** Also stop when you
|
|
19
|
+
catch any of these tells:
|
|
20
|
+
|
|
21
|
+
- You're re-running the same command hoping for a different result
|
|
22
|
+
- Each "fix" is a small mutation of the last failed fix
|
|
23
|
+
- You can no longer say what NEW information the last attempt produced
|
|
24
|
+
|
|
25
|
+
## The protocol
|
|
26
|
+
|
|
27
|
+
1. **Write down what you know** (before trying anything else):
|
|
28
|
+
what you're trying to achieve, the exact error/failure, the attempts
|
|
29
|
+
made, and what each attempt ruled out. Writing this usually exposes the
|
|
30
|
+
gap — half the time you solve it here.
|
|
31
|
+
2. **Re-read the brief and the skill** (`the infinity_brief tool`; the skill it
|
|
32
|
+
references). Stuck often means a constraint was missed, not that the
|
|
33
|
+
problem is hard.
|
|
34
|
+
3. **Reframe ONCE** — one genuinely different angle, not a variation:
|
|
35
|
+
different seam, smaller slice, different tool, the inverse operation,
|
|
36
|
+
or build the feedback loop you skipped (`diagnosing-bugs.md` Phase 1).
|
|
37
|
+
4. **Escalate cleanly** if the reframe fails:
|
|
38
|
+
- `harness/lessons-decisions.md "BLOCKED <step>: tried A, B, C; ruled out X, Y; suspect Z"`
|
|
39
|
+
- Leave the tree committed and green-adjacent (no half-applied change)
|
|
40
|
+
- Let validate fail honestly — the retry ladder and the human exist for
|
|
41
|
+
exactly this. A clean escalation with evidence is a GOOD outcome;
|
|
42
|
+
a fourth identical attempt is not.
|
|
43
|
+
|
|
44
|
+
## Rules
|
|
45
|
+
|
|
46
|
+
- Never delete the failing evidence (test, error output) to make the step
|
|
47
|
+
"pass".
|
|
48
|
+
- Never widen scope to route around the blocker ("I'll just rewrite the
|
|
49
|
+
module") — that's thrash with more damage.
|
|
50
|
+
- The write-down in step 1 is mandatory, not optional — it's what makes
|
|
51
|
+
the human's (or next session's) job possible.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tdd
|
|
3
|
+
description: Red → green test-driven loop — what a good test is, seams, anti-patterns
|
|
4
|
+
tags: [tdd, test, testing, unit, integration, red-green, seam, mock, coverage]
|
|
5
|
+
when: implementing any BUILD task, or fixing a bug that needs a regression test
|
|
6
|
+
phases: [build, verify]
|
|
7
|
+
provenance: { origin: "mattpocock/skills", license: MIT, adapted: true }
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# TDD — Test-Driven Development
|
|
11
|
+
|
|
12
|
+
> Adapted from [mattpocock/skills](https://github.com/mattpocock/skills) (MIT © Matt Pocock).
|
|
13
|
+
> Use during: BUILD (every task).
|
|
14
|
+
|
|
15
|
+
TDD is the red → green loop. This skill makes that loop produce tests worth
|
|
16
|
+
keeping. Every section applies on every cycle.
|
|
17
|
+
|
|
18
|
+
Before exploring the codebase, read `harness/docs/DOMAIN.md` (if present) so
|
|
19
|
+
test names and interface vocabulary match the project's domain language, and
|
|
20
|
+
respect decisions recorded in `harness/docs/DECISIONS.md`.
|
|
21
|
+
|
|
22
|
+
## Rules of the loop
|
|
23
|
+
|
|
24
|
+
- **Red before green.** Write the failing test first, then only enough code
|
|
25
|
+
to pass it. Don't anticipate future tests or add speculative features.
|
|
26
|
+
- **One slice at a time.** One seam, one test, one minimal implementation
|
|
27
|
+
per cycle.
|
|
28
|
+
- **Refactoring is not part of the loop.** It belongs to SIMPLIFY/REVIEW,
|
|
29
|
+
not the red → green cycle.
|
|
30
|
+
|
|
31
|
+
## What a good test is
|
|
32
|
+
|
|
33
|
+
Tests verify behavior through public interfaces, not implementation details.
|
|
34
|
+
Code can change entirely; tests shouldn't. A good test reads like a
|
|
35
|
+
specification — "user can checkout with valid cart" tells you exactly what
|
|
36
|
+
capability exists — and survives refactors because it doesn't care about
|
|
37
|
+
internal structure.
|
|
38
|
+
|
|
39
|
+
```js
|
|
40
|
+
// GOOD: observable behavior through the public API
|
|
41
|
+
test('user can checkout with valid cart', async () => {
|
|
42
|
+
const cart = createCart();
|
|
43
|
+
cart.add(product);
|
|
44
|
+
const result = await checkout(cart, paymentMethod);
|
|
45
|
+
expect(result.status).toBe('confirmed');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// BAD: implementation detail — breaks on refactor, catches nothing real
|
|
49
|
+
test('checkout calls paymentService.process', async () => {
|
|
50
|
+
const mockPayment = mock(paymentService);
|
|
51
|
+
await checkout(cart, payment);
|
|
52
|
+
expect(mockPayment.process).toHaveBeenCalledWith(cart.total);
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Seams — where tests go
|
|
57
|
+
|
|
58
|
+
A **seam** is the public boundary you test at: the interface where you
|
|
59
|
+
observe behavior without reaching inside. Tests live at seams, never against
|
|
60
|
+
internals. Before writing any test, write down the seams under test — the
|
|
61
|
+
task's acceptance criteria usually name them. Testing effort goes to critical
|
|
62
|
+
paths and complex logic, not every edge case.
|
|
63
|
+
|
|
64
|
+
Mock **only at external seams** (network, clock, filesystem, third-party
|
|
65
|
+
APIs) — never mock your own internal collaborators.
|
|
66
|
+
|
|
67
|
+
## Anti-patterns
|
|
68
|
+
|
|
69
|
+
- **Implementation-coupled** — mocks internal collaborators, tests private
|
|
70
|
+
methods, or verifies through a side channel (querying the database instead
|
|
71
|
+
of using the interface). Tell: the test breaks when you refactor but
|
|
72
|
+
behavior hasn't changed.
|
|
73
|
+
- **Tautological** — the assertion recomputes the expected value the way the
|
|
74
|
+
code does (`expect(add(a, b)).toBe(a + b)`), so it passes by construction.
|
|
75
|
+
Expected values must come from an independent source of truth — a
|
|
76
|
+
known-good literal, a worked example, the spec.
|
|
77
|
+
- **Horizontal slicing** — writing all tests first, then all implementation.
|
|
78
|
+
Bulk tests verify *imagined* behavior. Work in **vertical slices**: one
|
|
79
|
+
test → one implementation → repeat, each test a tracer bullet that responds
|
|
80
|
+
to what the last cycle taught you.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: testing-infra
|
|
3
|
+
description: Test infrastructure — fixtures, isolation, flaky-test policy, CI hygiene, coverage sanity
|
|
4
|
+
tags: [test, testing, fixture, ci, flaky, coverage, mock, isolation, pipeline, suite]
|
|
5
|
+
when: task sets up test tooling, fixtures, CI, or fights slow/flaky suites
|
|
6
|
+
phases: [build, verify]
|
|
7
|
+
provenance: { origin: built-in }
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Testing Infrastructure
|
|
11
|
+
|
|
12
|
+
(`tdd.md` covers what a good test IS; this covers the machinery around them.)
|
|
13
|
+
|
|
14
|
+
## Rules
|
|
15
|
+
|
|
16
|
+
- **Tests are order-independent and parallel-safe.** Each test creates its
|
|
17
|
+
own data and cleans up (or runs in a transaction rolled back / fresh
|
|
18
|
+
tmpdir). If running one test alone changes its result, the suite is
|
|
19
|
+
broken even while green.
|
|
20
|
+
- **Fixtures are builders, not blobs.** `makeUser({overrides})` beats a
|
|
21
|
+
500-line fixtures.json — tests state only what matters, defaults carry
|
|
22
|
+
the rest, schema changes touch one builder.
|
|
23
|
+
- **Determinism is manufactured:** pin the clock (fake timers), seed RNG,
|
|
24
|
+
freeze network (record/replay or fakes at the seam), isolate filesystem
|
|
25
|
+
(tmpdir per test). Anything you didn't pin will flake at 2am.
|
|
26
|
+
- **Flaky-test policy — zero tolerance:** a flaky test is a P1 against the
|
|
27
|
+
suite. Quarantine it the day it flakes (skip with a linked issue),
|
|
28
|
+
diagnose with `diagnosing-bugs.md` (usually: unpinned time, shared
|
|
29
|
+
state, real network, race). A retried-until-green suite verifies nothing.
|
|
30
|
+
- **The pyramid is a budget:** many fast unit/integration tests at seams,
|
|
31
|
+
few end-to-end smoke tests. E2E for "the wiring works", not for every
|
|
32
|
+
edge case — edges belong at the seam where they live.
|
|
33
|
+
- **CI runs what developers run:** same command (`npm test`), same
|
|
34
|
+
versions, fresh checkout, no network by default. "Works locally" bugs
|
|
35
|
+
are environment drift — fix the environment, not the test.
|
|
36
|
+
- **Coverage is a smoke detector, not a target.** Use it to FIND untested
|
|
37
|
+
branches; never write assertion-free tests to move the number. The
|
|
38
|
+
gate's threshold is a floor, not a goal.
|
|
39
|
+
|
|
40
|
+
## Anti-patterns
|
|
41
|
+
|
|
42
|
+
- **Shared mutable fixtures** ("the test database user") → per-test data
|
|
43
|
+
with unique keys; suites die by a thousand shared rows.
|
|
44
|
+
- **Sleeping to wait** (`sleep 2` then assert) → poll with timeout or
|
|
45
|
+
await the actual signal; sleeps are both slow AND flaky.
|
|
46
|
+
- **Mocking the world** — suite passes while the app is down → integration
|
|
47
|
+
tests at real seams (real DB, real HTTP server in-process).
|
|
48
|
+
- **Snapshot everything** — giant snapshots nobody reads, updated with
|
|
49
|
+
`--update` reflexively → snapshot small, stable, reviewed outputs only.
|
|
50
|
+
|
|
51
|
+
## Checklist
|
|
52
|
+
|
|
53
|
+
- [ ] Any single test runs alone: same result
|
|
54
|
+
- [ ] Suite passes twice in a row AND with a different order/seed
|
|
55
|
+
- [ ] No real network/clock/RNG unpinned anywhere
|
|
56
|
+
- [ ] Flaky tests quarantined with linked issues (count: 0 is the goal)
|
|
57
|
+
- [ ] CI command identical to the local test command
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: writing-skills
|
|
3
|
+
description: How to author a skill worth keeping — scope, structure, frontmatter, quality bar
|
|
4
|
+
tags: [meta, skill, writing, author, documentation, checklist]
|
|
5
|
+
when: creating a new skill or adapting an acquired one
|
|
6
|
+
phases: []
|
|
7
|
+
provenance: { origin: "mattpocock/skills writing-great-skills", license: MIT, adapted: true }
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Writing Skills
|
|
11
|
+
|
|
12
|
+
A skill is a reusable instruction file that changes how the work gets done.
|
|
13
|
+
The test: **would a weak model do the right thing following ONLY this
|
|
14
|
+
file?** If not, it's not done.
|
|
15
|
+
|
|
16
|
+
## Rules
|
|
17
|
+
|
|
18
|
+
- **One job per skill.** "databases" not "backend-development". If you're
|
|
19
|
+
writing "and also…", split it.
|
|
20
|
+
- **Rules + anti-patterns + checklist** — that structure, every time.
|
|
21
|
+
Rules are imperative and checkable. Anti-patterns show what going wrong
|
|
22
|
+
looks like AND the fix. The checklist is how the reader verifies they
|
|
23
|
+
applied it.
|
|
24
|
+
- **≤120 lines of body.** Longer means it's two skills or it's a tutorial.
|
|
25
|
+
- **Concrete over abstract.** One short example beats three paragraphs of
|
|
26
|
+
principle. Name real commands, real file paths, real error messages.
|
|
27
|
+
- **Frontmatter required** (the matcher is blind without it):
|
|
28
|
+
|
|
29
|
+
```yaml
|
|
30
|
+
---
|
|
31
|
+
name: kebab-case-name
|
|
32
|
+
description: One line, 10-300 chars — what this teaches
|
|
33
|
+
tags: [five, or, more, search, keywords] # ≥3 required; think "what words appear in tasks that need this?"
|
|
34
|
+
when: the task signal that should trigger this skill
|
|
35
|
+
phases: [build] # optional phase affinity
|
|
36
|
+
provenance: { origin: self-authored, authoredBy: agent }
|
|
37
|
+
---
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Frontmatter uses a strict subset: `key: value`, `key: [a, b]`,
|
|
41
|
+
`key: { k: v }` — no multiline YAML.
|
|
42
|
+
|
|
43
|
+
- **Tag for the matcher.** Tags are matched against task text — use the
|
|
44
|
+
nouns a task description would actually contain ("postgres", "auth",
|
|
45
|
+
"migration"), not categories ("backend").
|
|
46
|
+
|
|
47
|
+
## Anti-patterns
|
|
48
|
+
|
|
49
|
+
- **The essay** — background, history, philosophy. Delete everything that
|
|
50
|
+
doesn't change what the reader does next.
|
|
51
|
+
- **The mirror** — restating what the harness already enforces (gates,
|
|
52
|
+
phases). Skills teach craft, not process.
|
|
53
|
+
- **The wishlist** — "consider…", "you might…". Skills say DO and DON'T.
|
|
54
|
+
|
|
55
|
+
## Checklist
|
|
56
|
+
|
|
57
|
+
- [ ] Frontmatter passes: `infinity-harness capability add skill <path>` (it validates)
|
|
58
|
+
- [ ] A cold reader knows exactly what to do and how to check they did it
|
|
59
|
+
- [ ] Every rule is checkable; every anti-pattern has a fix
|
|
60
|
+
- [ ] Attribution line present if adapted from elsewhere
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "infinity-harness",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "A pi agent extension that runs a gated build pipeline unattended \u2014 enforces phases, validates with deterministic gates, and keeps working for hours or days without losing the plan.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"pi-package",
|
|
8
|
+
"pi-extension",
|
|
9
|
+
"harness",
|
|
10
|
+
"agent-pipeline",
|
|
11
|
+
"autonomous",
|
|
12
|
+
"continuous-development"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"author": "Bakr Bagaber",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/bakr-bagaber/infinity-harness.git"
|
|
19
|
+
},
|
|
20
|
+
"pi": {
|
|
21
|
+
"extensions": [
|
|
22
|
+
"./extensions"
|
|
23
|
+
],
|
|
24
|
+
"skills": [
|
|
25
|
+
"./harness/skills"
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"extensions/",
|
|
30
|
+
"src/",
|
|
31
|
+
"types/",
|
|
32
|
+
"harness/skills/",
|
|
33
|
+
"harness/docs/",
|
|
34
|
+
"harness/model-router.json",
|
|
35
|
+
"README.md",
|
|
36
|
+
"LICENSE",
|
|
37
|
+
"CHANGELOG.md"
|
|
38
|
+
],
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=22.0.0"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"proper-lockfile": "^4.1.2",
|
|
44
|
+
"string-width": "^7.1.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
48
|
+
"@types/node": "^22.0.0",
|
|
49
|
+
"typescript": "^5.5.0"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"test": "node scripts/run-tests.mjs",
|
|
53
|
+
"check": "tsc --noEmit",
|
|
54
|
+
"build": "tsc --noEmit",
|
|
55
|
+
"e2e": "node scripts/e2e.mjs"
|
|
56
|
+
},
|
|
57
|
+
"homepage": "https://github.com/bakr-bagaber/infinity-harness#readme",
|
|
58
|
+
"bugs": {
|
|
59
|
+
"url": "https://github.com/bakr-bagaber/infinity-harness/issues"
|
|
60
|
+
}
|
|
61
|
+
}
|