@yemi33/minions 0.1.2146 → 0.1.2148
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 +14 -0
- package/dashboard/js/render-pinned.js +14 -1
- package/dashboard/slim/body.html +2 -1
- package/dashboard/slim/js/command-send.js +3 -2
- package/dashboard/slim/js/history.js +9 -2
- package/dashboard/slim/styles.css +88 -10
- package/dashboard.js +11 -0
- package/docs/README.md +1 -0
- package/docs/architecture.excalidraw +3456 -0
- package/docs/completion-reports.md +65 -0
- package/docs/project-skills.md +133 -0
- package/engine/cli.js +23 -11
- package/engine/discover-project-skills.js +490 -0
- package/engine/discover-review-skills.js +25 -0
- package/engine/playbook-intents.js +76 -0
- package/engine/playbook.js +74 -0
- package/engine/shared.js +93 -0
- package/engine.js +30 -0
- package/package.json +1 -1
- package/playbooks/fix.md +4 -0
- package/playbooks/implement-shared.md +4 -0
- package/playbooks/implement.md +4 -0
- package/playbooks/plan-to-prd.md +4 -0
- package/playbooks/plan.md +4 -0
- package/playbooks/review.md +4 -0
- package/bin/minions.js.rej +0 -16
- package/dashboard/slim/body.html.rej +0 -11
- package/dashboard/slim/js/command-send.js.rej +0 -12
- package/dashboard/slim/js/history.js.rej +0 -26
- package/dashboard/slim/styles.css.rej +0 -124
- package/docs/README.md.rej +0 -9
- package/docs/onboarding.md.rej +0 -10
|
@@ -84,6 +84,71 @@ Do **not** invent, regenerate, or share the nonce across dispatches — each spa
|
|
|
84
84
|
| `tests` | string | `pass`, `fail`, `skipped`, `N/A`, or a free-form note like `skipped — relying on PR pipeline`. |
|
|
85
85
|
| `pending` | string | Any remaining work, or `none`. |
|
|
86
86
|
| `followups` | array | Optional. PR-comment follow-up work items the agent dispatched via `POST /api/work-items` with `meta.pr_followup` set. Each entry: `{wi_id, title, reason, parent_comment_id}`. See [PR-comment follow-ups](#pr-comment-follow-ups). |
|
|
87
|
+
| `meta.review` | object | Optional, review tasks only. Records project-local review-skill outcome — see [Review skill outcomes](#review-skill-outcomes). Aliased by the generalized `meta.skill` (W-mq1cczi90006b21f). |
|
|
88
|
+
| `meta.skill` | object | Optional. Records project-local skill outcome for ANY playbook type that surfaces a `## Project skills` block (implement / fix / plan / review / etc.). See [Project skill outcomes](#project-skill-outcomes). |
|
|
89
|
+
|
|
90
|
+
## Project skill outcomes
|
|
91
|
+
|
|
92
|
+
W-mq1cczi90006b21f. Generalizes the PR-82 review-only `meta.review.skill*` fields to the full Minions lifecycle. When the playbook renders a `## Project skills` block (via `engine/playbook-intents.js` → `engine/discover-project-skills.js`) and the agent acts on a discovered skill, record the outcome under `meta.skill` so later evaluation can compare skill-driven vs. first-principles work across implement / fix / plan / review dispatches uniformly.
|
|
93
|
+
|
|
94
|
+
All `meta.skill` fields are optional and backward-compatible — older agents that never set them stay valid.
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"status": "success",
|
|
99
|
+
"meta": {
|
|
100
|
+
"skill": {
|
|
101
|
+
"invoked": {
|
|
102
|
+
"name": "bump-fmf-android",
|
|
103
|
+
"path": ".claude/skills/bump-fmf-android/SKILL.md",
|
|
104
|
+
"kind": "skill",
|
|
105
|
+
"intent": "build"
|
|
106
|
+
},
|
|
107
|
+
"findings": 3
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
| Field | Type | Notes |
|
|
114
|
+
|---|---|---|
|
|
115
|
+
| `meta.skill.invoked` | object | The project skill the agent actually ran. Shape: `{name, path, kind, intent}` where `kind` is one of `skill`, `command`, `slash-command` (mirrors the discovery layer in `engine/discover-project-skills.js`) and `intent` is the bucket it served (`build`, `review`, `fix`, `test`, `plan`, `research`, `deploy`, `observability`, `meta`). Omit when no skill was invoked. |
|
|
116
|
+
| `meta.skill.findings` | number | Count of findings/artifacts the invoked skill returned. Semantics is per-skill; treat as opaque integer. Omit when no skill was invoked. |
|
|
117
|
+
| `meta.skill.skipped` | object | Set when a project skill was available but the agent intentionally chose not to run it (trivial diff, out-of-scope, meta-work on the skill itself, etc.). Shape: `{name, reason}`. Mirror the skip rationale into the PR comment / completion summary so a human sees the reasoning. |
|
|
118
|
+
|
|
119
|
+
Dispatchers can suppress the block entirely by setting `meta.skipProjectSkills: true` on the work item — the playbook then renders without the skills block. Use this for meta-work that targets the skill itself; the engine still accepts `meta.skill.skipped` in the report regardless. The PR-82 `meta.skipProjectReviewSkills` flag is preserved as an alias (suppresses the block on every dispatch type, not just review).
|
|
120
|
+
|
|
121
|
+
## Review skill outcomes
|
|
122
|
+
|
|
123
|
+
W-mq16xtdx001a347e. **Original PR-82 fields, preserved as aliases.** New code should prefer the generalized `meta.skill.*` fields above (W-mq1cczi90006b21f) — those work for every playbook type, not just review.
|
|
124
|
+
|
|
125
|
+
Review playbook renders a `## Project review skills` block at dispatch time when the target project ships `.claude/skills/*` or `.claude/commands/*` with `review` / `swarm` in the name or description (or when `.github/copilot-instructions.md` / `CLAUDE.md` mention a canonical `/…review…` slash-command). When the agent acts on that block, it records the outcome under `meta.review` so later evaluation can compare skill-driven reviews vs. first-principles reviews.
|
|
126
|
+
|
|
127
|
+
All `meta.review` fields are optional and backward-compatible — older agents that never set them stay valid.
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"status": "success",
|
|
132
|
+
"meta": {
|
|
133
|
+
"review": {
|
|
134
|
+
"skillInvoked": {
|
|
135
|
+
"name": "code-reviewer",
|
|
136
|
+
"path": ".claude/skills/code-reviewer/SKILL.md",
|
|
137
|
+
"kind": "skill"
|
|
138
|
+
},
|
|
139
|
+
"skillFindings": 3
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
| Field | Type | Notes |
|
|
146
|
+
|---|---|---|
|
|
147
|
+
| `meta.review.skillInvoked` | object | The project review skill the agent actually ran. Shape: `{name, path, kind}` where `kind` is one of `skill`, `command`, `slash-command` (mirrors the discovery layer in `engine/discover-project-skills.js`). Omit when no skill was invoked. Aliased by `meta.skill.invoked`. |
|
|
148
|
+
| `meta.review.skillFindings` | number | Count of findings the invoked skill returned. Used later to measure skill quality and the value-add of first-principles review on top. Omit when no skill was invoked. Aliased by `meta.skill.findings`. |
|
|
149
|
+
| `meta.review.skillSkipped` | object | Set when a project review skill was available but the agent intentionally chose not to run it (trivial diff, out-of-scope diff, meta-review of the skill itself, etc.). Shape: `{name, reason}`. Aliased by `meta.skill.skipped`. |
|
|
150
|
+
|
|
151
|
+
Dispatchers can suppress the block entirely by setting `meta.skipProjectReviewSkills: true` on the review work item — the playbook then renders identically to the pre-W-mq16xtdx 8-step contract. Use this for meta-reviews of the review skill itself; the engine still accepts `meta.review.skillSkipped` in the report regardless. (W-mq1cczi90006b21f generalized this to `meta.skipProjectSkills`, which suppresses the block on every dispatch type — both flags are honored.)
|
|
87
152
|
|
|
88
153
|
## `failure_class` enum
|
|
89
154
|
|
|
@@ -0,0 +1,133 @@
|
|
|
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
|
+
| `engine/discover-review-skills.js` | Thin re-export shim. Backward-compat only — new code uses `discover-project-skills.js`. |
|
|
17
|
+
|
|
18
|
+
## What gets discovered
|
|
19
|
+
|
|
20
|
+
Per project worktree, the discovery walk visits:
|
|
21
|
+
|
|
22
|
+
- `<projectRoot>/.claude/skills/*/SKILL.md` — top-level skill packs.
|
|
23
|
+
- `<projectRoot>/.claude/commands/*.md` — top-level slash-commands.
|
|
24
|
+
- `<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.
|
|
25
|
+
- `<projectRoot>/<area>/.claude/commands/*.md` — same, for nested commands.
|
|
26
|
+
- `<projectRoot>/.github/copilot-instructions.md` — slash-command mentions (top 32 KB).
|
|
27
|
+
- `<projectRoot>/CLAUDE.md` — slash-command mentions (top 32 KB).
|
|
28
|
+
|
|
29
|
+
Each discovery entry has shape:
|
|
30
|
+
|
|
31
|
+
```js
|
|
32
|
+
{
|
|
33
|
+
kind: 'skill' | 'command' | 'slash-command',
|
|
34
|
+
name: string, // e.g. "code-reviewer" or "/review-swarm"
|
|
35
|
+
path: string, // relative to projectRoot
|
|
36
|
+
oneLineDescription: string, // ≤200 chars
|
|
37
|
+
intents: string[] // closed enum, see below
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The walk is **cheap and bounded** — preserve every guardrail in
|
|
42
|
+
`engine/discover-project-skills.js`:
|
|
43
|
+
|
|
44
|
+
- ≤ 50 files per surface
|
|
45
|
+
- 8 KB per skill / 32 KB per docs file
|
|
46
|
+
- 250 ms walltime budget — bails rather than blocks dispatch
|
|
47
|
+
- ≤ 50 nested areas probed
|
|
48
|
+
- Missing worktree / unreadable → `[]` (never throws)
|
|
49
|
+
|
|
50
|
+
## The intent vocabulary (CLOSED)
|
|
51
|
+
|
|
52
|
+
| Intent | What belongs here |
|
|
53
|
+
|---|---|
|
|
54
|
+
| `review` | code review, PR review, swarm review (`code-reviewer`, `/review-swarm`, `/code-review`, etc.) |
|
|
55
|
+
| `build` | scaffold, generate, bump, migrate, codemod, refactor (`bump-fmf-android`, `workspace`, `vhd`, etc.) |
|
|
56
|
+
| `fix` | debug, triage, repro, regression, flake-killing (`triage-flake`, `cover-pr` for missing tests on PR…) |
|
|
57
|
+
| `test` | author tests, increase coverage, validate (`integration-tests`, `run-tests`, `qa-validate`) |
|
|
58
|
+
| `plan` | PRD authoring, ADR, design-doc, decompose (`substitute-scheduler-template-vars`, `decompose`) |
|
|
59
|
+
| `research` | investigate, gather-impact, telemetry-query, audit (`gather-impact`, `audit-deprecated`) |
|
|
60
|
+
| `deploy` | release, publish, buddy-build, rollout, ship (`buddy-build`, `track-pr`) |
|
|
61
|
+
| `observability` | telemetry, logs, kusto, monitoring, metrics dashboards (`kusto-telemetry-lmf-quality-report`, `weekly-repo-summary`) |
|
|
62
|
+
| `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. |
|
|
63
|
+
|
|
64
|
+
### How intents are assigned
|
|
65
|
+
|
|
66
|
+
For each discovered entry, `classifyIntents(...)` does:
|
|
67
|
+
|
|
68
|
+
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:
|
|
69
|
+
```yaml
|
|
70
|
+
---
|
|
71
|
+
name: bump-fmf-android
|
|
72
|
+
description: Bump the FMF SDK version pin in OCM Android
|
|
73
|
+
intents: [build, deploy]
|
|
74
|
+
---
|
|
75
|
+
```
|
|
76
|
+
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.
|
|
77
|
+
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.
|
|
78
|
+
|
|
79
|
+
### Slash-commands scraped from docs
|
|
80
|
+
|
|
81
|
+
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).
|
|
82
|
+
|
|
83
|
+
## The playbook → intent map
|
|
84
|
+
|
|
85
|
+
Defined in `engine/playbook-intents.js`. The default mapping at time of writing:
|
|
86
|
+
|
|
87
|
+
| Playbook | Intents surfaced |
|
|
88
|
+
|---|---|
|
|
89
|
+
| `review` | `['review']` |
|
|
90
|
+
| `fix` | `['fix', 'test', 'review']` |
|
|
91
|
+
| `implement` / `implement-shared` | `['build', 'test', 'research']` |
|
|
92
|
+
| `plan` / `plan-to-prd` / `decompose` | `['plan', 'research']` |
|
|
93
|
+
| `docs` | `['research']` |
|
|
94
|
+
| `verify` | `['test', 'review']` |
|
|
95
|
+
| `build-and-test` | `['build', 'test']` |
|
|
96
|
+
| `test` / `qa-validate` | `['test']` |
|
|
97
|
+
| `explore` | `['research']` |
|
|
98
|
+
| (all others) | `[]` — no block rendered |
|
|
99
|
+
|
|
100
|
+
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).
|
|
101
|
+
|
|
102
|
+
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.
|
|
103
|
+
|
|
104
|
+
## Adding a new playbook
|
|
105
|
+
|
|
106
|
+
1. Add a row to `PLAYBOOK_INTENTS` in `engine/playbook-intents.js` mapping your playbook name to the intent set it should surface.
|
|
107
|
+
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:
|
|
108
|
+
```md
|
|
109
|
+
{{#project_skills_block}}
|
|
110
|
+
{{project_skills_block}}
|
|
111
|
+
|
|
112
|
+
{{/project_skills_block}}
|
|
113
|
+
```
|
|
114
|
+
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.
|
|
115
|
+
|
|
116
|
+
## Adding a new intent
|
|
117
|
+
|
|
118
|
+
1. Add a regex to `INTENT_KEYWORDS` in `engine/discover-project-skills.js`. Use `\b` word boundaries.
|
|
119
|
+
2. Add the value to `INTENT_VOCABULARY` so explicit frontmatter `intents:` entries with the new name are accepted.
|
|
120
|
+
3. Add a row to the table above, with a one-line description of what belongs.
|
|
121
|
+
4. Update one or more playbook entries in `engine/playbook-intents.js` to include the new intent.
|
|
122
|
+
|
|
123
|
+
Keep the vocabulary tight — every additional intent is noise risk in every prompt that surfaces it.
|
|
124
|
+
|
|
125
|
+
## Completion-report contract
|
|
126
|
+
|
|
127
|
+
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.*`.
|
|
128
|
+
|
|
129
|
+
## Tests
|
|
130
|
+
|
|
131
|
+
- `test/unit/discover-project-skills.test.js` — discovery + classification + intent filtering + render + per-playbook splice coverage.
|
|
132
|
+
|
|
133
|
+
When you change discovery, classification, or the playbook→intent map, extend or update this test file.
|
package/engine/cli.js
CHANGED
|
@@ -163,18 +163,30 @@ function handleCommand(cmd, args) {
|
|
|
163
163
|
//
|
|
164
164
|
// `minions work --help` used to create ghost work items with title='--help'
|
|
165
165
|
// because the bare-string `title` was truthy and bypassed the `!title`
|
|
166
|
-
// usage check.
|
|
167
|
-
//
|
|
168
|
-
// command-specific `Usage:` output. `pr` and `bridge` handle help inline.
|
|
166
|
+
// usage check. Same class of bug exists in `spawn`/`plan`/`complete` —
|
|
167
|
+
// every command that takes a positional arg and tests it with `if (!arg)`.
|
|
169
168
|
//
|
|
170
|
-
//
|
|
171
|
-
//
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
169
|
+
// Intercept here so a single guard covers the whole command set. `pr` and
|
|
170
|
+
// `bridge` already handle `help`/`--help`/`-h` inline (see their own
|
|
171
|
+
// first-arg branches), so let them route through unchanged.
|
|
172
|
+
//
|
|
173
|
+
// W-mq60aco9: print the *per-command* usage (matching the convention from
|
|
174
|
+
// PR #3054 which added per-positional `Usage:` for work/spawn/plan/complete).
|
|
175
|
+
// Previously this branch printed the global `Commands:` list and short-
|
|
176
|
+
// circuited the per-command guards — so `minions work --help` advertised
|
|
177
|
+
// the wrong help text. Fall back to the global list only for commands
|
|
178
|
+
// missing from CLI_COMMAND_DOCS. The per-command `_isHelpArg` guards in
|
|
179
|
+
// work/spawn/plan/complete remain as defense-in-depth for any caller that
|
|
180
|
+
// bypasses handleCommand.
|
|
181
|
+
if (cmd !== 'pr' && cmd !== 'bridge' && isHelpToken(args && args[0])) {
|
|
182
|
+
const doc = CLI_COMMAND_DOCS[cmd];
|
|
183
|
+
if (doc) {
|
|
184
|
+
console.log(`Usage: minions ${cmd}${doc.args ? ' ' + doc.args : ''}`);
|
|
185
|
+
if (doc.summary) console.log(` ${doc.summary}`);
|
|
186
|
+
} else {
|
|
187
|
+
console.log('Commands:');
|
|
188
|
+
for (const line of formatCliCommandHelpLines()) console.log(line);
|
|
189
|
+
}
|
|
178
190
|
return;
|
|
179
191
|
}
|
|
180
192
|
return commands[cmd](...args);
|