@yemi33/minions 0.1.2370 → 0.1.2372
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/bin/minions.js +38 -11
- package/dashboard/js/render-other.js +2 -30
- package/dashboard/js/render-work-items.js +0 -34
- package/dashboard/js/settings.js +12 -27
- package/dashboard/pages/tools.html +1 -1
- package/dashboard.js +80 -257
- package/docs/README.md +2 -3
- package/docs/architecture.excalidraw +2 -2
- package/docs/auto-discovery.md +3 -3
- package/docs/completion-reports.md +0 -121
- package/docs/copilot-cli-schema.md +9 -17
- package/docs/deprecated.json +0 -51
- package/docs/design-state-storage.md +4 -4
- package/docs/harness-propagation.md +33 -263
- package/docs/human-vs-automated.md +1 -1
- package/docs/named-agents.md +0 -2
- package/docs/plan-lifecycle.md +5 -6
- package/docs/qa-runbook-lifecycle.md +10 -25
- package/docs/shared-lifecycle-module-map.md +2 -10
- package/engine/ado-comment.js +5 -11
- package/engine/ado.js +10 -5
- package/engine/cleanup.js +16 -36
- package/engine/cli.js +13 -175
- package/engine/comment-format.js +8 -182
- package/engine/db/index.js +60 -10
- package/engine/db/migrations/018-sql-only-cutover.js +56 -0
- package/engine/dispatch-store.js +0 -114
- package/engine/dispatch.js +1 -6
- package/engine/gh-comment.js +2 -10
- package/engine/github.js +8 -6
- package/engine/lifecycle.js +58 -173
- package/engine/llm.js +9 -11
- package/engine/managed-spawn.js +1 -6
- package/engine/memory-store.js +8 -6
- package/engine/metrics-store.js +4 -128
- package/engine/pipeline.js +4 -7
- package/engine/playbook.js +8 -196
- package/engine/prd-store.js +115 -141
- package/engine/preflight.js +8 -55
- package/engine/projects.js +34 -41
- package/engine/pull-requests-store.js +9 -234
- package/engine/qa-runs.js +4 -15
- package/engine/qa-sessions.js +5 -17
- package/engine/queries.js +23 -103
- package/engine/routing.js +1 -1
- package/engine/runtimes/claude.js +1 -2
- package/engine/runtimes/codex.js +0 -2
- package/engine/runtimes/copilot.js +1 -4
- package/engine/shared-branch-pr-reconcile.js +2 -5
- package/engine/shared.js +174 -533
- package/engine/small-state-store.js +12 -647
- package/engine/spawn-agent.js +5 -96
- package/engine/state-operations.js +166 -0
- package/engine/supervisor.js +0 -1
- package/engine/watch-actions.js +2 -3
- package/engine/watches-store.js +2 -128
- package/engine/work-items-store.js +3 -254
- package/engine.js +102 -334
- package/package.json +2 -2
- package/playbooks/build-fix-complex.md +0 -4
- package/playbooks/fix.md +0 -4
- package/playbooks/implement-shared.md +0 -4
- package/playbooks/implement.md +0 -4
- package/playbooks/plan-to-prd.md +16 -11
- package/playbooks/plan.md +0 -4
- package/playbooks/review.md +0 -6
- package/playbooks/shared-rules.md +0 -65
- package/docs/harness-transparency.md +0 -199
- package/docs/project-skills.md +0 -193
- package/engine/discover-project-skills.js +0 -673
- package/engine/playbook-intents.js +0 -76
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2372",
|
|
4
4
|
"description": "Multi-agent AI dev team that runs from ~/.minions/ — five autonomous agents share a single engine, dashboard, and knowledge base",
|
|
5
5
|
"bin": {
|
|
6
6
|
"minions": "bin/minions.js"
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"test:e2e:accept": "node test/playwright/accept-baseline.js",
|
|
30
30
|
"test:e2e:accept-force": "node test/playwright/accept-baseline.js --force",
|
|
31
31
|
"test:setup": "npx playwright install chromium",
|
|
32
|
-
"lint": "eslint dashboard/ engine
|
|
32
|
+
"lint": "eslint dashboard/ engine.js engine/ dashboard.js dashboard-build.js bin/"
|
|
33
33
|
},
|
|
34
34
|
"keywords": [
|
|
35
35
|
"ai",
|
|
@@ -76,10 +76,6 @@ Use subagents only for genuinely parallel, independent tasks (e.g., editing file
|
|
|
76
76
|
|
|
77
77
|
## Health Check
|
|
78
78
|
|
|
79
|
-
{{#project_skills_block}}
|
|
80
|
-
{{project_skills_block}}
|
|
81
|
-
|
|
82
|
-
{{/project_skills_block}}
|
|
83
79
|
Before starting work, run `git status` and verify the worktree is clean and on the expected branch (`{{pr_branch}}`). If the worktree is dirty or on the wrong branch, report the issue and stop.
|
|
84
80
|
|
|
85
81
|
## Validation
|
package/playbooks/fix.md
CHANGED
|
@@ -53,10 +53,6 @@ Before editing, split the feedback into:
|
|
|
53
53
|
|
|
54
54
|
## Health Check
|
|
55
55
|
|
|
56
|
-
{{#project_skills_block}}
|
|
57
|
-
{{project_skills_block}}
|
|
58
|
-
|
|
59
|
-
{{/project_skills_block}}
|
|
60
56
|
Before starting work, run `git status` and verify the worktree is clean and on the expected branch (`{{pr_branch}}`). If the worktree is dirty or on the wrong branch, report the issue and stop.
|
|
61
57
|
|
|
62
58
|
### Branch-mismatch guard (issue #2999)
|
|
@@ -45,10 +45,6 @@ Do ALL work in the worktree.
|
|
|
45
45
|
|
|
46
46
|
## Health Check
|
|
47
47
|
|
|
48
|
-
{{#project_skills_block}}
|
|
49
|
-
{{project_skills_block}}
|
|
50
|
-
|
|
51
|
-
{{/project_skills_block}}
|
|
52
48
|
Before starting work, run `git status` and verify the worktree is clean and on the expected branch (`{{branch_name}}`). If the worktree is dirty or on the wrong branch, report the issue and stop.
|
|
53
49
|
|
|
54
50
|
## Working Style
|
package/playbooks/implement.md
CHANGED
|
@@ -38,10 +38,6 @@ If this feature spans multiple projects, inspect the relevant repos, make change
|
|
|
38
38
|
|
|
39
39
|
## Health Check
|
|
40
40
|
|
|
41
|
-
{{#project_skills_block}}
|
|
42
|
-
{{project_skills_block}}
|
|
43
|
-
|
|
44
|
-
{{/project_skills_block}}
|
|
45
41
|
Before starting work, run `git status` and verify the worktree is clean and on the expected branch. If the worktree is dirty or on the wrong branch, report the issue and stop.
|
|
46
42
|
|
|
47
43
|
## Working Style
|
package/playbooks/plan-to-prd.md
CHANGED
|
@@ -19,10 +19,6 @@ A user has provided a plan. Analyze it against the codebase and produce a struct
|
|
|
19
19
|
|
|
20
20
|
## Instructions
|
|
21
21
|
|
|
22
|
-
{{#project_skills_block}}
|
|
23
|
-
{{project_skills_block}}
|
|
24
|
-
|
|
25
|
-
{{/project_skills_block}}
|
|
26
22
|
1. **Read the plan carefully** — understand the goals, scope, and requirements
|
|
27
23
|
- If the plan declares `Project: <name>` (including `**Project:** <name>`), the engine has resolved `{{project_name}}` from that declaration. Preserve `{{project_name}}` for the top-level `project`, default item `project`, filename, and implementation framing; do not let contextual mentions of another product or repository override it.
|
|
28
24
|
2. **Check for an existing PRD** — if the engine provides `existing_prd_json` below, a PRD already exists for this plan. See "Reusing an Existing PRD" section for how to preserve item IDs and done statuses. If no existing PRD is provided, this is a fresh run — all items start as `"missing"`.
|
|
@@ -35,11 +31,20 @@ A user has provided a plan. Analyze it against the codebase and produce a struct
|
|
|
35
31
|
|
|
36
32
|
## Output
|
|
37
33
|
|
|
38
|
-
Write the PRD to: `{{team_root}}/
|
|
34
|
+
Write the PRD result sidecar to: `{{team_root}}/agents/{{agent_id}}/prd-result.json`
|
|
35
|
+
|
|
36
|
+
The sidecar must be an envelope with the exact pre-generated filename:
|
|
39
37
|
|
|
40
|
-
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"filename": "{{prd_filename}}",
|
|
41
|
+
"prd": {
|
|
42
|
+
"...": "the PRD object described below"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
41
46
|
|
|
42
|
-
|
|
47
|
+
The engine validates and imports this one-shot sidecar into SQLite when the dispatch completes, then deletes it. Do not write runtime state under `prd/`.
|
|
43
48
|
|
|
44
49
|
```json
|
|
45
50
|
{
|
|
@@ -190,14 +195,14 @@ If the task description contains `mode: diff-aware-update`, you are updating an
|
|
|
190
195
|
|
|
191
196
|
## Important
|
|
192
197
|
|
|
193
|
-
- Write ONLY the single
|
|
198
|
+
- Write ONLY the single result sidecar at `{{team_root}}/agents/{{agent_id}}/prd-result.json`
|
|
199
|
+
- Wrap the PRD object in `{ "filename": "{{prd_filename}}", "prd": { ... } }`
|
|
194
200
|
- Do NOT create a git branch, worktree, or PR — this playbook writes minions-internal state only
|
|
195
201
|
- Do NOT modify any files in the project repo
|
|
196
|
-
-
|
|
197
|
-
- The engine will dispatch implementation agents automatically once the JSON file exists
|
|
202
|
+
- The engine will dispatch implementation agents automatically once the sidecar is imported
|
|
198
203
|
- For `shared-branch`: agents commit to a single branch — one PR is created automatically when all items are done
|
|
199
204
|
- For `parallel`: each agent creates its own branch and PR
|
|
200
205
|
|
|
201
206
|
## When to Stop
|
|
202
207
|
|
|
203
|
-
Your task is complete once you have written
|
|
208
|
+
Your task is complete once you have written `{{team_root}}/agents/{{agent_id}}/prd-result.json`. The engine imports it into SQLite after you exit. Do NOT run any git commands. Do NOT create branches, PRs, or modify project code. Stop after writing the sidecar.
|
package/playbooks/plan.md
CHANGED
|
@@ -27,10 +27,6 @@ A user has described a feature they want built. Your job is to create a detailed
|
|
|
27
27
|
- Identify the core goal, constraints, and success criteria
|
|
28
28
|
- Note any ambiguities that need to be called out
|
|
29
29
|
|
|
30
|
-
{{#project_skills_block}}
|
|
31
|
-
{{project_skills_block}}
|
|
32
|
-
|
|
33
|
-
{{/project_skills_block}}
|
|
34
30
|
### 2. Explore the Codebase
|
|
35
31
|
- Read `CLAUDE.md` at repo root and relevant directories
|
|
36
32
|
- Map the areas of code that this feature will touch
|
package/playbooks/review.md
CHANGED
|
@@ -27,12 +27,6 @@ Use subagents only for genuinely parallel, independent tasks (e.g., reviewing un
|
|
|
27
27
|
git diff {{main_branch}}...origin/{{pr_branch}}
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
{{#project_skills_block}}
|
|
31
|
-
{{project_skills_block}}
|
|
32
|
-
|
|
33
|
-
> **Skipping an in-scope review skill is gated.** Before you record a `meta.review.skillSkipped` (or `meta.skill.skipped`) outcome for any skill listed above, re-read that skill's own SKILL.md checklist and confirm your skip reason does not contradict any explicit "Flag if…" / "Verify that…" / "Requirements" item it documents. If the diff trips ANY such item, do NOT skip — apply the skill (or at least that item). When you do skip, surface the exact same `{name, reason}` in your PR review comment via `minions pr comment … --skill-skipped-json '{"name":"…","reason":"…"}'` so a human sees it alongside your verdict before merge (no drift between the report and the comment). See `playbooks/shared-rules.md` → "Skipped an in-scope project skill?".
|
|
34
|
-
|
|
35
|
-
{{/project_skills_block}}
|
|
36
30
|
2. Think about deploy risk before commenting:
|
|
37
31
|
- What user-visible behavior changed?
|
|
38
32
|
- What dependencies, callers, or tests could be affected?
|
|
@@ -120,71 +120,6 @@ The engine provides a completion report path in the prompt and in `MINIONS_COMPL
|
|
|
120
120
|
|
|
121
121
|
For the canonical schema — every field, the `failure_class` enum, `noop:true` semantics, `retryable` / `needs_rerun` shape, and the artifacts array — see `docs/completion-reports.md`. The JSON report is the primary signal; fenced `completion` blocks in stdout are accepted only as a fallback.
|
|
122
122
|
|
|
123
|
-
## Harness transparency / self-report
|
|
124
|
-
|
|
125
|
-
Populate the **optional** `harnessUsed` field on your completion report with the harness affordances you actually consulted to do the work — the skills you ran, the MCP servers you called, the slash-commands you invoked, and the reference docs you read. This is observability, not a gate: it lets the team see which tooling drove a dispatch and lets the engine cross-check your claims against what it actually exposed. Omit the field entirely when you used none; do not pad it with affordances you didn't touch.
|
|
126
|
-
|
|
127
|
-
Use this canonical `{ skills, mcpServers, commands, docs }` shape. Each kind keeps only the listed fields; the **required** field must be present or the entry is dropped:
|
|
128
|
-
|
|
129
|
-
- `skills` — `{ name, source, path }` (required: `name`; `source` is `user` / `project`)
|
|
130
|
-
- `mcpServers` — `{ name, scope }` (required: `name`; `scope` is `user` / `project`)
|
|
131
|
-
- `commands` — `{ name, scope }` (required: `name`)
|
|
132
|
-
- `docs` — `{ path, why }` (required: `path`; `why` is a short reason you read it)
|
|
133
|
-
|
|
134
|
-
Copyable worked example:
|
|
135
|
-
|
|
136
|
-
```json
|
|
137
|
-
{
|
|
138
|
-
"status": "success",
|
|
139
|
-
"summary": "Added the harnessUsed self-report contract to shared-rules + docs.",
|
|
140
|
-
"harnessUsed": {
|
|
141
|
-
"skills": [
|
|
142
|
-
{"name": "run-tests", "source": "project", "path": ".claude/skills/run-tests/SKILL.md"}
|
|
143
|
-
],
|
|
144
|
-
"mcpServers": [
|
|
145
|
-
{"name": "azure-ado", "scope": "user"}
|
|
146
|
-
],
|
|
147
|
-
"commands": [
|
|
148
|
-
{"name": "simplify", "scope": "user"}
|
|
149
|
-
],
|
|
150
|
-
"docs": [
|
|
151
|
-
{"path": "docs/completion-reports.md", "why": "confirmed the harnessUsed field shape"}
|
|
152
|
-
]
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
Entries you report are **cross-checked** against what the engine propagated into your worktree and annotated `grounded: true | false` — never dropped — so a `grounded: false` entry surfaces a discrepancy for a human rather than being hidden. Full contract: `docs/harness-transparency.md`.
|
|
158
|
-
|
|
159
|
-
When you author a **PR review / fix summary comment**, the same harness footprint belongs in the comment body as a collapsible "Harnesses used" section so reviewers see which skills / MCPs / docs informed the change.
|
|
160
|
-
|
|
161
|
-
**Preferred — `minions pr comment` (GitHub and Azure DevOps `--host ado`): do NOT hand-render the section.** Write your `harnessUsed` record — the same `{ skills, mcpServers, commands, docs }` shape as the completion field above — to a JSON file and pass `--harness-file <path>` (or inline via `--harness-json <json>`). The shared builder (`engine/comment-format.js#buildHarnessUsedSection`, consumed by both `engine/gh-comment.js` and `engine/ado-comment.js`) folds the byte-identical `<details>` section into the body for you, so agent-authored and engine-authored comments match. Each entry is cross-checked against the harness manifest the engine propagated into your worktree and annotated `grounded: true | false` (never dropped); a `grounded: false`, ⚠️-marked bullet means **the engine couldn't confirm that affordance against the propagated manifest — not that you did anything wrong**.
|
|
162
|
-
|
|
163
|
-
**Raw fallbacks only — `gh pr comment` / `az repos pr comment` / ADO REST:** these bypass the CLI chokepoint, so you MUST hand-render the section yourself. Render it **identically on both hosts** — append this exact `<details>` block at the end of your comment body (omit it entirely when you used no affordances):
|
|
164
|
-
|
|
165
|
-
```markdown
|
|
166
|
-
<details>
|
|
167
|
-
<summary>🧰 Harnesses used (N)</summary>
|
|
168
|
-
|
|
169
|
-
- 🧩 `skill-name` — source
|
|
170
|
-
- 🔌 `mcp-name` — scope
|
|
171
|
-
- ⌘ `command-name` — scope
|
|
172
|
-
- 📄 `docs/some-doc.md` — why you read it
|
|
173
|
-
|
|
174
|
-
</details>
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
One bullet per affordance, in the order skills → MCP servers → commands → docs; `N` is the bullet count. Whether the CLI folds it in or you hand-render it on a raw fallback, the section is the human-readable mirror of your `harnessUsed` completion field — keep the two consistent.
|
|
178
|
-
|
|
179
|
-
### Skipped an in-scope project skill? Validate the skip, then surface it in the PR comment
|
|
180
|
-
|
|
181
|
-
`meta.review.skillSkipped` / `meta.skill.skipped` (shape `{name, reason}`, see `docs/completion-reports.md`) lets you self-report that you intentionally skipped an available, **in-scope** project (review) skill. Two hard rules apply — this is not aspirational:
|
|
182
|
-
|
|
183
|
-
1. **Validate the skip against the skill's own scope before recording it.** Re-read the skipped skill's SKILL.md review criteria / checklist (the content already injected via the `## Project skills` / `## Project review skills` block). Confirm your skip reason does **not** contradict any explicit "Flag if…" / "Verify that…" / "Requirements" item the skill documents. If the diff trips ANY explicit checklist item the skill covers, skipping is **not** permitted — apply the skill (or at minimum that specific checklist item). A skip reason that waves away a gate the skill explicitly documents (e.g. "no CHANGELOG needed for this diff" when the skill's CHANGELOG Requirements section says otherwise) is invalid.
|
|
184
|
-
2. **Surface the skip in the PR comment, not just the JSON.** When you post a review/fix summary comment, the skip must be visible in the same comment as the verdict so a human sees it **before** merge. Via `minions pr comment` (GitHub and ADO `--host ado`), pass `--skill-skipped-file <path>` (JSON `{name, reason}`) or inline `--skill-skipped-json <json>`; the shared builder (`engine/comment-format.js#buildSkippedSkillSection`, consumed by both `engine/gh-comment.js` and `engine/ado-comment.js`) folds a byte-identical `> ⚠️ Skipped project skill: <name> — <reason>` callout in for you. On raw fallbacks (`gh pr comment` / `az repos pr comment` / ADO REST) render that exact one-line blockquote callout yourself.
|
|
185
|
-
|
|
186
|
-
The **same** `{name, reason}` you record in `meta.review.skillSkipped` / `meta.skill.skipped` must be the one rendered in the PR comment — no drift between the two.
|
|
187
|
-
|
|
188
123
|
## Minions API access
|
|
189
124
|
|
|
190
125
|
The Minions dashboard runs at `http://localhost:7331` whenever the engine is up. Agents may call its HTTP endpoints when (and only when) the playbook explicitly authorizes it for a particular task — most dispatches do not need any API access, and uninvited writes to engine-managed state are still prohibited (see "Do NOT write to `agents/*/status.json`" above).
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
# Harness Transparency
|
|
2
|
-
|
|
3
|
-
Plan P-a8f3c2d1. Minions gives dispatched agents a *harness* — the skills, MCP
|
|
4
|
-
servers, slash-commands, and reference docs the engine makes reachable inside a
|
|
5
|
-
worktree (user-scope `~/.claude` / `~/.copilot` / `~/.agents`, project-local
|
|
6
|
-
`.claude/skills`, `.mcp.json`, propagated `--add-dir` roots, …). Harness
|
|
7
|
-
transparency makes that surface **observable after the fact**: which of those
|
|
8
|
-
affordances did the agent actually consult to do the work?
|
|
9
|
-
|
|
10
|
-
The contract has three stages — **capture → ground → surface** — and a single
|
|
11
|
-
canonical vocabulary that every stage speaks.
|
|
12
|
-
|
|
13
|
-
## Canonical vocabulary
|
|
14
|
-
|
|
15
|
-
Defined in `engine/shared.js` as `HARNESS_USED_KINDS`. Four kinds; each declares
|
|
16
|
-
the only fields that survive normalization plus the one field that MUST be
|
|
17
|
-
present for an entry to be kept:
|
|
18
|
-
|
|
19
|
-
| Kind | Fields | Required |
|
|
20
|
-
|---|---|---|
|
|
21
|
-
| `skills` | `name`, `source`, `path` | `name` |
|
|
22
|
-
| `mcpServers` | `name`, `scope` | `name` |
|
|
23
|
-
| `commands` | `name`, `scope` | `name` |
|
|
24
|
-
| `docs` | `path`, `why` | `path` |
|
|
25
|
-
|
|
26
|
-
`shared.normalizeHarnessUsed(raw)` validates and clamps any untrusted
|
|
27
|
-
`harnessUsed`-shaped object into this canonical `{ skills, mcpServers, commands,
|
|
28
|
-
docs }` form: it drops malformed entries (non-objects, or entries missing the
|
|
29
|
-
kind's required field), keeps only whitelisted string fields (trimmed and
|
|
30
|
-
clamped to `HARNESS_USED_MAX_FIELD_LEN` = 512 chars), caps each array at
|
|
31
|
-
`HARNESS_USED_MAX_ENTRIES` = 50, and returns `null` when nothing survives so
|
|
32
|
-
callers can treat "no harness data" as one falsy case. When non-null, all four
|
|
33
|
-
kind keys are always present (empty arrays for kinds with no entries) for a
|
|
34
|
-
stable downstream shape.
|
|
35
|
-
|
|
36
|
-
## Stage 1 — Capture (agent self-report)
|
|
37
|
-
|
|
38
|
-
Every agent populates `completionReport.harnessUsed` with the affordances it
|
|
39
|
-
actually used. This is a self-report: the agent is the only party that knows
|
|
40
|
-
*which* skill it ran or *which* doc it read. The field is optional and
|
|
41
|
-
backward-compatible — agents that omit it stay valid. See
|
|
42
|
-
[completion-reports.md → harnessUsed](completion-reports.md#harness-usage-harnessused)
|
|
43
|
-
for the field schema and a copyable example, and `playbooks/shared-rules.md`
|
|
44
|
-
→ "Harness transparency / self-report" for the per-task instruction every
|
|
45
|
-
playbook inherits.
|
|
46
|
-
|
|
47
|
-
## Stage 2 — Ground (engine cross-check)
|
|
48
|
-
|
|
49
|
-
A self-report is a *claim*. Grounding cross-checks it against what the engine
|
|
50
|
-
actually exposed.
|
|
51
|
-
|
|
52
|
-
At spawn time (`engine.js spawnAgent`, P-a8f3c2d1) the engine folds the
|
|
53
|
-
resolved harness roots — `queries.getUserHarnesses` (user-scope) +
|
|
54
|
-
`queries.getProjectHarnesses` (project-scope) — plus the computed `--add-dir`
|
|
55
|
-
set into a `_harnessPropagated` manifest via
|
|
56
|
-
`queries.buildHarnessPropagatedManifest({ userHarnesses, projectHarnesses,
|
|
57
|
-
addDirs })`. The manifest unions **both** user-scope and project-scope
|
|
58
|
-
contributions and dedups by path, then is persisted onto the dispatch record as
|
|
59
|
-
`_harnessPropagated`. Capturing user-scope harnesses is load-bearing:
|
|
60
|
-
otherwise a legitimate `~/.agents` / `~/.claude` skill usage would be wrongly
|
|
61
|
-
flagged un-grounded downstream. This capture is observability only — it does
|
|
62
|
-
**not** change which dirs are propagated at spawn time, and any failure here is
|
|
63
|
-
non-fatal (the spawn proceeds).
|
|
64
|
-
|
|
65
|
-
**Monorepo sub-project contributes `--add-dir` roots (P-f52d81ba).** The `addDirs` set
|
|
66
|
-
folded into the manifest includes the project-local harness dirs propagated for
|
|
67
|
-
the dispatch. When the engine auto-derives a dominant sub-project (see
|
|
68
|
-
[project-skills.md → Monorepo sub-project scoping](project-skills.md#monorepo-sub-project-scoping)),
|
|
69
|
-
those sub-project-scoped `--project-harness-dir` roots flow into `propagatedProjectHarnessDirs`
|
|
70
|
-
→ `addDirs` → the `_harnessPropagated` manifest. The clip that selects them is
|
|
71
|
-
the **same** `shared.filterProjectHarnessDirsForWorkdir` used for an explicit
|
|
72
|
-
`meta.workdir` — `spawnAgent` passes `workdir: validatedWorkdir || _effectiveSubproject
|
|
73
|
-
|| null`, so an explicit `meta.workdir` wins, else the auto-derived sub-project's
|
|
74
|
-
first-level segment clips the surface, else no clip (whole-project harness).
|
|
75
|
-
Because the manifest captures the same sub-project-clipped roots the agent was actually
|
|
76
|
-
handed, a self-reported skill usage against a sub-project's skill (e.g.
|
|
77
|
-
`ocm/.claude/skills/…`) still grounds `true` — grounding stays faithful under
|
|
78
|
-
sub-project scoping instead of falsely flagging the sub-project's own skills.
|
|
79
|
-
|
|
80
|
-
The grounding cross-check (P-c6f5e8b3) runs in `engine/lifecycle.js`
|
|
81
|
-
`runPostCompletionHooks` once the completion report is parsed and nonce-trusted:
|
|
82
|
-
`shared.groundHarnessUsed(completionReport.harnessUsed, _harnessPropagated)`
|
|
83
|
-
normalizes the self-report (same clamp/drop rules as `normalizeHarnessUsed`) and
|
|
84
|
-
annotates each surviving entry `grounded: true | false`. The grounded object
|
|
85
|
-
replaces `structuredCompletion.harnessUsed` in place, so it rides the existing
|
|
86
|
-
completion storage onto the completed dispatch record for the Stage-3 readouts.
|
|
87
|
-
The spawn-time manifest is located via `lifecycle.resolveHarnessPropagated`
|
|
88
|
-
(in-memory dispatch record first, then the persisted dispatch queues for the
|
|
89
|
-
restart/re-attach case). It compares each self-reported entry against the
|
|
90
|
-
`_harnessPropagated` manifest and annotates it `grounded: true | false`:
|
|
91
|
-
|
|
92
|
-
- `grounded: true` — the engine demonstrably exposed this affordance.
|
|
93
|
-
- `grounded: false` — the entry is **kept, not dropped**, and flagged. A
|
|
94
|
-
false here means "the agent claims it used something the engine has no record
|
|
95
|
-
of exposing" — which can be a genuine out-of-band tool, a stale path, or a
|
|
96
|
-
hallucinated entry. The point is to surface the discrepancy for a human, not
|
|
97
|
-
to silently discard the claim.
|
|
98
|
-
|
|
99
|
-
An entry grounds `true` on any of these signals (OR'd):
|
|
100
|
-
|
|
101
|
-
- **identity** — the entry's `name` matches a propagated entry's name of the
|
|
102
|
-
same kind, or (skills/docs) its `path` is lexically contained under a
|
|
103
|
-
propagated skill root or `--add-dir`, or `basename(path)` matches a propagated
|
|
104
|
-
skill name.
|
|
105
|
-
- **scope** — the entry's scope (skills use `source`) matches a propagated
|
|
106
|
-
entry's scope of the same kind. The capture manifest records harness *roots*
|
|
107
|
-
(skill/command dirs, MCP config files), not individual affordances, so a
|
|
108
|
-
per-affordance self-report frequently can't match by name; scope membership is
|
|
109
|
-
the coarse-but-honest "the engine exposed this surface" signal the manifest
|
|
110
|
-
can attest. `docs` carry no scope, so path containment is their only signal —
|
|
111
|
-
a relative doc path (`docs/foo.md`) can't be tested against absolute add-dirs
|
|
112
|
-
and grounds `false`.
|
|
113
|
-
|
|
114
|
-
## Stage 3 — Surface (three readouts)
|
|
115
|
-
|
|
116
|
-
Grounded harness usage is rendered on three surfaces so a human (or a later
|
|
117
|
-
evaluation pass) can see what tooling drove a dispatch:
|
|
118
|
-
|
|
119
|
-
1. **PR comment** (P-e4b7a6d5) — the harness digest is folded into the agent's
|
|
120
|
-
PR comment/summary so reviewers see which skills / MCPs / docs informed the
|
|
121
|
-
change. `engine/comment-format.js#buildHarnessUsedSection(harnessUsed)` is
|
|
122
|
-
the single, platform-neutral renderer: it turns the grounded
|
|
123
|
-
`{ skills, mcpServers, commands, docs }` record into a collapsible Markdown
|
|
124
|
-
`<details>` block (one bullet per affordance, `grounded: false` entries kept
|
|
125
|
-
and ⚠️-marked), and returns `''` for an empty/absent record. The GitHub
|
|
126
|
-
comment path folds it in via `engine/gh-comment.js#buildMinionsCommentBody`
|
|
127
|
-
(optional `harnessUsed` arg, threaded through `postPrComment` /
|
|
128
|
-
`postPrReviewComment`); the Azure DevOps path mirrors it via
|
|
129
|
-
`engine/ado-comment.js#postAdoPrComment` (same builder, same `harnessUsed`
|
|
130
|
-
arg). Both posters are reached from the `minions pr comment` CLI, which turns
|
|
131
|
-
`--harness-file` / `--harness-json` into the grounded record and folds the
|
|
132
|
-
**byte-identical** section in for the agent. Only the raw `gh pr comment` /
|
|
133
|
-
`az repos pr comment` / REST fallbacks bypass that chokepoint, so on those
|
|
134
|
-
paths review/fix agents append the section themselves per
|
|
135
|
-
`playbooks/shared-rules.md` → "Harness transparency / self-report". Every
|
|
136
|
-
surface consumes the one renderer, so there is no second formatter to drift.
|
|
137
|
-
|
|
138
|
-
**Skipped in-scope project skill (W-mr287sc0000uc214).** The same PR-comment
|
|
139
|
-
surface also folds in a VISIBLE (non-collapsed) `> ⚠️ Skipped project skill:
|
|
140
|
-
<name> — <reason>` callout when the agent self-reported that it intentionally
|
|
141
|
-
skipped an available, in-scope project (review) skill
|
|
142
|
-
(`meta.review.skillSkipped` / `meta.skill.skipped`). This lived only in the
|
|
143
|
-
completion-report JSON before — invisible to a human reading the PR pre-merge.
|
|
144
|
-
`engine/comment-format.js#buildSkippedSkillSection(skillSkipped)` is the single
|
|
145
|
-
neutral renderer (sibling of `buildHarnessUsedSection`); it is threaded through
|
|
146
|
-
`buildMinionsCommentBody` (optional `skillSkipped` arg) and both posters
|
|
147
|
-
(`gh-comment.js` / `ado-comment.js`), and the `minions pr comment` CLI turns
|
|
148
|
-
`--skill-skipped-file` / `--skill-skipped-json` into the record. Two rules
|
|
149
|
-
attach to the skip (see `docs/completion-reports.md` → Review/Project skill
|
|
150
|
-
outcomes): the skip reason must be **validated against the skill's own
|
|
151
|
-
documented checklist** before it is recorded (a skip that contradicts an
|
|
152
|
-
explicit "Flag if…" / "Requirements" item the skill covers is invalid), and
|
|
153
|
-
the `{name, reason}` rendered in the comment must match the one recorded in the
|
|
154
|
-
report (no drift).
|
|
155
|
-
2. **Final agent note** — for a non-clean completion (failure / partial) the
|
|
156
|
-
single final agent report (`engine/lifecycle.js#writeNonCleanAgentReport`)
|
|
157
|
-
folds the grounded harness footprint in as the same `buildHarnessUsedSection`
|
|
158
|
-
block, so the learnings / inbox stream that feeds consolidation still carries
|
|
159
|
-
it without a separate per-attempt `harness-usage-*` note. Clean completions
|
|
160
|
-
rely on the work-item modal surface (#3) instead — they write no inbox note
|
|
161
|
-
at all (#308 removed the standalone harness-usage digest to cut note spam).
|
|
162
|
-
3. **Work-item detail modal** — the dashboard work-item modal shows the
|
|
163
|
-
harness list alongside the completion artifacts (P-d5a6f7c4). On
|
|
164
|
-
completion, `engine/lifecycle.js promoteCompletionArtifacts` persists the
|
|
165
|
-
grounded `structuredCompletion.harnessUsed` onto the work item as
|
|
166
|
-
`_harnessUsed` (it survives the slim `/api/work-items` list payload and
|
|
167
|
-
modal hydration). `dashboard/js/render-work-items.js _wiRenderDetail` renders
|
|
168
|
-
the "Repo harnesses used" section from `item._harnessUsed`: one plain solid
|
|
169
|
-
pill per skill / MCP / command / doc. The grounding flag is **not** surfaced
|
|
170
|
-
in this modal — every entry renders identically (the per-pill dashed-border /
|
|
171
|
-
⚠ marker distinction was dropped in PR #296). Grounding is surfaced only on
|
|
172
|
-
the PR-comment surface above.
|
|
173
|
-
|
|
174
|
-
## Why it matters
|
|
175
|
-
|
|
176
|
-
- **Tooling ROI.** Knowing which skills/MCPs are actually consulted (vs. shipped
|
|
177
|
-
and ignored) tells the team where to invest in harness affordances.
|
|
178
|
-
- **Grounding catches drift.** `grounded: false` entries flag stale paths,
|
|
179
|
-
renamed skills, or agents reaching for tooling the engine didn't actually
|
|
180
|
-
wire in — without dropping the signal.
|
|
181
|
-
- **Evaluation.** Comparing skill-driven work against first-principles work
|
|
182
|
-
(cf. `meta.skill` in [completion-reports.md](completion-reports.md#project-skill-outcomes))
|
|
183
|
-
needs a faithful record of what the agent had and used.
|
|
184
|
-
|
|
185
|
-
## Related
|
|
186
|
-
|
|
187
|
-
- `engine/shared.js` — `HARNESS_USED_KINDS`, `HARNESS_USED_MAX_ENTRIES`,
|
|
188
|
-
`HARNESS_USED_MAX_FIELD_LEN`, `normalizeHarnessUsed()`, `groundHarnessUsed()`,
|
|
189
|
-
`filterProjectHarnessDirsForWorkdir()` (the sub-project/workdir clip)
|
|
190
|
-
- `engine/queries.js` — `buildHarnessPropagatedManifest()`,
|
|
191
|
-
`getUserHarnesses()`, `getProjectHarnesses()`
|
|
192
|
-
- `engine/lifecycle.js` — `resolveHarnessPropagated()` + the grounding
|
|
193
|
-
cross-check wired into `runPostCompletionHooks`
|
|
194
|
-
- `docs/completion-reports.md` — the `harnessUsed` completion-report field
|
|
195
|
-
- `docs/project-skills.md` — project-local skill/command discovery that feeds
|
|
196
|
-
the project-scope harness
|
|
197
|
-
- `docs/workspace-manifests.md` — per-agent `allowed_tools` / `allowed_repos`
|
|
198
|
-
scoping that bounds the harness surface
|
|
199
|
-
- `playbooks/shared-rules.md` — the per-task self-report instruction
|
package/docs/project-skills.md
DELETED
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
# Project skill discovery & intent vocabulary
|
|
2
|
-
|
|
3
|
-
W-mq1cczi90006b21f (follow-on to PR #82, W-mq16xtdx001a347e).
|
|
4
|
-
|
|
5
|
-
Minions' project-local **skill discovery layer** surfaces purpose-built tooling that a project ships (`.claude/skills/`, `.claude/commands/`, slash-command mentions in `CLAUDE.md` / `.github/copilot-instructions.md`) so dispatched agents steer toward the right skill instead of reinventing the flow from first principles.
|
|
6
|
-
|
|
7
|
-
This document is the contract every playbook author and project teammate needs to know.
|
|
8
|
-
|
|
9
|
-
## Where the code lives
|
|
10
|
-
|
|
11
|
-
| File | Role |
|
|
12
|
-
|---|---|
|
|
13
|
-
| `engine/discover-project-skills.js` | Bounded filesystem walk + classification heuristic. The crash-safe primitive. |
|
|
14
|
-
| `engine/playbook-intents.js` | Single source of truth for the playbook → intent set mapping. |
|
|
15
|
-
| `engine/playbook.js` | Calls discovery + filter at render time, injects `{{project_skills_block}}` into the rendered prompt. |
|
|
16
|
-
|
|
17
|
-
## What gets discovered
|
|
18
|
-
|
|
19
|
-
Per project worktree, the discovery walk visits:
|
|
20
|
-
|
|
21
|
-
- `<projectRoot>/.claude/skills/*/SKILL.md` — top-level skill packs.
|
|
22
|
-
- `<projectRoot>/.claude/commands/*.md` — top-level slash-commands.
|
|
23
|
-
- `<projectRoot>/<area>/.claude/skills/*/SKILL.md` — **nested per-area skills** (one level deep). This is how OCM / loop / officemobile organize their skills in a monorepo.
|
|
24
|
-
- `<projectRoot>/<area>/.claude/commands/*.md` — same, for nested commands.
|
|
25
|
-
- `<projectRoot>/.github/copilot-instructions.md` — slash-command mentions (top 32 KB).
|
|
26
|
-
- `<projectRoot>/CLAUDE.md` — slash-command mentions (top 32 KB).
|
|
27
|
-
|
|
28
|
-
Each discovery entry has shape:
|
|
29
|
-
|
|
30
|
-
```js
|
|
31
|
-
{
|
|
32
|
-
kind: 'skill' | 'command' | 'slash-command',
|
|
33
|
-
name: string, // e.g. "code-reviewer" or "/review-swarm"
|
|
34
|
-
path: string, // relative to projectRoot
|
|
35
|
-
oneLineDescription: string, // ≤200 chars
|
|
36
|
-
intents: string[] // closed enum, see below
|
|
37
|
-
}
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
The walk is **cheap and bounded** — preserve every guardrail in
|
|
41
|
-
`engine/discover-project-skills.js`:
|
|
42
|
-
|
|
43
|
-
- ≤ 50 files per surface
|
|
44
|
-
- 8 KB per skill / 32 KB per docs file
|
|
45
|
-
- 250 ms walltime budget — bails rather than blocks dispatch
|
|
46
|
-
- ≤ 50 nested areas probed
|
|
47
|
-
- Missing worktree / unreadable → `[]` (never throws)
|
|
48
|
-
|
|
49
|
-
## Monorepo sub-project scoping
|
|
50
|
-
|
|
51
|
-
P-f52d81ba. In a monorepo, a dispatch usually touches one sub-project (`ocm/`,
|
|
52
|
-
`loop/`, `officemobile/`, …) even though discovery walks every sub-project's
|
|
53
|
-
`.claude/skills`. Scoping surfaces that sub-project's skills **first** without hiding
|
|
54
|
-
the rest, so an `ocm/`-focused agent isn't forced to scroll past `loop/` tooling
|
|
55
|
-
to find the relevant pack.
|
|
56
|
-
|
|
57
|
-
**Changed-path → sub-project detection.** `detectDominantSubproject({ projectPath,
|
|
58
|
-
changedPaths })` (engine/discover-project-skills.js) counts the changed paths
|
|
59
|
-
per first-level directory, keyed on the POSIX first segment. It reuses
|
|
60
|
-
`_listAreas` for the authoritative set of valid sub-projects, so a stray first segment
|
|
61
|
-
that isn't a real top-level dir never counts. It returns `{ subproject, matched,
|
|
62
|
-
total, confident }`. The engine feeds it changed paths from:
|
|
63
|
-
|
|
64
|
-
- **spawnAgent** (async, authoritative): `git diff --name-only <mainBranch>...HEAD`
|
|
65
|
-
in the current dispatch's worktree — never a parent/follow-up's stale diff.
|
|
66
|
-
- **renderProjectWorkItemPromptForAgent** (`_deriveDominantSubprojectSync`, build-time
|
|
67
|
-
fallback with no git access): the work item's `references[*].path`.
|
|
68
|
-
|
|
69
|
-
**Dominant-sub-project plurality threshold.** `detectDominantSubproject` only reports a sub-project
|
|
70
|
-
as `confident` when the top sub-project holds **≥ 60%** of the sub-project-matched files **and**
|
|
71
|
-
**≥ 2** files (`dominantSubprojectMinRatio` / `dominantSubprojectMinFiles` in `DEFAULTS`,
|
|
72
|
-
overridable via `opts`). Ties break alphabetically for determinism. An empty,
|
|
73
|
-
mixed, or no-known-sub-project diff returns `{ subproject: null, confident: false }` →
|
|
74
|
-
flat discovery (today's global name-sort). This is deliberately conservative:
|
|
75
|
-
a weakly-dominant or split diff falls back to flat surfacing rather than
|
|
76
|
-
mis-scoping to the wrong sub-project.
|
|
77
|
-
|
|
78
|
-
**Explicit `meta.workdir` wins over auto-detection.** When the operator declares
|
|
79
|
-
`meta.workdir` on the work item, the effective sub-project is its first path segment —
|
|
80
|
-
no diff work is done. Auto-detection only runs when `meta.workdir` is absent.
|
|
81
|
-
The async git-diff-derived sub-project (threaded into the shared-branch re-render via
|
|
82
|
-
`options.dominantSubproject`) overrides the sync `references`-derived guess.
|
|
83
|
-
|
|
84
|
-
**Prioritized, not exclusive, surfacing.** The effective sub-project is threaded through
|
|
85
|
-
`playbook.js` as `scopeSubproject` into `discoverProjectSkillsWithDiagnostics`. When
|
|
86
|
-
set, entries under `<scopeSubproject>/` lead the list (name-sorted within the group),
|
|
87
|
-
then root-level entries, then other-sub-project entries. **Discovery still walks
|
|
88
|
-
everything — no skills are dropped; only ordering changes.** An empty/unset
|
|
89
|
-
`scopeSubproject` reduces byte-for-byte to the historical global name-then-path sort.
|
|
90
|
-
|
|
91
|
-
**Configurable per-surface cap.** `ENGINE_DEFAULTS.projectSkillMaxFilesPerSurface`
|
|
92
|
-
(default **200**) caps how many skill packs / command files are read per surface
|
|
93
|
-
(root `.claude/skills`, each `<area>/.claude/skills`, …). `playbook.js` threads
|
|
94
|
-
it into the discovery `opts`; when no override is supplied the module falls back
|
|
95
|
-
to its own `DEFAULTS.maxFilesPerSurface` (50). It's raised well above the
|
|
96
|
-
fallback so large monorepo sub-projects (e.g. an `ocm/.claude/skills` with ~80 packs)
|
|
97
|
-
don't silently drop the most-relevant skills. Entries are alphabetically sorted
|
|
98
|
-
**before** the cap is applied, so the surviving subset is deterministic across
|
|
99
|
-
runs and OSes rather than FS-readdir-order-dependent.
|
|
100
|
-
|
|
101
|
-
**Truncation diagnostics.** `discoverProjectSkillsWithDiagnostics` returns
|
|
102
|
-
`{ entries, truncations }` where each truncation is `{ surface, dir, scanned,
|
|
103
|
-
total }` — recorded when a surface's `total` file count exceeds `scanned`
|
|
104
|
-
(i.e. the cap dropped entries). `playbook.js` logs a `warn` when any surface
|
|
105
|
-
truncates and stashes the diagnostics so `spawnAgent` can persist the detected
|
|
106
|
-
sub-project (`_dominantSubproject`) and truncations (`_skillDiscoveryTruncations`) onto the
|
|
107
|
-
dispatch record for later grounding/observability. Overflow is thus **observable**
|
|
108
|
-
instead of silent.
|
|
109
|
-
|
|
110
|
-
## The intent vocabulary (CLOSED)
|
|
111
|
-
|
|
112
|
-
| Intent | What belongs here |
|
|
113
|
-
|---|---|
|
|
114
|
-
| `review` | code review, PR review, swarm review (`code-reviewer`, `/review-swarm`, `/code-review`, etc.) |
|
|
115
|
-
| `build` | scaffold, generate, bump, migrate, codemod, refactor (`bump-fmf-android`, `workspace`, `vhd`, etc.) |
|
|
116
|
-
| `fix` | debug, triage, repro, regression, flake-killing (`triage-flake`, `cover-pr` for missing tests on PR…) |
|
|
117
|
-
| `test` | author tests, increase coverage, validate (`integration-tests`, `run-tests`, `qa-validate`) |
|
|
118
|
-
| `plan` | PRD authoring, ADR, design-doc, decompose (`substitute-scheduler-template-vars`, `decompose`) |
|
|
119
|
-
| `research` | investigate, gather-impact, telemetry-query, audit (`gather-impact`, `audit-deprecated`) |
|
|
120
|
-
| `deploy` | release, publish, buddy-build, rollout, ship (`buddy-build`, `track-pr`) |
|
|
121
|
-
| `observability` | telemetry, logs, kusto, monitoring, metrics dashboards (`kusto-telemetry-lmf-quality-report`, `weekly-repo-summary`) |
|
|
122
|
-
| `meta` | meta-tooling about the skill system itself. **Do NOT use as a catch-all** — empty `intents: []` is the honest signal when the heuristic doesn't fire. |
|
|
123
|
-
|
|
124
|
-
### How intents are assigned
|
|
125
|
-
|
|
126
|
-
For each discovered entry, `classifyIntents(...)` does:
|
|
127
|
-
|
|
128
|
-
1. **Honor explicit author intent first.** A skill's `SKILL.md` frontmatter may declare `intents:` (or `tags:` / `intent:`) — only values that match the closed vocabulary above are accepted. Example:
|
|
129
|
-
```yaml
|
|
130
|
-
---
|
|
131
|
-
name: bump-fmf-android
|
|
132
|
-
description: Bump the FMF SDK version pin in OCM Android
|
|
133
|
-
intents: [build, deploy]
|
|
134
|
-
---
|
|
135
|
-
```
|
|
136
|
-
2. **Fall back to keyword heuristics.** The skill's `name`, frontmatter `description`, first heading, and filename are matched against the per-intent keyword regexes in `INTENT_KEYWORDS` (engine/discover-project-skills.js). A skill matching multiple regexes carries multiple intents.
|
|
137
|
-
3. **Empty intents are honest.** Zero matches → `intents: []`. The entry is still discovered and returned, but no intent-filtered playbook will surface it. NEVER default to `meta` just to satisfy the field.
|
|
138
|
-
|
|
139
|
-
### Slash-commands scraped from docs
|
|
140
|
-
|
|
141
|
-
For `/foo` mentions in `CLAUDE.md` / `.github/copilot-instructions.md`, the discovery layer is more conservative: it only surfaces slash-commands whose **name itself** matches at least one intent keyword. This keeps doc-scrape noise out of every prompt (a doc may name 50 `/foo` commands; we don't want to dump them all into an `implement` prompt).
|
|
142
|
-
|
|
143
|
-
## The playbook → intent map
|
|
144
|
-
|
|
145
|
-
Defined in `engine/playbook-intents.js`. The default mapping at time of writing:
|
|
146
|
-
|
|
147
|
-
| Playbook | Intents surfaced |
|
|
148
|
-
|---|---|
|
|
149
|
-
| `review` | `['review']` |
|
|
150
|
-
| `fix` | `['fix', 'test', 'review']` |
|
|
151
|
-
| `implement` / `implement-shared` | `['build', 'test', 'research']` |
|
|
152
|
-
| `plan` / `plan-to-prd` / `decompose` | `['plan', 'research']` |
|
|
153
|
-
| `docs` | `['research']` |
|
|
154
|
-
| `verify` | `['test', 'review']` |
|
|
155
|
-
| `build-and-test` | `['build', 'test']` |
|
|
156
|
-
| `test` / `qa-validate` | `['test']` |
|
|
157
|
-
| `explore` | `['research']` |
|
|
158
|
-
| (all others) | `[]` — no block rendered |
|
|
159
|
-
|
|
160
|
-
When a playbook's intent set is empty (or maps to none), the `{{project_skills_block}}` template variable resolves to the empty string and the splice fence collapses cleanly (no stray header, no padding).
|
|
161
|
-
|
|
162
|
-
The `followup-dispatch` template **inherits** its parent dispatch's intent set via `vars.parent_dispatch_type` — there's no row in the map for it.
|
|
163
|
-
|
|
164
|
-
## Adding a new playbook
|
|
165
|
-
|
|
166
|
-
1. Add a row to `PLAYBOOK_INTENTS` in `engine/playbook-intents.js` mapping your playbook name to the intent set it should surface.
|
|
167
|
-
2. Splice the conditional template fence into your playbook markdown at the position where the agent should see purpose-built tooling — typically between the task-intake step and the first "actually do the work" step:
|
|
168
|
-
```md
|
|
169
|
-
{{#project_skills_block}}
|
|
170
|
-
{{project_skills_block}}
|
|
171
|
-
|
|
172
|
-
{{/project_skills_block}}
|
|
173
|
-
```
|
|
174
|
-
3. If the playbook should opt out for some dispatches, the dispatcher can set `meta.skipProjectSkills: true` (or the PR-82 alias `meta.skipProjectReviewSkills: true`) on the work item.
|
|
175
|
-
|
|
176
|
-
## Adding a new intent
|
|
177
|
-
|
|
178
|
-
1. Add a regex to `INTENT_KEYWORDS` in `engine/discover-project-skills.js`. Use `\b` word boundaries.
|
|
179
|
-
2. Add the value to `INTENT_VOCABULARY` so explicit frontmatter `intents:` entries with the new name are accepted.
|
|
180
|
-
3. Add a row to the table above, with a one-line description of what belongs.
|
|
181
|
-
4. Update one or more playbook entries in `engine/playbook-intents.js` to include the new intent.
|
|
182
|
-
|
|
183
|
-
Keep the vocabulary tight — every additional intent is noise risk in every prompt that surfaces it.
|
|
184
|
-
|
|
185
|
-
## Completion-report contract
|
|
186
|
-
|
|
187
|
-
When an agent acts on a discovered skill, record the outcome in the completion report's `meta.skill` block. See [docs/completion-reports.md](completion-reports.md#project-skill-outcomes) for the full schema. The legacy `meta.review.skill*` fields (PR #82) remain accepted as aliases — new code should prefer `meta.skill.*`.
|
|
188
|
-
|
|
189
|
-
## Tests
|
|
190
|
-
|
|
191
|
-
- `test/unit/discover-project-skills.test.js` — discovery + classification + intent filtering + render + per-playbook splice coverage.
|
|
192
|
-
|
|
193
|
-
When you change discovery, classification, or the playbook→intent map, extend or update this test file.
|