infinity-harness 2.0.0 → 2.0.2

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.
Files changed (48) hide show
  1. package/CHANGELOG.md +95 -4
  2. package/README.md +30 -3
  3. package/harness/docs/ARCHITECTURE.md +1 -1
  4. package/harness/docs/agents/generator.md +1 -1
  5. package/harness/docs/agents/simplifier.md +1 -1
  6. package/harness/docs/phases/build.md +6 -6
  7. package/harness/docs/phases/define.md +4 -4
  8. package/harness/docs/phases/plan.md +4 -4
  9. package/harness/docs/phases/review.md +5 -5
  10. package/harness/docs/phases/ship.md +5 -5
  11. package/harness/docs/phases/simplify.md +6 -6
  12. package/harness/docs/phases/verify.md +6 -6
  13. package/harness/docs/skills.md +89 -0
  14. package/harness/skills/auth-security.md +1 -0
  15. package/harness/skills/building-tools.md +35 -39
  16. package/harness/skills/capability-acquisition.md +51 -48
  17. package/harness/skills/cli-design.md +3 -3
  18. package/harness/skills/code-review.md +1 -0
  19. package/harness/skills/codebase-design.md +1 -0
  20. package/harness/skills/concurrency-async.md +1 -0
  21. package/harness/skills/config-and-secrets.md +1 -0
  22. package/harness/skills/context-hygiene.md +1 -0
  23. package/harness/skills/databases.md +1 -0
  24. package/harness/skills/diagnosing-bugs.md +1 -0
  25. package/harness/skills/domain-modeling.md +1 -0
  26. package/harness/skills/error-handling-logging.md +1 -0
  27. package/harness/skills/frontend-ui.md +1 -0
  28. package/harness/skills/grilling.md +1 -0
  29. package/harness/skills/http-apis.md +1 -0
  30. package/harness/skills/performance.md +1 -0
  31. package/harness/skills/pi-todo-adapted.md +1 -0
  32. package/harness/skills/planning-tasks.md +1 -0
  33. package/harness/skills/prototype.md +2 -1
  34. package/harness/skills/research.md +1 -0
  35. package/harness/skills/resolving-merge-conflicts.md +2 -1
  36. package/harness/skills/scope-discipline.md +1 -0
  37. package/harness/skills/self-review.md +1 -0
  38. package/harness/skills/stuck-protocol.md +2 -1
  39. package/harness/skills/tdd.md +1 -0
  40. package/harness/skills/testing-infra.md +1 -0
  41. package/harness/skills/writing-skills.md +2 -1
  42. package/package.json +1 -1
  43. package/src/core/brief.ts +57 -2
  44. package/src/core/skills.ts +386 -0
  45. package/src/core/skillsAudit.ts +223 -0
  46. package/src/core/types.ts +2 -0
  47. package/harness/skills/README.md +0 -60
  48. package/harness/skills/building-mcp-servers.md +0 -70
@@ -1,72 +1,75 @@
1
1
  ---
2
2
  name: capability-acquisition
3
- description: The capability ladder — HAVE, ACQUIRE, CREATE, KEEP — for skills, MCP servers, and tools
4
- tags: [meta, capability, acquire, search, skill, mcp, tool, ladder, library]
5
- when: a task needs knowledge, system access, or an executable the project lacks
3
+ description: The capability ladder — HAVE, ACQUIRE, CREATE, KEEP — for skills, extensions and project scripts
4
+ tags: [meta, capability, acquire, search, skill, extension, tool, script, ladder, library]
5
+ when: a task needs knowledge, an integration, or an executable the project lacks
6
6
  phases: []
7
+ kind: meta
7
8
  provenance: { origin: built-in }
8
9
  ---
9
10
 
10
11
  # Capability Acquisition — The Ladder
11
12
 
12
- Your task needs something the library lacks. Resolve it with the ladder
13
- and register what you find so the NEXT task starts at Tier 0.
13
+ The task needs something you do not have. Work the ladder in order, and leave
14
+ the result behind so the next task starts one rung higher.
14
15
 
15
- ## Step 1 Decide the capability TYPE
16
+ pi has three kinds of capability. Pick the right shape first — most wasted
17
+ effort here is building the wrong one.
16
18
 
17
- - Need **knowledge or method** (how to do X well) → a **skill**
18
- - Need to **interact with an external system** (DB, API, browser, tracker) → an **MCP server**
19
- - Need a **repeatable executable action** (reset fixtures, run a codemod) a **tool**
20
- - Need a **fact** (does API X support Y?) follow `research.md` findings
21
- saved under `docs/research/` with frontmatter become matchable facts
19
+ | You need | Build | Lives in |
20
+ |---|---|---|
21
+ | Knowledge or method how to do X well | a **skill** | `.pi/skills/<name>.md` |
22
+ | A repeatable action — reset fixtures, run a codemod | a **script** | the repo, run through bash |
23
+ | A tool the model can call, or a slash command | an **extension** | its own package, `pi install`ed |
24
+ | A fact — does API X support Y? | neither | `research.md`, written into `harness/docs/` |
22
25
 
23
- ## Step 2 ACQUIRE: search the sources
26
+ ## 1HAVE: check before you build
24
27
 
25
- ```
26
- the capability index "<2-4 keywords>" --type skill|mcp|tool
27
- ```
28
+ - **Skills already loaded.** This package ships 28. The brief names the ones
29
+ that match the current task; `/skill:<name>` invokes any of them.
30
+ - **Scripts already in the repo.** `package.json` scripts, `Makefile`,
31
+ `scripts/`. Read before you write — the thing you are about to build is
32
+ often already there under a name you did not guess.
33
+ - **Extensions already installed.** `pi list`.
28
34
 
29
- This queries the machine-queryable registries directly (npm, MCP registry,
30
- GitHub, crates, …). Browse-only sources are listed after — use them only
31
- if you have web access.
35
+ ## 2 ACQUIRE: take what exists
32
36
 
33
- **Choosing among hits** (in order): trust tier (official > curated >
34
- community) actively maintained widely used known author
35
- permissive license (MIT/Apache/BSD) small and composable. NEVER adopt a
36
- framework that wants to own your whole process the harness owns the
37
- process.
37
+ - **A skill** is plain markdown. Copy one in, then *adapt* it: trim to the
38
+ useful core, re-point its references at this project's surfaces, and add an
39
+ attribution line naming the source and its licence.
40
+ - **An extension**: `pi install npm:<pkg> -l` (project-local, so the team gets
41
+ it through `.pi/settings.json`) or `pi install git:<host>/<repo>`. Pin the
42
+ version, and read what it registers before you trust it.
38
43
 
39
- **Adapt, don't adopt.** Whatever you take: trim it to the useful core,
40
- re-point references to harness surfaces (DOMAIN.md, feature-list,
41
- learn/decision), add an attribution line (source + license), then register:
44
+ **Choosing among candidates**, in order: actively maintained widely used
45
+ permissive licence (MIT/Apache/BSD) small and composable. Never adopt
46
+ something that wants to own the whole process the harness owns the process.
42
47
 
43
- ```
44
- infinity-harness capability add skill <path> --from <url>
45
- infinity-harness capability add mcp <name> --command npx --args -y,<pkg>@<exact-version> \
46
- --tags ... --description "..." --trust curated
47
- infinity-harness capability add tool <file> --run "..." --tags ... --description "..."
48
- ```
48
+ ## 3 — CREATE: nothing usable exists
49
49
 
50
- **MCP security (hard rules):** pin exact versions (`pkg@1.2.3`, never
51
- `@latest`); community-tier servers need `--force` after you review their
52
- source; secrets go through env indirection, never into configs.
50
+ - **A skill** write it per `writing-skills.md` into `.pi/skills/<name>.md`.
51
+ pi loads it on the next start. There is nothing to register.
52
+ - **A script** build it per `building-tools.md`, and name it where a cold
53
+ reader will look (`AGENTS.md`, or `package.json` scripts).
54
+ - **An extension** → only when the capability has to be a tool the model calls
55
+ or a slash command. It is a package with a `pi.extensions` entry;
56
+ `pi install ./<dir> -l` loads it straight from a checkout.
53
57
 
54
- ## Step 3 CREATE: nothing usable exists
58
+ ## 4KEEP: or you will do this again
55
59
 
56
- ```
57
- infinity-harness capability create skill|tool|mcp <name>
58
- ```
60
+ A capability that lives only in this session is not a capability.
59
61
 
60
- - skill fill the stub per `writing-skills.md`
61
- - tool → implement per `building-tools.md`
62
- - mcp the scaffold is a WORKING server; fill in handlers per
63
- `building-mcp-servers.md`, verify with its self-test, then register
62
+ - **Commit it.** A skill in `.pi/skills/` and a script in the repo both travel
63
+ with the project.
64
+ - **Make it findable.** Tags in a skill's frontmatter are how the brief
65
+ surfaces it later; a script nobody can find is a script nobody runs.
64
66
 
65
- ## Step 4 — Budget and fallback (never block the pipeline)
67
+ ## 5 — Budget: never block the pipeline
66
68
 
67
- Acquisition fits ONE working session. If the search didn't conclude, or you
69
+ Acquisition fits inside one working session. If it does not conclude, or you
68
70
  have no network:
69
71
 
70
- 1. Record the gap: `harness/lessons-decisions.md "capability gap: <what was needed>"`
71
- 2. Proceed with general best practices — a missing skill is not a blocked task
72
- 3. The gap resurfaces via `infinity-harness capability gaps` for a later pass
72
+ 1. Record the gap in `harness/lessons-decisions.md` what was needed, what
73
+ you tried, what you would try next.
74
+ 2. Carry on with general best practice. A missing skill is not a blocked task,
75
+ and it is never a reason to mark work complete that is not.
@@ -4,6 +4,7 @@ description: Command-line tool design — argument conventions, output contracts
4
4
  tags: [cli, command, terminal, flags, arguments, stdout, stdin, shell, script, tool]
5
5
  when: task builds or extends a command-line interface
6
6
  phases: [plan, build]
7
+ kind: domain
7
8
  provenance: { origin: built-in }
8
9
  ---
9
10
 
@@ -30,9 +31,8 @@ provenance: { origin: built-in }
30
31
  consistently; flags kebab-case with `--long` forms; `-` means stdin/
31
32
  stdout where files are expected; respect `NO_COLOR` and non-TTY (no
32
33
  spinners into pipes).
33
- - **Errors say what + why + what next:** `✗ config not found:
34
- harness/config.json — run: infinity-harness init`. Never a bare stack trace
35
- for an expected failure.
34
+ - **Errors say what + why + what next:** `✗ config not found: ./app.config.json
35
+ — run: myapp init`. Never a bare stack trace for an expected failure.
36
36
  - **Fast startup matters.** A CLI invoked in loops pays its startup cost
37
37
  ×N — lazy-load heavy imports per subcommand.
38
38
 
@@ -4,6 +4,7 @@ description: Two-axis review (spec fidelity + standards/smells) with the Fowler
4
4
  tags: [review, quality, smell, refactor, standards, spec, diff, audit]
5
5
  when: reviewing a diff, a branch, or the whole delivery before shipping
6
6
  phases: [review, simplify]
7
+ kind: process
7
8
  provenance: { origin: "mattpocock/skills", license: MIT, adapted: true }
8
9
  ---
9
10
 
@@ -4,6 +4,7 @@ description: Deep modules — small interfaces hiding lots of behavior, seams, t
4
4
  tags: [design, architecture, module, interface, seam, refactor, coupling, abstraction, api]
5
5
  when: designing module boundaries, planning features, refactoring for clarity
6
6
  phases: [plan, simplify]
7
+ kind: process
7
8
  provenance: { origin: "mattpocock/skills", license: MIT, adapted: true }
8
9
  ---
9
10
 
@@ -4,6 +4,7 @@ description: Concurrency and async correctness — races, idempotency, queues, c
4
4
  tags: [concurrency, async, race, parallel, queue, lock, mutex, retry, idempotent, worker, thread, promise, deadlock, atomic]
5
5
  when: task involves parallel work, background jobs, shared state, or retried operations
6
6
  phases: [plan, build, verify]
7
+ kind: domain
7
8
  provenance: { origin: built-in }
8
9
  ---
9
10
 
@@ -4,6 +4,7 @@ description: Configuration discipline — env-driven config, validation at boot,
4
4
  tags: [config, configuration, environment, env, secret, settings, deploy, dotenv, variable]
5
5
  when: task adds configuration, environment handling, or deployment settings
6
6
  phases: [build, ship]
7
+ kind: domain
7
8
  provenance: { origin: built-in }
8
9
  ---
9
10
 
@@ -4,6 +4,7 @@ description: Externalize state before it decays — write discoveries down, re-r
4
4
  tags: [meta, context, memory, handoff, session, notes, playbook]
5
5
  when: any long session, and always before ending one
6
6
  phases: []
7
+ kind: process
7
8
  provenance: { origin: built-in, notes: frontier-playbook }
8
9
  ---
9
10
 
@@ -4,6 +4,7 @@ description: Relational database craft — schema design, migrations, transactio
4
4
  tags: [database, db, sql, postgres, postgresql, mysql, sqlite, schema, migration, transaction, index, query, orm, persistence, storage]
5
5
  when: task touches persistent data, schemas, queries, or migrations
6
6
  phases: [plan, build, verify]
7
+ kind: domain
7
8
  provenance: { origin: built-in }
8
9
  ---
9
10
 
@@ -4,6 +4,7 @@ description: Feedback-loop-first debugging discipline for hard bugs and regressi
4
4
  tags: [debug, debugging, bug, error, failure, crash, flaky, slow, performance, regression, bisect]
5
5
  when: something is broken, throwing, failing intermittently, or slow
6
6
  phases: [verify, build]
7
+ kind: process
7
8
  provenance: { origin: "mattpocock/skills", license: MIT, adapted: true }
8
9
  ---
9
10
 
@@ -4,6 +4,7 @@ description: Pin down domain terminology — glossary discipline and decision re
4
4
  tags: [domain, glossary, terminology, naming, model, ubiquitous, language, adr, decision]
5
5
  when: defining specs, resolving fuzzy or conflicting terms, recording decisions
6
6
  phases: [define, plan]
7
+ kind: process
7
8
  provenance: { origin: "mattpocock/skills", license: MIT, adapted: true }
8
9
  ---
9
10
 
@@ -4,6 +4,7 @@ description: Error taxonomy, fail-loud handling, structured logging that debugs
4
4
  tags: [error, exception, logging, log, observability, retry, crash, handling, monitoring, trace]
5
5
  when: task defines error paths, adds logging, or hardens failure behavior
6
6
  phases: [build, verify]
7
+ kind: domain
7
8
  provenance: { origin: built-in }
8
9
  ---
9
10
 
@@ -4,6 +4,7 @@ description: Frontend craft — state discipline, componentization, accessibilit
4
4
  tags: [frontend, ui, component, react, vue, svelte, state, form, accessibility, a11y, css, browser, render]
5
5
  when: task builds or changes user interface
6
6
  phases: [plan, build]
7
+ kind: domain
7
8
  provenance: { origin: built-in }
8
9
  ---
9
10
 
@@ -4,6 +4,7 @@ description: Stress-test a spec or plan with relentless one-at-a-time questions
4
4
  tags: [grill, spec, requirements, questions, stress, interview, scope, clarify]
5
5
  when: before proposing the sprint contract, or when a plan feels underspecified
6
6
  phases: [define]
7
+ kind: process
7
8
  provenance: { origin: "mattpocock/skills", license: MIT, adapted: true }
8
9
  ---
9
10
 
@@ -4,6 +4,7 @@ description: HTTP/REST API design — resources, status codes, errors, versionin
4
4
  tags: [api, http, rest, endpoint, route, json, status, error, versioning, pagination, webhook, request, response]
5
5
  when: task designs or implements HTTP endpoints or consumes external APIs
6
6
  phases: [plan, build]
7
+ kind: domain
7
8
  provenance: { origin: built-in }
8
9
  ---
9
10
 
@@ -4,6 +4,7 @@ description: Performance work — measure first, fix the biggest cost, cache wit
4
4
  tags: [performance, slow, latency, profiling, optimize, cache, memory, benchmark, throughput, speed]
5
5
  when: something is slow, memory-hungry, or a task sets performance targets
6
6
  phases: [verify, build]
7
+ kind: domain
7
8
  provenance: { origin: built-in }
8
9
  ---
9
10
 
@@ -4,6 +4,7 @@ description: "Atomic infinity_plan pattern with omission deletion, baseRevision
4
4
  tags: [harness, pi-todo, atomic, baseRevision, omission, deletion, compaction, widget, task-list, dependency]
5
5
  when: "implementing infinity_plan, atomic revisioning, Pi widget with session persistence or task dependencies"
6
6
  phases: [build, verify]
7
+ kind: domain
7
8
  provenance: { origin: "https://github.com/99percentpeople/pi-extensions", license: MIT, adapted: true, url: "https://github.com/99percentpeople/pi-extensions", contentHash: abf626df6a74a6fb }
8
9
  ---
9
10
 
@@ -4,6 +4,7 @@ description: Break specs into tracer-bullet vertical slices with checkable accep
4
4
  tags: [plan, planning, slice, ticket, decompose, criteria, backlog, breakdown, refactor]
5
5
  when: writing or restructuring the feature list from a spec
6
6
  phases: [plan]
7
+ kind: process
7
8
  provenance: { origin: "mattpocock/skills", license: MIT, adapted: true }
8
9
  ---
9
10
 
@@ -3,7 +3,8 @@ name: prototype
3
3
  description: Throwaway code that answers a design question fast, then gets deleted
4
4
  tags: [prototype, spike, experiment, explore, poc, throwaway, design]
5
5
  when: a state model, logic shape, or UI direction cannot be judged on paper
6
- phases: [build, plan]
6
+ phases: [plan, build]
7
+ kind: process
7
8
  provenance: { origin: "mattpocock/skills", license: MIT, adapted: true }
8
9
  ---
9
10
 
@@ -4,6 +4,7 @@ description: Answer factual questions from primary sources; capture cited findin
4
4
  tags: [research, docs, documentation, investigate, source, facts, api, spec, evidence]
5
5
  when: a factual question about an API, library, protocol, or tool blocks progress
6
6
  phases: [define, plan, build]
7
+ kind: process
7
8
  provenance: { origin: "mattpocock/skills", license: MIT, adapted: true }
8
9
  ---
9
10
 
@@ -4,6 +4,7 @@ description: Resolve git merge/rebase conflicts by original intent, verify, and
4
4
  tags: [git, merge, rebase, conflict, branch, hunk]
5
5
  when: an in-progress git merge or rebase has conflicting hunks
6
6
  phases: []
7
+ kind: process
7
8
  provenance: { origin: "mattpocock/skills", license: MIT, adapted: true }
8
9
  ---
9
10
 
@@ -23,7 +24,7 @@ provenance: { origin: "mattpocock/skills", license: MIT, adapted: true }
23
24
  trade-off. Do **not** invent new behaviour. Always resolve; never
24
25
  `--abort`.
25
26
  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
+ lint (`infinity_validate` runs the configured set). Fix anything the
27
28
  merge broke.
28
29
  5. **Finish the merge/rebase.** Stage everything and commit. If rebasing,
29
30
  continue until all commits are rebased. Record anything surprising:
@@ -4,6 +4,7 @@ description: The contract is the boundary — park ideas, resist drive-by fixes,
4
4
  tags: [meta, scope, creep, contract, focus, discipline, playbook]
5
5
  when: mid-task ideas, adjacent problems, or "while I'm here" temptations appear
6
6
  phases: []
7
+ kind: process
7
8
  provenance: { origin: built-in, notes: frontier-playbook }
8
9
  ---
9
10
 
@@ -4,6 +4,7 @@ description: Structured pass before claiming done — criteria re-check, real ru
4
4
  tags: [meta, review, verify, done, quality, check, playbook]
5
5
  when: before running validate on any task — every time
6
6
  phases: [build, verify, simplify]
7
+ kind: process
7
8
  provenance: { origin: built-in, notes: frontier-playbook }
8
9
  ---
9
10
 
@@ -4,6 +4,7 @@ description: What to do after repeated failures — stop, write down, reframe on
4
4
  tags: [meta, stuck, retry, failure, escalate, blocked, playbook]
5
5
  when: the same step has failed 2-3 times, or you notice you are looping
6
6
  phases: []
7
+ kind: process
7
8
  provenance: { origin: built-in, notes: frontier-playbook }
8
9
  ---
9
10
 
@@ -28,7 +29,7 @@ catch any of these tells:
28
29
  what you're trying to achieve, the exact error/failure, the attempts
29
30
  made, and what each attempt ruled out. Writing this usually exposes the
30
31
  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
+ 2. **Re-read the brief and the skill** (`infinity_brief`; the skill it
32
33
  references). Stuck often means a constraint was missed, not that the
33
34
  problem is hard.
34
35
  3. **Reframe ONCE** — one genuinely different angle, not a variation:
@@ -4,6 +4,7 @@ description: Red → green test-driven loop — what a good test is, seams, anti
4
4
  tags: [tdd, test, testing, unit, integration, red-green, seam, mock, coverage]
5
5
  when: implementing any BUILD task, or fixing a bug that needs a regression test
6
6
  phases: [build, verify]
7
+ kind: process
7
8
  provenance: { origin: "mattpocock/skills", license: MIT, adapted: true }
8
9
  ---
9
10
 
@@ -4,6 +4,7 @@ description: Test infrastructure — fixtures, isolation, flaky-test policy, CI
4
4
  tags: [test, testing, fixture, ci, flaky, coverage, mock, isolation, pipeline, suite]
5
5
  when: task sets up test tooling, fixtures, CI, or fights slow/flaky suites
6
6
  phases: [build, verify]
7
+ kind: domain
7
8
  provenance: { origin: built-in }
8
9
  ---
9
10
 
@@ -4,6 +4,7 @@ description: How to author a skill worth keeping — scope, structure, frontmatt
4
4
  tags: [meta, skill, writing, author, documentation, checklist]
5
5
  when: creating a new skill or adapting an acquired one
6
6
  phases: []
7
+ kind: meta
7
8
  provenance: { origin: "mattpocock/skills writing-great-skills", license: MIT, adapted: true }
8
9
  ---
9
10
 
@@ -54,7 +55,7 @@ Frontmatter uses a strict subset: `key: value`, `key: [a, b]`,
54
55
 
55
56
  ## Checklist
56
57
 
57
- - [ ] Frontmatter passes: `infinity-harness capability add skill <path>` (it validates)
58
+ - [ ] Frontmatter is complete: `name` matching the filename, `description`, `kind`, `tags`, `when`, `phases`
58
59
  - [ ] A cold reader knows exactly what to do and how to check they did it
59
60
  - [ ] Every rule is checkable; every anti-pattern has a fix
60
61
  - [ ] Attribution line present if adapted from elsewhere
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "infinity-harness",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
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
5
  "type": "module",
6
6
  "keywords": [
package/src/core/brief.ts CHANGED
@@ -22,6 +22,23 @@ import { runChecks } from "./gates.ts";
22
22
  import { getPhaseOrder, nextPhase, isFinalPhase } from "./phases.ts";
23
23
  import * as P from "./paths.ts";
24
24
  import { readText } from "./fsx.ts";
25
+ import { loadSkills, matchSkills } from "./skills.ts";
26
+
27
+ /**
28
+ * What the agent calls to have its work judged.
29
+ *
30
+ * This said `harness validate` for a long time — a command line that has not
31
+ * existed since the CLI was ported into `src/`. A brief that ends by telling
32
+ * the model to run a command that does not exist is a brief that ends in a
33
+ * failed shell call and a confused retry, every single turn.
34
+ */
35
+ const VALIDATE_TOOL = "infinity_validate";
36
+
37
+ /**
38
+ * Two is the number that gets read. One hides a better match; five is a
39
+ * reading list, and a reading list is a thing you skip.
40
+ */
41
+ const SKILL_SUGGESTIONS = 2;
25
42
 
26
43
  const PHASE_INTENT: Record<Phase, string> = {
27
44
  init: "Set up the project skeleton and confirm the harness can see it.",
@@ -88,7 +105,7 @@ export async function buildBrief(targetDir: string, options: BuildBriefOptions =
88
105
  }
89
106
  : null,
90
107
  criteria: collectCriteria(feature, nextTask?.criteria),
91
- validateCommand: "harness validate",
108
+ validateCommand: VALIDATE_TOOL,
92
109
  gate,
93
110
  progress: {
94
111
  tasksDone: progress.tasksDone,
@@ -102,10 +119,39 @@ export async function buildBrief(targetDir: string, options: BuildBriefOptions =
102
119
  phase: config.phaseRetryCount ?? 0,
103
120
  max: retry.tasks.max,
104
121
  },
122
+ skills: suggestSkills(phase, {
123
+ goal: (list.goals ?? [])[0]?.title ?? null,
124
+ feature: feature?.name ?? null,
125
+ task: nextTask?.description ?? null,
126
+ criteria: collectCriteria(feature, nextTask?.criteria),
127
+ }),
105
128
  notes,
106
129
  };
107
130
  }
108
131
 
132
+ /**
133
+ * Which craft skills to point at, given what is being worked on.
134
+ *
135
+ * The skills ship with the package, so this works in an install with no
136
+ * project-level setup. If they are missing — someone vendored `src/` alone —
137
+ * the brief simply has no SKILLS section rather than failing to build.
138
+ */
139
+ function suggestSkills(
140
+ phase: Phase | null,
141
+ work: { goal: string | null; feature: string | null; task: string | null; criteria: string[] },
142
+ ): Brief["skills"] {
143
+ const text = [work.task, work.feature, work.goal, ...work.criteria].filter(Boolean).join(" \n ");
144
+ try {
145
+ return matchSkills(loadSkills(), { phase, text, limit: SKILL_SUGGESTIONS }).map((m) => ({
146
+ name: m.skill.name,
147
+ description: m.skill.description,
148
+ why: m.why,
149
+ }));
150
+ } catch {
151
+ return [];
152
+ }
153
+ }
154
+
109
155
  function collectCriteria(
110
156
  feature: { criteria?: string[] } | null,
111
157
  taskCriteria: string[] | undefined,
@@ -189,6 +235,15 @@ export function renderBrief(brief: Brief, config?: HarnessConfig): string {
189
235
  for (const c of brief.criteria) L.push(` - ${c}`);
190
236
  }
191
237
 
238
+ if (brief.skills.length) {
239
+ L.push("");
240
+ L.push("SKILLS read before you start — invoke by name");
241
+ for (const s of brief.skills) {
242
+ L.push(` - ${s.name} — ${s.description}`);
243
+ if (s.why) L.push(` (${s.why})`);
244
+ }
245
+ }
246
+
192
247
  if (brief.gate) {
193
248
  L.push("");
194
249
  L.push(`GATE ${brief.gate.overall ? "PASS" : "FAIL"}`);
@@ -207,7 +262,7 @@ export function renderBrief(brief: Brief, config?: HarnessConfig): string {
207
262
  L.push("");
208
263
  L.push("THE LOOP");
209
264
  L.push(" 1. Do the work described above.");
210
- L.push(` 2. Run: ${brief.validateCommand}`);
265
+ L.push(` 2. Call the ${brief.validateCommand} tool (a human types /infinity:validate).`);
211
266
  L.push(" 3. FAIL → fix the listed checks and validate again.");
212
267
  L.push(" 4. PASS → the harness advances the phase and issues the next brief.");
213
268
  L.push("");