@dtlabs/ai-toolkit 0.3.1 → 0.5.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/.claude/agents/install-toolkit.md +1 -46
- package/.claude/workflows/pm-phase2.js +38 -32
- package/.claude/workflows/pm-phase3.js +148 -236
- package/CHANGELOG.md +22 -0
- package/CLAUDE.global.md +34 -0
- package/CLAUDE.md +15 -99
- package/bin/cli.js +1 -51
- package/package.json +2 -1
|
@@ -171,51 +171,7 @@ configuration is out of scope and risks clobbering the user's existing settings.
|
|
|
171
171
|
|
|
172
172
|
---
|
|
173
173
|
|
|
174
|
-
## Step 5 —
|
|
175
|
-
|
|
176
|
-
After copying the toolkit files, check the state of Matt Pocock's skills:
|
|
177
|
-
|
|
178
|
-
1. **Detect installed version**: check if `~/.claude/skills/mattpocock/.version` exists and read it. If not found, try `npm list -g mattpocock --json` to get the cached version. If neither works, assume not installed.
|
|
179
|
-
|
|
180
|
-
2. **Detect latest available version**: run `npm view mattpocock version` to get the current version on npm. If offline or unavailable, skip the version comparison.
|
|
181
|
-
|
|
182
|
-
3. **Present the appropriate prompt** using `AskUserQuestion`:
|
|
183
|
-
|
|
184
|
-
**Not installed:**
|
|
185
|
-
```
|
|
186
|
-
question: "Matt Pocock's skills are not installed. Install them now?"
|
|
187
|
-
description: "Includes define-feature, grilling, TDD, prototype, handoff, and more.
|
|
188
|
-
Installs globally via: npx skills@latest add mattpocock/skills"
|
|
189
|
-
options:
|
|
190
|
-
- "Yes — install now"
|
|
191
|
-
- "No — skip (install manually later)"
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
**Installed, update available (installed=vX, latest=vY):**
|
|
195
|
-
```
|
|
196
|
-
question: "Matt Pocock skills v{installed} is installed. Update to v{latest}?"
|
|
197
|
-
options:
|
|
198
|
-
- "Yes — update now"
|
|
199
|
-
- "No — keep current version"
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
**Already up to date:**
|
|
203
|
-
```
|
|
204
|
-
question: "Matt Pocock skills v{installed} is already up to date. Re-install?"
|
|
205
|
-
options:
|
|
206
|
-
- "Yes — re-install"
|
|
207
|
-
- "No — skip"
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
4. If the user selects **Yes** (install or update), run:
|
|
211
|
-
```bash
|
|
212
|
-
npx skills@latest add mattpocock/skills
|
|
213
|
-
```
|
|
214
|
-
Report the outcome. If it fails, show the manual install command.
|
|
215
|
-
|
|
216
|
-
---
|
|
217
|
-
|
|
218
|
-
## Step 6 — Compact Instructions opt-in
|
|
174
|
+
## Step 5 — Compact Instructions opt-in
|
|
219
175
|
|
|
220
176
|
The toolkit includes a `# Compact instructions` section for `~/.claude/CLAUDE.md` that guides Claude's auto-compaction (what to keep, what to drop) and enables proactive topic-change suggestions.
|
|
221
177
|
|
|
@@ -304,7 +260,6 @@ New files copied: N
|
|
|
304
260
|
Modified/overwritten: N
|
|
305
261
|
Modified/kept: N (user chose to keep existing version)
|
|
306
262
|
Unchanged (same): N (skipped silently)
|
|
307
|
-
Matt Pocock skills: ✅ installed v{X} / ⬆️ updated v{old}→v{new} / ⏭ skipped / ✅ already up to date v{X}
|
|
308
263
|
Spawn depth: ✅ CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH=2+ present / ⚠️ MISSING — see action above
|
|
309
264
|
Compact instructions: {compact_instructions_status}
|
|
310
265
|
──────────────────────────────────────────────────
|
|
@@ -93,16 +93,18 @@ Write {feature_dir}/{PREFIX}-Effort-Estimate.md with this format:
|
|
|
93
93
|
| Human estimate | {human_estimate} (sequential, no parallelism) |
|
|
94
94
|
| Agent estimate | {agent_estimate} (parallel dispatch, critical path only) |
|
|
95
95
|
|
|
96
|
-
## Per-
|
|
96
|
+
## Per-Phase Breakdown
|
|
97
97
|
|
|
98
|
-
|
|
|
99
|
-
|
|
100
|
-
{one row per US extracted from Section 4}
|
|
98
|
+
| Phase | Title | Tasks | Domains | Est. Human | Est. Agent | Actual Human | Actual Agent |
|
|
99
|
+
|-------|-------|-------|---------|-----------|-----------|-------------|-------------|
|
|
100
|
+
{one row per phase (INFRA + each US) extracted from Section 4 of the Work Breakdown — use ~2h per BE task, ~1h per TEST task, ~30min per INFRA task for human estimate; agent estimate = human / 6 as baseline}
|
|
101
|
+
| **Total** | | **{total_tasks}** | | **{human_estimate}** | **{agent_estimate}** | **—** | **—** |
|
|
101
102
|
|
|
102
103
|
## Notes
|
|
103
104
|
- Human estimate assumes sequential execution with no parallelism.
|
|
104
|
-
- Agent estimate assumes parallel dispatch of independent tasks within each phase.
|
|
105
|
-
- Actual
|
|
105
|
+
- Agent estimate assumes parallel dispatch of independent tasks within each phase (critical path only).
|
|
106
|
+
- Actual Human: filled in if a human developer performed or reviewed the implementation.
|
|
107
|
+
- Actual Agent: filled in by pm-phase3 after implementation completes.
|
|
106
108
|
|
|
107
109
|
TASK 3 — Write the Token-Estimate.md file.
|
|
108
110
|
Write {feature_dir}/{PREFIX}-Token-Estimate.md with this format:
|
|
@@ -111,39 +113,43 @@ Write {feature_dir}/{PREFIX}-Token-Estimate.md with this format:
|
|
|
111
113
|
|
|
112
114
|
## Phase 1 — Documentation (Actuals)
|
|
113
115
|
|
|
114
|
-
| Agent | Task | Model | Tokens
|
|
115
|
-
|
|
116
|
-
| generate-requirements | Generate requirements from feature.md | haiku |
|
|
117
|
-
| generate-tech-spec | Generate tech spec from feature.md | haiku |
|
|
118
|
-
| validate-feature-docs | Validate requirements + tech spec | haiku |
|
|
116
|
+
| Agent | Task | Model | Tokens Est. | Tokens Actual |
|
|
117
|
+
|-------|------|-------|------------|--------------|
|
|
118
|
+
| generate-requirements | Generate requirements from feature.md | haiku | — | {phase1_req_tokens} |
|
|
119
|
+
| generate-tech-spec | Generate tech spec from feature.md | haiku | — | {phase1_spec_tokens} |
|
|
120
|
+
| validate-feature-docs | Validate requirements + tech spec | haiku | — | {phase1_val_tokens} |
|
|
121
|
+
| **Phase 1 total** | | | **—** | **${phase1Tokens}** |
|
|
119
122
|
|
|
120
123
|
## Phase 2 — Work Breakdown (Actuals)
|
|
121
124
|
|
|
122
|
-
| Agent | Task | Model | Tokens
|
|
123
|
-
|
|
124
|
-
| generate-work-breakdown | Generate work breakdown from docs | haiku |
|
|
125
|
+
| Agent | Task | Model | Tokens Est. | Tokens Actual |
|
|
126
|
+
|-------|------|-------|------------|--------------|
|
|
127
|
+
| generate-work-breakdown | Generate work breakdown from docs | haiku | — | {wbTokens from above} |
|
|
128
|
+
| **Phase 2 total** | | | **—** | **{wbTokens from above}** |
|
|
125
129
|
|
|
126
130
|
## Phase 3 — Implementation (Estimates)
|
|
127
131
|
|
|
128
132
|
Estimates based on {total_tasks} tasks ({domain_breakdown}), {user_stories} User Stories.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
| Agent | Task | Model | Tokens
|
|
132
|
-
|
|
133
|
-
|
|
|
134
|
-
|
|
|
135
|
-
|
|
|
136
|
-
|
|
|
137
|
-
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
| Phase
|
|
144
|
-
|
|
145
|
-
| Phase
|
|
146
|
-
|
|
|
133
|
+
Baseline: ~15,000 tokens/BE task, ~8,000/TEST task, ~5,000/INFRA task.
|
|
134
|
+
|
|
135
|
+
| Agent | Task | Model | Tokens Est. | Tokens Actual |
|
|
136
|
+
|-------|------|-------|------------|--------------|
|
|
137
|
+
| developer-backend | Implement BE/INFRA tasks | sonnet | {estimated: be_tasks * 15000 + infra_tasks * 5000} | — |
|
|
138
|
+
| developer-testing | Implement TEST tasks | sonnet | {estimated: test_tasks * 8000} | — |
|
|
139
|
+
| review-solution (×{user_stories}) | Architect review per US | sonnet | {estimated: user_stories * 8000} | — |
|
|
140
|
+
| remediation | Fix review issues | sonnet | ~10,000 | — |
|
|
141
|
+
| pr-and-registry | Push branch, create PR | sonnet | ~5,000 | — |
|
|
142
|
+
| write-actuals | Update Token/Effort Estimate | sonnet | ~3,000 | — |
|
|
143
|
+
| **Phase 3 total** | | | **{sum of phase 3 estimates}** | **—** |
|
|
144
|
+
|
|
145
|
+
## Grand Total
|
|
146
|
+
|
|
147
|
+
| Phase | Tokens Est. | Tokens Actual |
|
|
148
|
+
|-------|------------|--------------|
|
|
149
|
+
| Phase 1 — Documentation | — | ${phase1Tokens} |
|
|
150
|
+
| Phase 2 — Work Breakdown | — | {wbTokens from above} |
|
|
151
|
+
| Phase 3 — Implementation | {sum of phase 3 estimates} | — |
|
|
152
|
+
| **Total** | **{sum of phase 3 estimates}** | **{phase1Tokens + wbTokens} (partial)** |
|
|
147
153
|
|
|
148
154
|
---
|
|
149
155
|
*Actuals will be appended by pm-phase3 after implementation completes.*
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export const meta = {
|
|
2
2
|
name: 'pm-phase3',
|
|
3
|
-
description: 'Feature delivery phase 3: parse WB → dispatch specialist agents per US (
|
|
3
|
+
description: 'Feature delivery phase 3: parse WB → dispatch specialist agents per US (commit per phase) → single architect review → PR → actuals.',
|
|
4
4
|
phases: [
|
|
5
|
-
{ title: 'Parse', detail: 'Parse Work Breakdown into structured
|
|
6
|
-
{ title: 'Implementation', detail: 'Dispatch developer agents per
|
|
7
|
-
{ title: '
|
|
5
|
+
{ title: 'Parse', detail: 'Parse Work Breakdown CSV into structured phases' },
|
|
6
|
+
{ title: 'Implementation', detail: 'Dispatch developer agents per phase, commit each one' },
|
|
7
|
+
{ title: 'Review', detail: 'Single architect review on full feature diff' },
|
|
8
8
|
{ title: 'PR', detail: 'Push branch, create PR, update registry' },
|
|
9
9
|
{ title: 'Actuals', detail: 'Write Token-Estimate and Effort-Estimate actuals' },
|
|
10
10
|
],
|
|
@@ -17,12 +17,10 @@ const branchMatch = argStr.match(/--branch\s+(\S+)/)
|
|
|
17
17
|
const branch = branchMatch ? branchMatch[1] : null
|
|
18
18
|
|
|
19
19
|
const tokenLedger = []
|
|
20
|
-
const escalations = []
|
|
21
20
|
|
|
22
21
|
// ── Parse Work Breakdown CSV (deterministic, no AI) ───────────────────────────
|
|
23
22
|
phase('Parse')
|
|
24
23
|
|
|
25
|
-
// Derive feature_dir and prefix from featurePath (e.g. "docs/features/FTR-004-.../feature.md")
|
|
26
24
|
const featureDir = featurePath.replace(/\/[^/]+$/, '')
|
|
27
25
|
const prefixMatch = featureDir.match(/([A-Z]+-\d+)/)
|
|
28
26
|
const prefix = prefixMatch ? prefixMatch[1] : 'FTR-000'
|
|
@@ -30,22 +28,16 @@ const csvPath = `${featureDir}/${prefix}-Work-Breakdown.csv`
|
|
|
30
28
|
|
|
31
29
|
log(`Reading CSV: ${csvPath}`)
|
|
32
30
|
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
required: ['content'],
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const csvResult = await agent(
|
|
40
|
-
`Read the file at path: ${csvPath}\nReturn its full text content as the "content" field.`,
|
|
41
|
-
{ label: 'read-wb-csv', phase: 'Parse', schema: READ_SCHEMA, model: 'haiku' }
|
|
31
|
+
const csvContent = await agent(
|
|
32
|
+
`Read the file at path: ${csvPath}\nReturn ONLY the raw file contents, nothing else. No explanation, no formatting, no JSON wrapping — just the raw text of the file.`,
|
|
33
|
+
{ label: 'read-wb-csv', phase: 'Parse', model: 'haiku' }
|
|
42
34
|
)
|
|
43
35
|
|
|
44
36
|
// Parse CSV into structured phases — pure JS, no AI
|
|
45
|
-
const rows =
|
|
37
|
+
const rows = csvContent
|
|
46
38
|
.split('\n')
|
|
47
39
|
.map(l => l.trim())
|
|
48
|
-
.filter(l => l && !l.startsWith('phase_id'))
|
|
40
|
+
.filter(l => l && !l.startsWith('phase_id'))
|
|
49
41
|
.map(l => {
|
|
50
42
|
const [phase_id, phase_title, commit_message, depends_on, task_id, task_title, domain, agent_type] = l.split('|')
|
|
51
43
|
return { phase_id, phase_title, commit_message, depends_on: depends_on || '', task_id, task_title, domain, agent_type }
|
|
@@ -60,7 +52,7 @@ for (const row of rows) {
|
|
|
60
52
|
phase_id: row.phase_id,
|
|
61
53
|
title: row.phase_title,
|
|
62
54
|
commit_message: row.commit_message,
|
|
63
|
-
depends_on: row.depends_on.split(' ').filter(Boolean),
|
|
55
|
+
depends_on: row.depends_on.split(' ').filter(Boolean),
|
|
64
56
|
impl_tasks: [],
|
|
65
57
|
test_tasks: [],
|
|
66
58
|
})
|
|
@@ -93,11 +85,9 @@ const allPhases = Array.from(phaseMap.values()).map(p => ({
|
|
|
93
85
|
}))
|
|
94
86
|
|
|
95
87
|
const wb = { prefix, feature_dir: featureDir, phases: allPhases }
|
|
96
|
-
|
|
97
88
|
log(`CSV parsed: ${rows.length} tasks → ${wb.phases.length} phases for ${wb.prefix}`)
|
|
98
89
|
|
|
99
|
-
// Build execution waves: phases whose dependencies are all satisfied
|
|
100
|
-
// Wave 0 = no deps, Wave 1 = depends only on Wave 0 phases, etc.
|
|
90
|
+
// Build execution waves: phases whose dependencies are all satisfied run in parallel
|
|
101
91
|
const buildWaves = (phases) => {
|
|
102
92
|
const done = new Set()
|
|
103
93
|
const waves = []
|
|
@@ -105,7 +95,6 @@ const buildWaves = (phases) => {
|
|
|
105
95
|
while (remaining.length > 0) {
|
|
106
96
|
const ready = remaining.filter(p => p.depends_on.every(d => done.has(d)))
|
|
107
97
|
if (ready.length === 0) {
|
|
108
|
-
// Circular or unresolvable deps — run the rest sequentially to avoid deadlock
|
|
109
98
|
waves.push(remaining)
|
|
110
99
|
break
|
|
111
100
|
}
|
|
@@ -119,131 +108,71 @@ const buildWaves = (phases) => {
|
|
|
119
108
|
const waves = buildWaves(wb.phases)
|
|
120
109
|
log(`Execution plan: ${waves.length} wave(s) — ${waves.map((w, i) => `wave${i+1}:[${w.map(p => p.phase_id).join(',')}]`).join(' ')}`)
|
|
121
110
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const usPassed = []
|
|
125
|
-
const usEscalated = []
|
|
126
|
-
let issuesPath = ''
|
|
127
|
-
let issuesOpen = 0
|
|
111
|
+
let phasesDone = 0
|
|
112
|
+
const usPassed = []
|
|
128
113
|
|
|
129
114
|
// ── Implementation ────────────────────────────────────────────────────────────
|
|
130
115
|
phase('Implementation')
|
|
131
116
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
properties: {
|
|
135
|
-
has_critical: { type: 'boolean' },
|
|
136
|
-
findings: { type: 'string' },
|
|
137
|
-
issues_md: { type: 'string' },
|
|
138
|
-
},
|
|
139
|
-
required: ['has_critical'],
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// executePhase: runs impl_groups → test_groups → review → rework → commit for one phase
|
|
117
|
+
// executePhase: impl_groups (parallel) → test_groups (parallel) → commit
|
|
118
|
+
// No inline review — review runs once after all phases complete.
|
|
143
119
|
const executePhase = async (implPhase) => {
|
|
144
120
|
log(`Starting phase ${implPhase.phase_id}: ${implPhase.title}`)
|
|
145
121
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
`${featurePath} ${group.task_ids.join(',')}${reworkSuffix}`,
|
|
161
|
-
{
|
|
162
|
-
agentType: group.agent_type,
|
|
163
|
-
label: `${group.agent_type}:${implPhase.phase_id}${reworkCycle > 0 ? ':rework' + reworkCycle : ''}`,
|
|
164
|
-
phase: 'Implementation',
|
|
165
|
-
}
|
|
166
|
-
)
|
|
167
|
-
))
|
|
168
|
-
const implTokens = budget.spent() - beforeImpl
|
|
169
|
-
tokenLedger.push({
|
|
170
|
-
agent: `${implPhase.impl_groups.map(g => g.agent_type).join('+')}:${implPhase.phase_id}${reworkCycle > 0 ? ':rework' + reworkCycle : ''}`,
|
|
171
|
-
model: 'sonnet',
|
|
172
|
-
phase_delta_tokens: implTokens,
|
|
173
|
-
})
|
|
174
|
-
log(`Phase ${implPhase.phase_id} impl groups done — ${implTokens} tokens`)
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Step 2 — test groups in parallel (TEST) — after impl groups
|
|
178
|
-
if (implPhase.test_groups.length > 0) {
|
|
179
|
-
const beforeTest = budget.spent()
|
|
180
|
-
await parallel(implPhase.test_groups.map(group => () =>
|
|
181
|
-
agent(
|
|
182
|
-
`${featurePath} ${group.task_ids.join(',')}${reworkSuffix}`,
|
|
183
|
-
{
|
|
184
|
-
agentType: group.agent_type,
|
|
185
|
-
label: `${group.agent_type}:${implPhase.phase_id}${reworkCycle > 0 ? ':rework' + reworkCycle : ''}`,
|
|
186
|
-
phase: 'Implementation',
|
|
187
|
-
}
|
|
188
|
-
)
|
|
189
|
-
))
|
|
190
|
-
const testTokens = budget.spent() - beforeTest
|
|
191
|
-
tokenLedger.push({
|
|
192
|
-
agent: `developer-testing:${implPhase.phase_id}${reworkCycle > 0 ? ':rework' + reworkCycle : ''}`,
|
|
193
|
-
model: 'sonnet',
|
|
194
|
-
phase_delta_tokens: testTokens,
|
|
195
|
-
})
|
|
196
|
-
log(`Phase ${implPhase.phase_id} test groups done — ${testTokens} tokens`)
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Step 3 — review-solution
|
|
200
|
-
const beforeReview = budget.spent()
|
|
201
|
-
const review = await agent(
|
|
202
|
-
`${featurePath} --scope ${implPhase.phase_id}`,
|
|
203
|
-
{
|
|
204
|
-
agentType: 'review-solution',
|
|
205
|
-
label: `review-solution:${implPhase.phase_id}`,
|
|
206
|
-
phase: 'Implementation',
|
|
207
|
-
schema: REVIEW_SCHEMA,
|
|
208
|
-
}
|
|
209
|
-
)
|
|
210
|
-
const reviewTokens = budget.spent() - beforeReview
|
|
122
|
+
// Step 1 — impl groups in parallel (INFRA / BE / FE)
|
|
123
|
+
if (implPhase.impl_groups.length > 0) {
|
|
124
|
+
const beforeImpl = budget.spent()
|
|
125
|
+
await parallel(implPhase.impl_groups.map(group => () =>
|
|
126
|
+
agent(
|
|
127
|
+
`${featurePath} ${group.task_ids.join(',')}`,
|
|
128
|
+
{
|
|
129
|
+
agentType: group.agent_type,
|
|
130
|
+
label: `${group.agent_type}:${implPhase.phase_id}`,
|
|
131
|
+
phase: 'Implementation',
|
|
132
|
+
}
|
|
133
|
+
)
|
|
134
|
+
))
|
|
135
|
+
const implTokens = budget.spent() - beforeImpl
|
|
211
136
|
tokenLedger.push({
|
|
212
|
-
agent:
|
|
213
|
-
model:
|
|
214
|
-
phase_delta_tokens:
|
|
137
|
+
agent: `${implPhase.impl_groups.map(g => g.agent_type).join('+')}:${implPhase.phase_id}`,
|
|
138
|
+
model: 'sonnet',
|
|
139
|
+
phase_delta_tokens: implTokens,
|
|
215
140
|
})
|
|
216
|
-
|
|
217
|
-
if (review && !review.has_critical) {
|
|
218
|
-
passed = true
|
|
219
|
-
if (review.issues_md) {
|
|
220
|
-
await agent(
|
|
221
|
-
`Append the following WARNING/INFO findings to ${wb.feature_dir}/${prefix}-Issues.md (create the file if it does not exist, with a header "# Issues Register — ${prefix}"):\n\n${review.issues_md}`,
|
|
222
|
-
{ label: `log-issues:${implPhase.phase_id}`, phase: 'Implementation' }
|
|
223
|
-
)
|
|
224
|
-
}
|
|
225
|
-
} else {
|
|
226
|
-
lastFindings = review?.findings || 'unspecified critical issues'
|
|
227
|
-
reworkCycle++
|
|
228
|
-
log(`Phase ${implPhase.phase_id}: critical findings — rework cycle ${reworkCycle}`)
|
|
229
|
-
}
|
|
141
|
+
log(`Phase ${implPhase.phase_id} impl done — ${implTokens} tokens`)
|
|
230
142
|
}
|
|
231
143
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
144
|
+
// Step 2 — test groups in parallel (TEST)
|
|
145
|
+
if (implPhase.test_groups.length > 0) {
|
|
146
|
+
const beforeTest = budget.spent()
|
|
147
|
+
await parallel(implPhase.test_groups.map(group => () =>
|
|
148
|
+
agent(
|
|
149
|
+
`${featurePath} ${group.task_ids.join(',')}`,
|
|
150
|
+
{
|
|
151
|
+
agentType: group.agent_type,
|
|
152
|
+
label: `developer-testing:${implPhase.phase_id}`,
|
|
153
|
+
phase: 'Implementation',
|
|
154
|
+
}
|
|
155
|
+
)
|
|
156
|
+
))
|
|
157
|
+
const testTokens = budget.spent() - beforeTest
|
|
158
|
+
tokenLedger.push({
|
|
159
|
+
agent: `developer-testing:${implPhase.phase_id}`,
|
|
160
|
+
model: 'sonnet',
|
|
161
|
+
phase_delta_tokens: testTokens,
|
|
162
|
+
})
|
|
163
|
+
log(`Phase ${implPhase.phase_id} tests done — ${testTokens} tokens`)
|
|
244
164
|
}
|
|
245
165
|
|
|
166
|
+
// Step 3 — commit this phase
|
|
167
|
+
const commitMsg = implPhase.commit_message || `feat(${prefix}): implement ${implPhase.phase_id}`
|
|
168
|
+
await agent(
|
|
169
|
+
`Run these git commands in the repository root:\ngit add -A\ngit commit -m "${commitMsg}"\nIf there is nothing to commit, that is fine — just report success.`,
|
|
170
|
+
{ label: `commit:${implPhase.phase_id}`, phase: 'Implementation', model: 'haiku' }
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
if (implPhase.phase_id !== 'INFRA') usPassed.push(implPhase.phase_id)
|
|
246
174
|
phasesDone++
|
|
175
|
+
log(`Phase ${implPhase.phase_id} committed`)
|
|
247
176
|
}
|
|
248
177
|
|
|
249
178
|
// Execute waves: phases in the same wave run in parallel, waves are sequential
|
|
@@ -256,69 +185,57 @@ for (const wave of waves) {
|
|
|
256
185
|
}
|
|
257
186
|
}
|
|
258
187
|
|
|
259
|
-
|
|
260
|
-
const ISSUES_SCHEMA = {
|
|
261
|
-
type: 'object',
|
|
262
|
-
properties: {
|
|
263
|
-
exists: { type: 'boolean' },
|
|
264
|
-
open_count: { type: 'number' },
|
|
265
|
-
path: { type: 'string' },
|
|
266
|
-
},
|
|
267
|
-
required: ['exists', 'open_count'],
|
|
268
|
-
}
|
|
269
|
-
const issuesResult = await agent(
|
|
270
|
-
`Check if ${wb.feature_dir}/${prefix}-Issues.md exists. If it does, count rows with status OPEN. Return exists, open_count, and the full path.`,
|
|
271
|
-
{ label: 'count-open-issues', phase: 'Implementation', schema: ISSUES_SCHEMA }
|
|
272
|
-
)
|
|
273
|
-
issuesPath = issuesResult?.path || ''
|
|
274
|
-
issuesOpen = issuesResult?.open_count || 0
|
|
275
|
-
log(`Implementation complete — ${phasesDone} phases, ${usPassed.length} US passed, ${usEscalated.length} escalated, ${issuesOpen} open issues`)
|
|
188
|
+
log(`Implementation complete — ${phasesDone} phases, ${usPassed.length} US implemented`)
|
|
276
189
|
|
|
277
|
-
// ──
|
|
278
|
-
phase('
|
|
190
|
+
// ── Review — single pass over the full feature diff ───────────────────────────
|
|
191
|
+
phase('Review')
|
|
279
192
|
|
|
280
|
-
const
|
|
193
|
+
const REVIEW_SCHEMA = {
|
|
281
194
|
type: 'object',
|
|
282
195
|
properties: {
|
|
283
|
-
|
|
284
|
-
|
|
196
|
+
has_critical: { type: 'boolean' },
|
|
197
|
+
findings: { type: 'string' },
|
|
198
|
+
issues_md: { type: 'string' },
|
|
285
199
|
},
|
|
286
|
-
required: ['
|
|
200
|
+
required: ['has_critical'],
|
|
287
201
|
}
|
|
288
202
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
For each OPEN issue:
|
|
302
|
-
- If severity is INFO: mark it DEFERRED immediately (update Status column to DEFERRED). Do not dispatch a developer agent.
|
|
303
|
-
- If severity is WARNING: dispatch the appropriate developer agent (developer-backend for most cases) with the issue description. Then spawn review-solution to verify the fix. Max 1 retry per issue. If unresolved after 1 retry, mark DEFERRED.
|
|
304
|
-
|
|
305
|
-
After processing all issues, return: { "issues_fixed": N, "issues_deferred": N }
|
|
203
|
+
const beforeReview = budget.spent()
|
|
204
|
+
const review = await agent(
|
|
205
|
+
`${featurePath} --scope all`,
|
|
206
|
+
{
|
|
207
|
+
agentType: 'review-solution',
|
|
208
|
+
label: 'review-solution:full-feature',
|
|
209
|
+
phase: 'Review',
|
|
210
|
+
schema: REVIEW_SCHEMA,
|
|
211
|
+
}
|
|
212
|
+
)
|
|
213
|
+
const reviewTokens = budget.spent() - beforeReview
|
|
214
|
+
tokenLedger.push({ agent: 'review-solution:full-feature', model: 'sonnet', phase_delta_tokens: reviewTokens })
|
|
306
215
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
phase: 'Remediation',
|
|
311
|
-
schema: REM_SCHEMA,
|
|
312
|
-
}
|
|
313
|
-
)
|
|
216
|
+
let issuesOpen = 0
|
|
217
|
+
let issuesPath = `${wb.feature_dir}/${prefix}-Issues.md`
|
|
218
|
+
let hasCritical = false
|
|
314
219
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
220
|
+
if (review) {
|
|
221
|
+
hasCritical = review.has_critical || false
|
|
222
|
+
if (review.issues_md) {
|
|
223
|
+
await agent(
|
|
224
|
+
`Write the following content to ${issuesPath} (create or overwrite the file):\n\n# Issues Register — ${prefix}\n\n${review.issues_md}`,
|
|
225
|
+
{ label: 'write-issues', phase: 'Review', model: 'haiku' }
|
|
226
|
+
)
|
|
227
|
+
// Count OPEN issues from issues_md (rough count of "OPEN" occurrences)
|
|
228
|
+
issuesOpen = (review.issues_md.match(/\bOPEN\b/g) || []).length
|
|
229
|
+
log(`Review complete — has_critical: ${hasCritical}, open issues: ${issuesOpen}`)
|
|
230
|
+
} else {
|
|
231
|
+
log(`Review complete — no issues found`)
|
|
232
|
+
}
|
|
320
233
|
} else {
|
|
321
|
-
log(
|
|
234
|
+
log(`Review agent returned null — skipping issues register`)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (hasCritical) {
|
|
238
|
+
log(`WARNING: critical issues found — PR will be created but marked as blocked. Inspect ${prefix}-Issues.md before merging.`)
|
|
322
239
|
}
|
|
323
240
|
|
|
324
241
|
// ── PR ────────────────────────────────────────────────────────────────────────
|
|
@@ -341,39 +258,37 @@ const prResult = await agent(
|
|
|
341
258
|
Feature path: ${featurePath}
|
|
342
259
|
Branch: ${branch || 'current branch'}
|
|
343
260
|
Prefix: ${prefix}
|
|
344
|
-
|
|
261
|
+
Critical issues found: ${hasCritical}
|
|
262
|
+
Open issues: ${issuesOpen}
|
|
345
263
|
|
|
346
264
|
Your tasks:
|
|
347
265
|
|
|
348
|
-
1.
|
|
349
|
-
git add -A
|
|
350
|
-
git commit -m "fix(${prefix}): remediate review issues"
|
|
351
|
-
|
|
352
|
-
2. Push the branch:
|
|
266
|
+
1. Push the branch:
|
|
353
267
|
git push -u origin ${branch || 'HEAD'}
|
|
354
268
|
|
|
355
|
-
|
|
269
|
+
2. Create a PR targeting develop:
|
|
356
270
|
gh pr create \\
|
|
357
271
|
--title "feat(${prefix}): <Feature Title from feature.md>" \\
|
|
358
272
|
--base develop \\
|
|
359
273
|
--body "## Summary
|
|
360
|
-
- Implements <Feature Title> (
|
|
274
|
+
- Implements <Feature Title from feature.md> (${usPassed.length} User Stories, ${phasesDone} phases)
|
|
361
275
|
- Source docs: ${prefix}-Requirements.md, ${prefix}-Tech-Spec.md
|
|
362
276
|
|
|
363
277
|
## Implementation
|
|
364
|
-
-
|
|
365
|
-
-
|
|
278
|
+
- Phases implemented: ${usPassed.join(', ') || 'N/A'}
|
|
279
|
+
- Architect review: ${hasCritical ? '⚠️ CRITICAL issues found — see ' + prefix + '-Issues.md before merging' : '✅ No critical issues'}
|
|
280
|
+
- Open issues: ${issuesOpen} → see ${prefix}-Issues.md
|
|
366
281
|
|
|
367
282
|
## Test plan
|
|
368
283
|
- [ ] Build passes
|
|
369
284
|
- [ ] Tests pass
|
|
370
285
|
- [ ] Manual smoke test of key flows"
|
|
371
286
|
|
|
372
|
-
|
|
373
|
-
Find or append the entry for ${prefix}. Set Status to "completed".
|
|
287
|
+
3. Update the Feature Registry (internal_docs/features/REGISTRY.md):
|
|
288
|
+
Find or append the entry for ${prefix}. Set Status to "${hasCritical ? 'review-required' : 'completed'}".
|
|
374
289
|
|
|
375
290
|
Return { "pr_url": "<url>", "registry_updated": true/false }.
|
|
376
|
-
If the PR creation fails, return { "pr_url": "(PR creation failed)", "registry_updated": false }.`,
|
|
291
|
+
If the PR already exists, return its URL. If creation fails, return { "pr_url": "(PR creation failed)", "registry_updated": false }.`,
|
|
377
292
|
{
|
|
378
293
|
label: 'pr-and-registry',
|
|
379
294
|
phase: 'PR',
|
|
@@ -390,15 +305,6 @@ phase('Actuals')
|
|
|
390
305
|
|
|
391
306
|
const totalPhase3Tokens = tokenLedger.reduce((s, e) => s + (e.phase_delta_tokens || 0), 0)
|
|
392
307
|
|
|
393
|
-
const ACTUALS_SCHEMA = {
|
|
394
|
-
type: 'object',
|
|
395
|
-
properties: {
|
|
396
|
-
token_estimate_path: { type: 'string' },
|
|
397
|
-
effort_estimate_path: { type: 'string' },
|
|
398
|
-
},
|
|
399
|
-
required: [],
|
|
400
|
-
}
|
|
401
|
-
|
|
402
308
|
const beforeActuals = budget.spent()
|
|
403
309
|
|
|
404
310
|
await agent(
|
|
@@ -419,42 +325,56 @@ Append this section at the end of the file:
|
|
|
419
325
|
|
|
420
326
|
---
|
|
421
327
|
|
|
422
|
-
##
|
|
328
|
+
## Phase 3 — Implementation (Actuals)
|
|
423
329
|
|
|
424
330
|
> Phase totals are exact measurements from budget tracking.
|
|
425
331
|
> Per-agent values are exact where each agent ran separately; proportional where merged.
|
|
426
332
|
|
|
427
|
-
| Agent | Phase | Model |
|
|
428
|
-
|
|
429
|
-
${tokenLedger.map(e => `| ${e.agent} | — | ${e.model} | ${e.phase_delta_tokens} |`).join('\n')}
|
|
333
|
+
| Agent | Phase | Model | Tokens Est. | Tokens Actual |
|
|
334
|
+
|-------|-------|-------|------------|--------------|
|
|
335
|
+
${tokenLedger.map(e => `| ${e.agent} | — | ${e.model} | — | ${e.phase_delta_tokens} |`).join('\n')}
|
|
336
|
+
| **Phase 3 total** | | | **—** | **${totalPhase3Tokens}** |
|
|
337
|
+
|
|
338
|
+
## Grand Total (updated)
|
|
430
339
|
|
|
431
|
-
|
|
340
|
+
| Phase | Tokens Est. | Tokens Actual |
|
|
341
|
+
|-------|------------|--------------|
|
|
342
|
+
| Phase 1 — Documentation | — | *(see above)* |
|
|
343
|
+
| Phase 2 — Work Breakdown | — | *(see above)* |
|
|
344
|
+
| Phase 3 — Implementation | *(see above)* | ${totalPhase3Tokens} |
|
|
345
|
+
|
|
346
|
+
## Implementation Summary
|
|
432
347
|
|
|
433
348
|
| Metric | Value |
|
|
434
349
|
|--------|-------|
|
|
435
|
-
| Total tokens (pm-phase3) | ${totalPhase3Tokens} (exact) |
|
|
436
350
|
| Implementation phases done | ${phasesDone} |
|
|
437
|
-
| US
|
|
438
|
-
|
|
|
351
|
+
| US implemented | ${usPassed.join(', ') || 'N/A'} |
|
|
352
|
+
| Critical issues | ${hasCritical} |
|
|
353
|
+
| Open issues | ${issuesOpen} |
|
|
354
|
+
|
|
355
|
+
TASK 2 — Update actuals in ${prefix}-Effort-Estimate.md:
|
|
356
|
+
Find the file in the feature directory. Read the existing Per-Phase Breakdown table and update
|
|
357
|
+
the "Actual Agent" column for each phase that was implemented:
|
|
358
|
+
- Phases implemented (${usPassed.join(', ') || 'none'} + INFRA): write "done (agent)"
|
|
359
|
+
- Any phase not in the list: leave "—"
|
|
439
360
|
|
|
440
|
-
|
|
441
|
-
Find the file in the feature directory. Append:
|
|
361
|
+
Also append this section at the end of the file:
|
|
442
362
|
|
|
443
363
|
---
|
|
444
364
|
|
|
445
|
-
##
|
|
365
|
+
## Implementation Summary
|
|
446
366
|
|
|
447
367
|
| Metric | Estimated | Actual |
|
|
448
368
|
|--------|-----------|--------|
|
|
449
369
|
| Implementation phases | ${phasesDone} | ${phasesDone} |
|
|
450
|
-
|
|
|
451
|
-
|
|
|
370
|
+
| Critical review issues | — | ${hasCritical ? 'yes' : 'none'} |
|
|
371
|
+
| Open issues | — | ${issuesOpen} |
|
|
452
372
|
|
|
453
373
|
Return { "token_estimate_path": "<path>", "effort_estimate_path": "<path>" }.`,
|
|
454
374
|
{
|
|
455
375
|
label: 'write-actuals',
|
|
456
376
|
phase: 'Actuals',
|
|
457
|
-
schema:
|
|
377
|
+
schema: { type: 'object', properties: { token_estimate_path: { type: 'string' }, effort_estimate_path: { type: 'string' } }, required: [] },
|
|
458
378
|
}
|
|
459
379
|
)
|
|
460
380
|
|
|
@@ -463,28 +383,22 @@ tokenLedger.push({ agent: 'write-actuals', model: 'sonnet', phase_delta_tokens:
|
|
|
463
383
|
log(`Actuals written — ${actualsTokens} tokens`)
|
|
464
384
|
|
|
465
385
|
// ── Append to process-log ─────────────────────────────────────────────────────
|
|
466
|
-
const usPassed3 = usPassed.join(', ') || 'none'
|
|
467
|
-
const usEscalated3 = usEscalated.join(', ') || 'none'
|
|
468
386
|
const phase3Events = [
|
|
469
387
|
`APPROVAL GRANTED by user — Gate 2`,
|
|
470
388
|
`pm-phase3 START — implementation phase — branch: ${branch || '(current)'}`,
|
|
471
389
|
`WB parsed: ${wb.phases.length} phases`,
|
|
472
|
-
`Implementation DONE — ${phasesDone} phases
|
|
473
|
-
|
|
474
|
-
? `Remediation: ${issuesFixed} fixed, ${issuesDeferred} deferred`
|
|
475
|
-
: `Remediation: skipped (no open issues)`,
|
|
390
|
+
`Implementation DONE — ${phasesDone} phases implemented: ${usPassed.join(', ') || 'none'}`,
|
|
391
|
+
`Review DONE — critical: ${hasCritical}, open issues: ${issuesOpen}`,
|
|
476
392
|
`PR created: ${prResult.pr_url}`,
|
|
477
393
|
`Actuals written: Token-Estimate.md + Effort-Estimate.md`,
|
|
478
394
|
`RUN COMPLETE`,
|
|
479
395
|
`════════════════════════════════════════════════════════`,
|
|
480
396
|
].join('\n')
|
|
481
397
|
|
|
482
|
-
const featureDir3 = featurePath.replace(/\/[^/]+$/, '')
|
|
483
|
-
|
|
484
398
|
await agent(
|
|
485
399
|
`Append phase 3 events to the process-log for this feature delivery run.
|
|
486
400
|
|
|
487
|
-
Process-log path: ${
|
|
401
|
+
Process-log path: ${featureDir}/${prefix}-process-log.txt
|
|
488
402
|
|
|
489
403
|
Steps:
|
|
490
404
|
1. Get current UTC datetime via Bash: run \`date -u +"%Y-%m-%dT%H:%M:%S"\`
|
|
@@ -494,16 +408,14 @@ Steps:
|
|
|
494
408
|
|
|
495
409
|
Events to append:
|
|
496
410
|
${phase3Events}`,
|
|
497
|
-
{ label: 'finalize-process-log', phase: 'Actuals' }
|
|
411
|
+
{ label: 'finalize-process-log', phase: 'Actuals', model: 'haiku' }
|
|
498
412
|
)
|
|
499
413
|
|
|
500
414
|
return {
|
|
501
415
|
pr_url: prResult.pr_url,
|
|
502
416
|
token_ledger: tokenLedger,
|
|
503
417
|
issues_summary: {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
issues_fixed: issuesFixed,
|
|
507
|
-
issues_deferred: issuesDeferred,
|
|
418
|
+
has_critical: hasCritical,
|
|
419
|
+
open_issues: issuesOpen,
|
|
508
420
|
},
|
|
509
421
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,26 @@
|
|
|
1
1
|
## 0.1.4 (2026-07-21)
|
|
2
|
+
## [0.5.0](https://github.com/dtlab-tech/ai-toolkit/compare/v0.4.0...v0.5.0) (2026-07-29)
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
* **pm-phase3:** Option C review architecture + estimate format improvements ([b385b3e](https://github.com/dtlab-tech/ai-toolkit/commit/b385b3e35ef9121b8d9008223c77c88291c4173a))
|
|
8
|
+
|
|
9
|
+
## [0.4.0](https://github.com/dtlab-tech/ai-toolkit/compare/v0.3.1...v0.4.0) (2026-07-29)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
|
|
14
|
+
* **effort-estimate:** add Est./Actual Human/Agent columns to Per-Phase Breakdown ([696146c](https://github.com/dtlab-tech/ai-toolkit/commit/696146cc583ca13ee18914af19ff4de87a91cb60))
|
|
15
|
+
* FTR-010 unit tests, process-log, OPT-02/03/04, remove Matt Pocock dependency ([1f43a4e](https://github.com/dtlab-tech/ai-toolkit/commit/1f43a4e6bf98a4b5821f1a0ae2dac33aca090597))
|
|
16
|
+
* **token-estimate:** split tokens into Est./Actual columns in pm-phase2 and pm-phase3 ([d85b6e4](https://github.com/dtlab-tech/ai-toolkit/commit/d85b6e4aa871a934190e1d65995cb8e7e8db4495))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Bug Fixes
|
|
20
|
+
|
|
21
|
+
* **pm-phase3:** read CSV as raw string instead of schema-wrapped object ([1737842](https://github.com/dtlab-tech/ai-toolkit/commit/17378422f6a9dc9168a35c7114cdd227e9214ce8))
|
|
22
|
+
* **pm-phase3:** remove duplicate const prefix declaration ([85455e8](https://github.com/dtlab-tech/ai-toolkit/commit/85455e83929ccc6274d7d888fd429fc83ad78137))
|
|
23
|
+
|
|
2
24
|
## [0.3.1](https://github.com/dtlab-tech/ai-toolkit/compare/v0.3.0...v0.3.1) (2026-07-28)
|
|
3
25
|
|
|
4
26
|
|
package/CLAUDE.global.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# AI Toolkit — Gate Protocol
|
|
2
|
+
|
|
3
|
+
> Full catalog (Skills, Commands, Agents, Procedures): see `CLAUDE.md` in the project root,
|
|
4
|
+
> or [`docs/reference.md`](docs/reference.md) for the cheatsheet.
|
|
5
|
+
|
|
6
|
+
## Gate Protocol — MANDATORY RULES
|
|
7
|
+
|
|
8
|
+
These rules apply in every session, without exception.
|
|
9
|
+
|
|
10
|
+
### Launching the Project Manager
|
|
11
|
+
|
|
12
|
+
**Always pass `run_in_background: false` when spawning the `project-manager` agent.**
|
|
13
|
+
|
|
14
|
+
Running the PM in the background leaves the main loop free to act independently. This creates two parallel execution paths that will conflict. The PM must block the main loop until it reaches a gate and returns.
|
|
15
|
+
|
|
16
|
+
### While the PM is running
|
|
17
|
+
|
|
18
|
+
**Do nothing.** No file reads "to prepare", no file writes "to accelerate", no implementation "because it seems stuck". The only permitted actions are:
|
|
19
|
+
|
|
20
|
+
- Receiving gate notifications and presenting them to the user
|
|
21
|
+
- Responding to the user's status questions ("still running")
|
|
22
|
+
- Sending messages to the PM via SendMessage if it is genuinely blocked and the user asks to unblock it
|
|
23
|
+
|
|
24
|
+
If the PM produces relay agents that appear to do nothing useful, that is noise — not a signal that the PM is stuck. Wait.
|
|
25
|
+
|
|
26
|
+
### Gate notifications are hard stops
|
|
27
|
+
|
|
28
|
+
When any gate notification arrives (Gate 1, Gate 2, Findings Gate, or any **HARD STOP** in any agent output):
|
|
29
|
+
|
|
30
|
+
1. Stop immediately — even if mid-turn
|
|
31
|
+
2. Present the full gate content to the user
|
|
32
|
+
3. Wait for explicit written approval before touching any file or spawning any agent
|
|
33
|
+
|
|
34
|
+
This applies even if the PM appears stuck, in a relay loop, or the gate arrives while another tool call is in progress.
|
package/CLAUDE.md
CHANGED
|
@@ -2,19 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
A reusable set of AI agents and procedures for software feature delivery and codebase assessment — from requirements to PR, and from audit to remediation.
|
|
4
4
|
|
|
5
|
-
> **
|
|
6
|
-
|
|
7
|
-
## Dependencies
|
|
8
|
-
|
|
9
|
-
This toolkit expects the **`define-feature`** agent from [Matt Pocock's skills package](https://github.com/mattpocock/skills) to be available. That agent is responsible for producing the `feature.md` input file that `/implement-feature` and all downstream agents consume.
|
|
10
|
-
|
|
11
|
-
Install it with:
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
npx skills@latest add mattpocock/skills
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
> **Tip:** Install Matt's skills globally (`~/.claude/skills/`) so they are available in every project without repeating the setup.
|
|
5
|
+
> **Full catalog of skills, commands, agents, and procedures:** [`docs/reference.md`](docs/reference.md)
|
|
18
6
|
|
|
19
7
|
## How it works
|
|
20
8
|
|
|
@@ -81,89 +69,17 @@ When any gate notification arrives (Gate 1, Gate 2, Findings Gate, or any **HARD
|
|
|
81
69
|
|
|
82
70
|
This applies even if the PM appears stuck, in a relay loop, or the gate arrives while another tool call is in progress.
|
|
83
71
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
| Skill | Command | Purpose |
|
|
100
|
-
|-------|---------|---------|
|
|
101
|
-
| Assess Codebase | `/assess-codebase` | Starts the full assessment pipeline: parallel assessment → intervention docs → approval gate → remediation → review → PR |
|
|
102
|
-
|
|
103
|
-
### General
|
|
104
|
-
|
|
105
|
-
| Skill | Command | Purpose |
|
|
106
|
-
|-------|---------|---------|
|
|
107
|
-
| Gaia | `/hi-gaia [topic]` | Your toolkit assistant — introduces herself, explains pipelines, agents, and commands; helps you find the right tool for your situation |
|
|
108
|
-
|
|
109
|
-
## Commands (slash shortcuts, in `.claude/commands/`)
|
|
110
|
-
|
|
111
|
-
### Feature Delivery
|
|
112
|
-
|
|
113
|
-
| Command | Purpose |
|
|
114
|
-
|---------|---------|
|
|
115
|
-
| `/feature-status <slug>` | Reports presence/state of feature.md, requirements, tech-spec, work-breakdown, and implementation progress |
|
|
116
|
-
| `/check-docs <slug>` | Terse consistency check between feature docs — outputs only the inconsistencies |
|
|
117
|
-
| `/pr-description` | Generates a PR description from the current branch commits + linked feature.md |
|
|
118
|
-
| `/next-task [slug]` | Finds the next unblocked task in the work breakdown and suggests the agent to delegate it to |
|
|
119
|
-
|
|
120
|
-
### Assessment & Remediation
|
|
121
|
-
|
|
122
|
-
| Command | Purpose |
|
|
123
|
-
|---------|---------|
|
|
124
|
-
| `/assessment-status <prefix>` | Reports presence/state of all assessment artifacts (assessments, interventions, approvals, issues register) |
|
|
125
|
-
| `/next-intervention [prefix]` | Finds the next un-actioned flagged intervention and suggests the `/define-feature` invocation to start on it |
|
|
126
|
-
| `/check-interventions [prefix]` | Full reconciliation table: every intervention cross-referenced against the Index, on-disk files, and existing feature folders |
|
|
127
|
-
|
|
128
|
-
## Agents (spawnable subagents, in `.claude/agents/`)
|
|
129
|
-
|
|
130
|
-
### Feature Delivery
|
|
131
|
-
|
|
132
|
-
| Agent | subagent_type | Purpose |
|
|
133
|
-
|-------|---------------|---------|
|
|
134
|
-
| Install Toolkit | `install-toolkit` | Copies toolkit files into a destination project |
|
|
135
|
-
| Init AGENTS.md | `init-agents-md` | Analyzes codebase and generates AGENTS.md |
|
|
136
|
-
| Define Feature | `define-feature` | Interviews the user and writes `feature.md` in `docs/features/FTR-XXX-slug/` |
|
|
137
|
-
| Generate Requirements | `generate-requirements` | Produces functional requirements from feature.md |
|
|
138
|
-
| Generate Tech-Spec | `generate-tech-spec` | Produces technical specification from feature + requirements |
|
|
139
|
-
| Validate Docs | `validate-feature-docs` | Cross-validates requirements + tech-spec against feature.md |
|
|
140
|
-
| Generate Work Breakdown | `generate-work-breakdown` | Creates User Stories + tasks from approved docs |
|
|
141
|
-
| Backend Developer | `developer-backend` | Implements backend tasks (DB, BE, INFRA domains) |
|
|
142
|
-
| Frontend Developer | `developer-frontend` | Implements frontend tasks (FE domain) |
|
|
143
|
-
| Testing Agent | `developer-testing` | Creates unit/integration tests (TEST domain) |
|
|
144
|
-
| Review Solution | `review-solution` | Architect-level code review |
|
|
145
|
-
| Project Manager | `project-manager` | Orchestrates the full feature delivery pipeline |
|
|
146
|
-
|
|
147
|
-
### Assessment & Remediation
|
|
148
|
-
|
|
149
|
-
| Agent | subagent_type | Purpose |
|
|
150
|
-
|-------|---------------|---------|
|
|
151
|
-
| Assessment Manager | `assessment-manager` | Orchestrates the assessment pipeline: parallel assessment → intervention docs → approval gate → effort/token estimates → summary |
|
|
152
|
-
| Generic Software Assessment | `generic-software-assessment` | Broad quality analysis across architecture, security, testability, observability, DevOps |
|
|
153
|
-
| Intervention Documentation Standard | `intervention-documentation-standard` | Generates structured, self-contained intervention documents from assessment findings |
|
|
154
|
-
| God Class Decomposition | `god-class-decomposition` | Safe incremental decomposition of oversized classes and methods |
|
|
155
|
-
| Domain Model Refactoring | `domain-model-refactoring` | Splits monolithic model files, introduces type hierarchies, aligns domain vocabulary |
|
|
156
|
-
| Layered Architecture Assessment | `layered-architecture-assessment` | Audits layer boundary violations and namespace/package misalignment |
|
|
157
|
-
| Dependency Injection Refactoring | `dependency-injection-refactoring` | Converts static/direct coupling to constructor-injected services |
|
|
158
|
-
| Security Hardening | `security-hardening` | Input validation, parameterised queries, secret management, log sanitisation, TLS |
|
|
159
|
-
| Dependency Supply Chain Security | `dependency-supply-chain-security` | Lock files, integrity verification, unused dependency audit, SCA in CI |
|
|
160
|
-
| Concurrency Safety Assessment | `concurrency-safety-assessment` | Race conditions, shared mutable state, unsafe shutdown patterns |
|
|
161
|
-
|
|
162
|
-
## Available procedures (in `docs/procedures/`)
|
|
163
|
-
|
|
164
|
-
| Procedure | Purpose |
|
|
165
|
-
|-----------|---------|
|
|
166
|
-
| `code-generation.md` | Step-by-step workflow for generating/modifying code |
|
|
167
|
-
| `code-review.md` | Checklist and process for reviewing code |
|
|
168
|
-
| `secure-coding.md` | Security checklist for auth/data handling |
|
|
169
|
-
| `testing.md` | Strategy and guidelines for writing tests |
|
|
72
|
+
## Compact instructions
|
|
73
|
+
|
|
74
|
+
When compacting this conversation, preserve:
|
|
75
|
+
- Current objective and which pipeline step we are on
|
|
76
|
+
- User decisions and approvals (Gate 1, Gate 2, Findings Gate)
|
|
77
|
+
- Files created or modified this session
|
|
78
|
+
- Open errors or blockers
|
|
79
|
+
- Feature/assessment prefix IDs and artifact paths (e.g. FTR-010, ASSESS-001)
|
|
80
|
+
|
|
81
|
+
Discard:
|
|
82
|
+
- Raw grep/glob/read output that has already been acted on
|
|
83
|
+
- Successful tool-call results that produced no follow-up action
|
|
84
|
+
- Repeated explanations of the same concept
|
|
85
|
+
- Superseded plans or approaches
|
package/bin/cli.js
CHANGED
|
@@ -225,53 +225,6 @@ async function runInstall(label, mappings, force) {
|
|
|
225
225
|
);
|
|
226
226
|
}
|
|
227
227
|
|
|
228
|
-
// ── Matt Pocock skills ───────────────────────────────────────────────────────
|
|
229
|
-
|
|
230
|
-
function isMattPocockInstalled() {
|
|
231
|
-
const homedir = require('os').homedir();
|
|
232
|
-
// 'grilling' is a skill exclusive to Matt Pocock's package — not included in this toolkit
|
|
233
|
-
const pathsToCheck = [
|
|
234
|
-
path.join(homedir, '.claude', 'skills', 'grilling', 'SKILL.md'),
|
|
235
|
-
path.join(process.cwd(), '.claude', 'skills', 'grilling', 'SKILL.md'),
|
|
236
|
-
];
|
|
237
|
-
return pathsToCheck.some(p => fs.existsSync(p));
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
async function installMattPocock() {
|
|
241
|
-
const { execSync } = require('child_process');
|
|
242
|
-
console.log(`\n ${clr('cyan', '↓')} Running: ${dim('npx skills@latest add mattpocock/skills')}\n`);
|
|
243
|
-
try {
|
|
244
|
-
execSync('npx skills@latest add mattpocock/skills', { stdio: 'inherit' });
|
|
245
|
-
console.log(`\n ${clr('green', '✔')} Matt Pocock skills installed successfully.\n`);
|
|
246
|
-
} catch (err) {
|
|
247
|
-
console.error(`\n ${clr('red', '✖')} Install failed: ${err.message}`);
|
|
248
|
-
console.error(` Run manually: ${dim('npx skills@latest add mattpocock/skills')}\n`);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
async function askMattPocock() {
|
|
253
|
-
const installed = isMattPocockInstalled();
|
|
254
|
-
|
|
255
|
-
console.log(divider());
|
|
256
|
-
console.log(bold(' Matt Pocock Skills'));
|
|
257
|
-
console.log(divider());
|
|
258
|
-
console.log(` ${dim('Includes: define-feature, grilling, TDD, prototype, handoff, and more.')}`);
|
|
259
|
-
console.log();
|
|
260
|
-
|
|
261
|
-
if (!installed) {
|
|
262
|
-
console.log(` ${clr('gray', '○')} Status : ${clr('gray', 'not installed')}\n`);
|
|
263
|
-
const ok = await askConfirm('Install Matt Pocock\'s skills now?');
|
|
264
|
-
if (ok) await installMattPocock();
|
|
265
|
-
else console.log(`\n ${clr('gray', 'Skipped. Install later with: npx skills@latest add mattpocock/skills')}\n`);
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
console.log(` ${clr('green', '✔')} Status : ${clr('green', 'installed')}\n`);
|
|
270
|
-
const ok = await askConfirm('Re-install / update Matt Pocock skills?');
|
|
271
|
-
if (ok) await installMattPocock();
|
|
272
|
-
else console.log(` ${clr('gray', 'Skipped.')}\n`);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
228
|
// ── subagent spawn-depth check (verify & advise only — never write) ────────────
|
|
276
229
|
|
|
277
230
|
const SPAWN_DEPTH_VAR = 'CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH';
|
|
@@ -334,7 +287,6 @@ async function installLocal(targetDir, force) {
|
|
|
334
287
|
writeInstalledVersion(targetDir);
|
|
335
288
|
console.log(` ${clr('green', '✔')} ${bold('Install complete.')}\n`);
|
|
336
289
|
checkSpawnDepth(targetDir);
|
|
337
|
-
await askMattPocock();
|
|
338
290
|
console.log(divider());
|
|
339
291
|
console.log(`\n ${bold('Next steps:')}`);
|
|
340
292
|
console.log(` ${clr('cyan', '1.')} Run ${clr('cyan', '/init-agents')} to generate AGENTS.md`);
|
|
@@ -355,13 +307,12 @@ async function installGlobal(force) {
|
|
|
355
307
|
{ src: path.join(packageRoot, '.claude', 'commands'), dest: path.join(target, 'commands') },
|
|
356
308
|
{ src: path.join(packageRoot, '.claude', 'workflows'), dest: path.join(target, 'workflows') },
|
|
357
309
|
{ src: path.join(packageRoot, 'docs'), dest: path.join(target, 'docs') },
|
|
358
|
-
{ src: path.join(packageRoot, 'CLAUDE.md'),
|
|
310
|
+
{ src: path.join(packageRoot, 'CLAUDE.global.md'), dest: path.join(target, 'CLAUDE.md') },
|
|
359
311
|
];
|
|
360
312
|
await runInstall('global Claude folder', mappings, force);
|
|
361
313
|
writeInstalledVersion(target);
|
|
362
314
|
console.log(` ${clr('green', '✔')} ${bold('Global install complete.')}\n`);
|
|
363
315
|
checkSpawnDepth(homedir);
|
|
364
|
-
await askMattPocock();
|
|
365
316
|
console.log(divider());
|
|
366
317
|
console.log(`\n ${bold('Next steps:')}`);
|
|
367
318
|
console.log(` ${clr('cyan', '1.')} The toolkit is now available in all your projects`);
|
|
@@ -419,7 +370,6 @@ if (require.main === module) {
|
|
|
419
370
|
expandMappings,
|
|
420
371
|
categorize,
|
|
421
372
|
readInstalledVersion,
|
|
422
|
-
isMattPocockInstalled,
|
|
423
373
|
NEVER_COPY,
|
|
424
374
|
};
|
|
425
375
|
}
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dtlabs/ai-toolkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "AI Toolkit — reusable agents and procedures for developers to build AI-powered applications.",
|
|
5
5
|
"files": [
|
|
6
6
|
"docs/",
|
|
7
7
|
"CLAUDE.md",
|
|
8
8
|
"CHANGELOG.md",
|
|
9
9
|
"README.md",
|
|
10
|
+
"CLAUDE.global.md",
|
|
10
11
|
".claude",
|
|
11
12
|
"bin"
|
|
12
13
|
],
|