@dtlabs/ai-toolkit 0.1.7 → 0.2.1

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.
@@ -0,0 +1,309 @@
1
+ export const meta = {
2
+ name: 'pm-phase3',
3
+ description: 'Feature delivery phase 3: implementation loop (developer agents + review-solution per US, max 2 rework cycles, git commit per US) → remediation → PR → Feature Registry → Token-Estimate actuals → Effort-Estimate actuals.',
4
+ phases: [
5
+ { title: 'Implementation', detail: 'Dispatch developer agents per work breakdown, review per US' },
6
+ { title: 'Remediation', detail: 'Fix OPEN issues from Issues Register' },
7
+ { title: 'PR', detail: 'Push branch, create PR, update registry' },
8
+ { title: 'Actuals', detail: 'Write Token-Estimate and Effort-Estimate actuals' },
9
+ ],
10
+ }
11
+
12
+ // args: "<path-to-feature.md> --branch feature/FTR-NNN-slug"
13
+ const argStr = typeof args === 'string' ? args : ''
14
+ const featurePath = argStr.trim().split(/\s+/)[0]
15
+ const branchMatch = argStr.match(/--branch\s+(\S+)/)
16
+ const branch = branchMatch ? branchMatch[1] : null
17
+
18
+ // ── Implementation ────────────────────────────────────────────────────────────
19
+ phase('Implementation')
20
+
21
+ log(`Starting implementation for ${featurePath}${branch ? ` on branch ${branch}` : ''}`)
22
+
23
+ const tokenLedger = []
24
+ const escalations = []
25
+
26
+ // Read the Work Breakdown and execute implementation
27
+ // A single orchestration agent handles the full implementation loop:
28
+ // parse WB → per-phase dispatch → review per US → rework (max 2 cycles) → commit per US
29
+ // It uses sub-tool calls (Read, Bash, etc.) to do git work and reads the WB itself.
30
+ // It does NOT spawn further subagents — it reads files and calls Bash for git commands.
31
+
32
+ const IMPL_SCHEMA = {
33
+ type: 'object',
34
+ properties: {
35
+ prefix: { type: 'string' },
36
+ phases_done: { type: 'number' },
37
+ us_passed: { type: 'array', items: { type: 'string' } },
38
+ us_escalated: { type: 'array', items: { type: 'string' } },
39
+ issues_path: { type: 'string' },
40
+ issues_open: { type: 'number' },
41
+ },
42
+ required: ['prefix', 'phases_done'],
43
+ }
44
+
45
+ const beforeImpl = budget.spent()
46
+
47
+ const implResult = await agent(
48
+ `You are the implementation orchestrator for the feature delivery pipeline.
49
+
50
+ Feature path: ${featurePath}
51
+ Branch: ${branch || '(already checked out)'}
52
+
53
+ Your job:
54
+
55
+ 1. Read {PREFIX}-Work-Breakdown.md (same directory as feature.md).
56
+ Extract all phases, tasks, domains, and User Story groupings from Section 4.
57
+
58
+ 2. For each phase in order:
59
+ a. Identify tasks grouped by User Story (US-XX) or INFRA.
60
+ b. For each group, spawn the correct developer agent:
61
+ - DB/BE/INFRA tasks → subagent_type: developer-backend
62
+ - FE tasks → subagent_type: developer-frontend
63
+ - TEST tasks → subagent_type: developer-testing
64
+ Prompt: "${featurePath} <comma-separated task IDs>"
65
+ Independent groups within a phase can be dispatched in parallel (multiple Agent calls in same response).
66
+ c. When ALL tasks for a User Story are done → spawn review-solution:
67
+ subagent_type: review-solution, prompt: "${featurePath} --scope <US-ID>"
68
+ - PASS (no CRITICAL): git add -A && git commit -m "feat({PREFIX}): implement {US-ID} — {title}"
69
+ Log WARNING/INFO findings to {PREFIX}-Issues.md.
70
+ - FAIL (CRITICAL): rework — re-dispatch the developer agent with the review findings appended to the prompt.
71
+ Max 2 rework cycles. After 2 failed cycles → escalate (add to escalations list).
72
+ INFRA tasks: reviewed as a group, commit: "feat({PREFIX}): implement shared infrastructure (INFRA)"
73
+
74
+ 3. After all phases complete:
75
+ - Read {PREFIX}-Issues.md if it exists. Count OPEN items.
76
+ - Report: prefix, phases_done, us_passed (list of US IDs that passed), us_escalated (list that escalated), issues_path, issues_open.
77
+
78
+ IMPORTANT RULES:
79
+ - Never use run_in_background: true when spawning agents.
80
+ - Track escalations: if a US fails review after 2 rework cycles, add its ID to us_escalated and continue.
81
+ - Partial failures are acceptable — continue with remaining phases.
82
+ - All git commands via Bash tool.
83
+ - Commit message format: feat({PREFIX}): implement {US-ID} — {US title}`,
84
+ {
85
+ label: 'implementation-orchestrator',
86
+ phase: 'Implementation',
87
+ schema: IMPL_SCHEMA,
88
+ }
89
+ )
90
+
91
+ const implTokens = budget.spent() - beforeImpl
92
+ tokenLedger.push({ agent: 'implementation-orchestrator', model: 'sonnet', phase_delta_tokens: implTokens })
93
+ log(`Implementation done — ${implResult.phases_done} phases, ${(implResult.us_passed || []).length} US passed, ${(implResult.us_escalated || []).length} escalated`)
94
+ log(`Phase delta: ${implTokens} tokens`)
95
+
96
+ if (implResult.us_escalated?.length) {
97
+ for (const usId of implResult.us_escalated) {
98
+ escalations.push({ usId, reason: 'CRITICAL review finding unresolved after 2 rework cycles' })
99
+ }
100
+ }
101
+
102
+ const prefix = implResult.prefix
103
+ const issuesPath = implResult.issues_path || ''
104
+
105
+ // ── Remediation ───────────────────────────────────────────────────────────────
106
+ phase('Remediation')
107
+
108
+ const REM_SCHEMA = {
109
+ type: 'object',
110
+ properties: {
111
+ issues_fixed: { type: 'number' },
112
+ issues_deferred: { type: 'number' },
113
+ },
114
+ required: ['issues_fixed', 'issues_deferred'],
115
+ }
116
+
117
+ let issuesFixed = 0
118
+ let issuesDeferred = 0
119
+
120
+ if (implResult.issues_open > 0 && issuesPath) {
121
+ log(`Remediation: ${implResult.issues_open} OPEN issues`)
122
+ const beforeRem = budget.spent()
123
+
124
+ const remResult = await agent(
125
+ `You are a remediation agent for the feature delivery pipeline.
126
+
127
+ Read the Issues Register at: ${issuesPath}
128
+
129
+ For each OPEN issue:
130
+ - If severity is INFO: mark it DEFERRED immediately (update the Status column to DEFERRED). Do not dispatch a developer agent.
131
+ - 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.
132
+
133
+ After processing all issues, return:
134
+ { "issues_fixed": N, "issues_deferred": N }
135
+
136
+ Update the Issues Register Status column in place for each resolved/deferred issue.`,
137
+ {
138
+ label: 'remediation',
139
+ phase: 'Remediation',
140
+ schema: REM_SCHEMA,
141
+ }
142
+ )
143
+
144
+ const remTokens = budget.spent() - beforeRem
145
+ tokenLedger.push({ agent: 'remediation', model: 'sonnet', phase_delta_tokens: remTokens })
146
+ issuesFixed = remResult.issues_fixed || 0
147
+ issuesDeferred = remResult.issues_deferred || 0
148
+ log(`Remediation done — fixed: ${issuesFixed}, deferred: ${issuesDeferred} | phase delta: ${remTokens} tokens`)
149
+ } else {
150
+ log('Remediation: no OPEN issues — skipped')
151
+ }
152
+
153
+ // ── PR ────────────────────────────────────────────────────────────────────────
154
+ phase('PR')
155
+
156
+ const PR_SCHEMA = {
157
+ type: 'object',
158
+ properties: {
159
+ pr_url: { type: 'string' },
160
+ registry_updated: { type: 'boolean' },
161
+ },
162
+ required: ['pr_url'],
163
+ }
164
+
165
+ const beforePR = budget.spent()
166
+
167
+ const prResult = await agent(
168
+ `You are the PR and registry agent for the feature delivery pipeline.
169
+
170
+ Feature path: ${featurePath}
171
+ Branch: ${branch || 'current branch'}
172
+ Prefix: ${prefix}
173
+ Issues fixed: ${issuesFixed}, deferred: ${issuesDeferred}
174
+
175
+ Your tasks:
176
+
177
+ 1. If there are remediation fixes, commit them:
178
+ git add -A
179
+ git commit -m "fix(${prefix}): remediate review issues"
180
+
181
+ 2. Push the branch:
182
+ git push -u origin ${branch || 'HEAD'}
183
+
184
+ 3. Create a PR targeting develop:
185
+ gh pr create \\
186
+ --title "feat(${prefix}): <Feature Title from feature.md>" \\
187
+ --base develop \\
188
+ --body "## Summary
189
+ - Implements <Feature Title> (<N> User Stories, <N> tasks)
190
+ - Source docs: ${prefix}-Requirements.md, ${prefix}-Tech-Spec.md
191
+
192
+ ## Implementation
193
+ - Architect review: all US passed
194
+ - Issues Register: ${issuesFixed} fixed, ${issuesDeferred} deferred → see ${prefix}-Issues.md
195
+
196
+ ## Test plan
197
+ - [ ] Build passes
198
+ - [ ] Tests pass
199
+ - [ ] Manual smoke test of key flows"
200
+
201
+ 4. Update the Feature Registry (internal_docs/features/REGISTRY.md):
202
+ Find or append the entry for ${prefix}. Set Status to "completed".
203
+
204
+ Return { "pr_url": "<url>", "registry_updated": true/false }.
205
+ If the PR creation fails, return { "pr_url": "(PR creation failed)", "registry_updated": false }.`,
206
+ {
207
+ label: 'pr-and-registry',
208
+ phase: 'PR',
209
+ schema: PR_SCHEMA,
210
+ }
211
+ )
212
+
213
+ const prTokens = budget.spent() - beforePR
214
+ tokenLedger.push({ agent: 'pr-and-registry', model: 'sonnet', phase_delta_tokens: prTokens })
215
+ log(`PR done: ${prResult.pr_url} | phase delta: ${prTokens} tokens`)
216
+
217
+ // ── Actuals ───────────────────────────────────────────────────────────────────
218
+ phase('Actuals')
219
+
220
+ // Compute proportional distribution of phase tokens across logical agents
221
+ // Phase tokens are exact (budget.spent() deltas); per-agent breakdown is proportional.
222
+ // This is documented in the Token-Estimate file with a disclaimer.
223
+ const totalImplTokens = tokenLedger.reduce((s, e) => s + (e.phase_delta_tokens || 0), 0)
224
+
225
+ const ACTUALS_SCHEMA = {
226
+ type: 'object',
227
+ properties: {
228
+ token_estimate_path: { type: 'string' },
229
+ effort_estimate_path: { type: 'string' },
230
+ },
231
+ required: [],
232
+ }
233
+
234
+ const beforeActuals = budget.spent()
235
+
236
+ await agent(
237
+ `You are the actuals recorder for the feature delivery pipeline.
238
+
239
+ Feature path: ${featurePath}
240
+ Prefix: ${prefix}
241
+
242
+ Token ledger (phase-level measurements):
243
+ ${JSON.stringify(tokenLedger, null, 2)}
244
+
245
+ Total tokens consumed by pm-phase3 workflow (all phases combined): ${totalImplTokens} (exact, from budget tracking)
246
+
247
+ TASK 1 — Update Token-Estimate.md:
248
+ Find ${prefix}-Token-Estimate.md in the feature directory.
249
+ If it doesn't exist, create it with the structure from docs/procedures/token-estimation.md.
250
+
251
+ Append this section at the end:
252
+
253
+ ---
254
+
255
+ ## Actuals vs Estimate
256
+
257
+ > ⚠️ Per-agent values are proportional distributions of the phase total.
258
+ > Phase totals (pm-phase3 total: ${totalImplTokens} tokens) are exact measurements.
259
+ > Individual agent breakdown is estimated proportionally.
260
+
261
+ | Agent | Task / Scope | Model | Phase delta tokens | Notes |
262
+ |-------|-------------|-------|-------------------|-------|
263
+ ${tokenLedger.map(e => `| ${e.agent} | — | ${e.model} | ${e.phase_delta_tokens} | exact phase delta |`).join('\n')}
264
+
265
+ ## Grand Total (pm-phase3)
266
+
267
+ | Metric | Value |
268
+ |--------|-------|
269
+ | Total tokens (pm-phase3) | ${totalImplTokens} (exact) |
270
+ | Implementation phases | ${implResult.phases_done} |
271
+ | US passed | ${(implResult.us_passed || []).join(', ') || 'N/A'} |
272
+ | US escalated | ${(implResult.us_escalated || []).join(', ') || 'none'} |
273
+
274
+ TASK 2 — Append actuals to Effort-Estimate.md:
275
+ Find ${prefix}-Effort-Estimate.md in the feature directory.
276
+ Append:
277
+
278
+ ---
279
+
280
+ ## Actuals vs Estimate
281
+
282
+ | Metric | Estimated | Actual |
283
+ |--------|-----------|--------|
284
+ | Implementation phases | ${implResult.phases_done} | ${implResult.phases_done} |
285
+ | Issues fixed | — | ${issuesFixed} |
286
+ | Issues deferred | — | ${issuesDeferred} |
287
+
288
+ Return { "token_estimate_path": "<path>", "effort_estimate_path": "<path>" }.`,
289
+ {
290
+ label: 'write-actuals',
291
+ phase: 'Actuals',
292
+ schema: ACTUALS_SCHEMA,
293
+ }
294
+ )
295
+
296
+ const actualsTokens = budget.spent() - beforeActuals
297
+ tokenLedger.push({ agent: 'write-actuals', model: 'sonnet', phase_delta_tokens: actualsTokens })
298
+ log(`Actuals written | phase delta: ${actualsTokens} tokens`)
299
+
300
+ return {
301
+ pr_url: prResult.pr_url,
302
+ token_ledger: tokenLedger,
303
+ issues_summary: {
304
+ escalations: escalations.length,
305
+ escalation_details: escalations,
306
+ issues_fixed: issuesFixed,
307
+ issues_deferred: issuesDeferred,
308
+ },
309
+ }
package/CHANGELOG.md CHANGED
@@ -1,4 +1,33 @@
1
1
  ## 0.1.4 (2026-07-21)
2
+ ## [0.2.1](https://github.com/dtlab-tech/ai-toolkit/compare/v0.2.0...v0.2.1) (2026-07-27)
3
+
4
+
5
+ ### Bug Fixes
6
+
7
+ * validate-feature-docs always writes report; fix false-positive gap detection ([68caf3e](https://github.com/dtlab-tech/ai-toolkit/commit/68caf3e25214bcb219df1654c4b3ede5cc42eb3b))
8
+ * validate-feature-docs always writes report; fix false-positive gap detection in pm-phase1 ([d99fdb3](https://github.com/dtlab-tech/ai-toolkit/commit/d99fdb39be1663539bd0ed7e6ca4facc2c53fd76))
9
+
10
+ ## [0.2.0](https://github.com/dtlab-tech/ai-toolkit/compare/v0.1.7...v0.2.0) (2026-07-27)
11
+
12
+
13
+ ### Features
14
+
15
+ * **FTR-007:** explicit per-agent model assignment ([853eb0f](https://github.com/dtlab-tech/ai-toolkit/commit/853eb0f956a9a1aa64dedac7100fb1ad9eab4b08))
16
+ * **FTR-007:** implement US-01 — explicit per-agent model assignment ([0fe5fba](https://github.com/dtlab-tech/ai-toolkit/commit/0fe5fba9b25dc261e840d99d97105dec7c0c9318))
17
+ * **FTR-008:** compact instructions block for ~/.claude/CLAUDE.md ([738df59](https://github.com/dtlab-tech/ai-toolkit/commit/738df597e2da3edc04de68462f0e4555b232941d))
18
+ * **FTR-008:** implement compact instructions block ([0dab04d](https://github.com/dtlab-tech/ai-toolkit/commit/0dab04d9c14392866c9046eee9e7052a2beac586))
19
+ * **FTR-009:** implement shared infrastructure (INFRA) ([31bceb9](https://github.com/dtlab-tech/ai-toolkit/commit/31bceb9788a1f403eea3f2971b87959fa9e33f97))
20
+ * **FTR-009:** implement US-01 — Feature Delivery Workflow Scripts ([7f6dd7d](https://github.com/dtlab-tech/ai-toolkit/commit/7f6dd7da8280d9bc6b5b9922bf7f751c1837f8ad))
21
+ * **FTR-009:** implement US-02 — Assessment Workflow Scripts ([7b1e668](https://github.com/dtlab-tech/ai-toolkit/commit/7b1e668217f89ef16011fbe253a8e4bfb5714d0c))
22
+ * **FTR-009:** rewrite orchestrators as Workflow scripts ([7f63b20](https://github.com/dtlab-tech/ai-toolkit/commit/7f63b209e6f4826115c74189847f68d77dc16ac1))
23
+ * release develop → main (FTR-007, FTR-008, FTR-009) ([66c9e05](https://github.com/dtlab-tech/ai-toolkit/commit/66c9e05dde12be03f2c3d2a13eea112103fd6a20))
24
+
25
+
26
+ ### Bug Fixes
27
+
28
+ * **FTR-009:** remediate review issues; update registry ([6aaeeb0](https://github.com/dtlab-tech/ai-toolkit/commit/6aaeeb0465b4d2003e61f33f7c6d0641bc477f9c))
29
+ * **FTR-009:** rewrite all 5 workflow scripts with correct Workflow SDK API ([2c6da04](https://github.com/dtlab-tech/ai-toolkit/commit/2c6da041c07a1c233678cd0d64dfeaf66f0674a5))
30
+
2
31
  ## 0.1.7 (2026-07-23)
3
32
 
4
33
 
package/README.md CHANGED
@@ -65,6 +65,32 @@ The toolkit ships **generic agents** that work with any project. Each agent read
65
65
 
66
66
  Generic procedures live in `docs/procedures/`. Projects can override any of them by placing a file with the same name at their own `docs/procedures/`. Agents check the project first, then fall back to the toolkit.
67
67
 
68
+ ## Required configuration — subagent spawn depth
69
+
70
+ > ⚠️ **This setting is not optional for the orchestrated pipelines.** Without it, `/implement-feature` and `/assess-codebase` silently degrade.
71
+
72
+ The toolkit is built on a **two-level agent hierarchy**: an orchestrator (`project-manager` or `assessment-manager`) is spawned as a subagent, and it in turn spawns the specialized worker agents (developers, reviewers, assessors), each on its own role-appropriate model with an isolated context.
73
+
74
+ Since Claude Code **v2.1.217, a subagent cannot spawn further subagents by default** (spawn depth is capped at 1, an intentional guard against unbounded recursive fan-out and cost). Under that default, when an orchestrator runs as a subagent it has **no `Agent` tool** — so instead of delegating, it executes every worker's task *inline, in its own context, on its own model*. The consequences:
75
+
76
+ - **Per-agent model assignment stops taking effect** — the `haiku`/`sonnet`/`opus` mapping on each agent is never applied, because those agents are never actually spawned. Everything runs on the orchestrator's model.
77
+ - **Context isolation is lost** — one long orchestrator context replaces the intended per-agent isolation.
78
+ - **Per-agent token telemetry disappears** — no per-agent `<usage>` blocks are emitted, so `*-Token-Estimate.md` records only an aggregate orchestrator total.
79
+
80
+ To let the toolkit work as designed, raise the allowed depth to **2** (main loop → orchestrator → workers). This repo already sets it in [`.claude/settings.json`](.claude/settings.json):
81
+
82
+ ```json
83
+ {
84
+ "env": {
85
+ "CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH": "2"
86
+ }
87
+ }
88
+ ```
89
+
90
+ **When you install the toolkit into another project, you must add this setting yourself.** The installers (`npx @dtlabs/ai-toolkit`, `ai-toolkit --global`, and the `/install-toolkit` agent) **never copy or edit any `settings.json`** — that file is user-owned, and merging it automatically would risk clobbering your existing configuration. Instead, each installer **checks** whether `CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH` is set to `2`+ in the destination and, if it is missing, prints the exact snippet to add (to `.claude/settings.json` for one project, or `~/.claude/settings.json` for all projects). After adding it, restart Claude Code so the variable is loaded.
91
+
92
+ The orchestrator agents already omit the `tools:` frontmatter field, so they inherit the `Agent` tool automatically once the depth allows it — no per-agent changes are needed.
93
+
68
94
  ## Documentation
69
95
 
70
96
  - [Quick Reference](docs/reference.md) — cheatsheet of every skill, command, agent, and procedure
package/bin/cli.js CHANGED
@@ -40,10 +40,18 @@ function banner() {
40
40
 
41
41
  // ── helpers ──────────────────────────────────────────────────────────────────
42
42
 
43
+ // User-owned config that must NEVER be copied into a destination. We only verify
44
+ // and advise on these — copying would clobber the user's existing settings.
45
+ const NEVER_COPY = new Set(['settings.json', 'settings.local.json']);
46
+
43
47
  function fileHash(filePath) {
44
48
  return crypto.createHash('md5').update(fs.readFileSync(filePath)).digest('hex');
45
49
  }
46
50
 
51
+ function readJsonSafe(filePath) {
52
+ try { return JSON.parse(fs.readFileSync(filePath, 'utf8')); } catch { return null; }
53
+ }
54
+
47
55
  function ensureDir(filePath) {
48
56
  const dir = path.dirname(filePath);
49
57
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
@@ -67,10 +75,12 @@ function expandMappings(mappings) {
67
75
  if (!fs.existsSync(src)) continue;
68
76
  if (fs.statSync(src).isDirectory()) {
69
77
  for (const entry of walkDir(src)) {
78
+ if (NEVER_COPY.has(path.basename(entry))) continue; // never clobber user config
70
79
  const rel = path.relative(src, entry);
71
80
  files.push({ src: entry, dest: path.join(dest, rel) });
72
81
  }
73
82
  } else {
83
+ if (NEVER_COPY.has(path.basename(src))) continue;
74
84
  files.push({ src, dest });
75
85
  }
76
86
  }
@@ -262,6 +272,52 @@ async function askMattPocock() {
262
272
  else console.log(` ${clr('gray', 'Skipped.')}\n`);
263
273
  }
264
274
 
275
+ // ── subagent spawn-depth check (verify & advise only — never write) ────────────
276
+
277
+ const SPAWN_DEPTH_VAR = 'CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH';
278
+
279
+ // Report whether the spawn-depth prerequisite is satisfied for a destination,
280
+ // checking both project-level and local-override settings files. Purely advisory:
281
+ // this NEVER creates or modifies any settings file.
282
+ function checkSpawnDepth(destRoot) {
283
+ const candidates = [
284
+ path.join(destRoot, '.claude', 'settings.json'),
285
+ path.join(destRoot, '.claude', 'settings.local.json'),
286
+ ];
287
+
288
+ console.log(divider());
289
+ console.log(bold(' Subagent spawn depth (required for orchestrated pipelines)'));
290
+ console.log(divider());
291
+
292
+ for (const file of candidates) {
293
+ if (!fs.existsSync(file)) continue;
294
+ const json = readJsonSafe(file);
295
+ const value = json && json.env && json.env[SPAWN_DEPTH_VAR];
296
+ if (value !== undefined && Number(value) >= 2) {
297
+ console.log(` ${clr('green', '✔')} ${SPAWN_DEPTH_VAR}=${value} found in ${dim(path.relative(process.cwd(), file))}`);
298
+ console.log(` ${dim('Orchestrators can spawn worker subagents — pipelines will run as designed.')}\n`);
299
+ return;
300
+ }
301
+ }
302
+
303
+ console.log(` ${clr('yellow', '⚠')} ${SPAWN_DEPTH_VAR} is not set to 2+ in this project.`);
304
+ console.log(` ${dim('Without it, /implement-feature and /assess-codebase run every worker inline')}`);
305
+ console.log(` ${dim('on the orchestrator model: per-agent model assignment, context isolation,')}`);
306
+ console.log(` ${dim('and per-agent token telemetry are all lost.')}`);
307
+ console.log();
308
+ console.log(` ${bold('Action required')} — add this to ${clr('cyan', '.claude/settings.json')} (project)`);
309
+ console.log(` or ${clr('cyan', '~/.claude/settings.json')} (all projects). We do not edit it for you,`);
310
+ console.log(` ${dim('to avoid clobbering your existing configuration:')}`);
311
+ console.log();
312
+ console.log(clr('gray', ' {'));
313
+ console.log(clr('gray', ' "env": {'));
314
+ console.log(clr('gray', ` "${SPAWN_DEPTH_VAR}": "2"`));
315
+ console.log(clr('gray', ' }'));
316
+ console.log(clr('gray', ' }'));
317
+ console.log();
318
+ console.log(` ${dim('Then restart Claude Code so the variable is loaded.')}\n`);
319
+ }
320
+
265
321
  // ── entry points ──────────────────────────────────────────────────────────────
266
322
 
267
323
  async function installLocal(targetDir, force) {
@@ -277,6 +333,7 @@ async function installLocal(targetDir, force) {
277
333
  await runInstall(`local project`, mappings, force);
278
334
  writeInstalledVersion(targetDir);
279
335
  console.log(` ${clr('green', '✔')} ${bold('Install complete.')}\n`);
336
+ checkSpawnDepth(targetDir);
280
337
  await askMattPocock();
281
338
  console.log(divider());
282
339
  console.log(`\n ${bold('Next steps:')}`);
@@ -293,15 +350,17 @@ async function installGlobal(force) {
293
350
  console.log(` ${clr('cyan', '▸')} Target: ${bold(target)} ${clr('gray', '(global Claude folder)')}\n`);
294
351
  await checkVersion(target, force);
295
352
  const mappings = [
296
- { src: path.join(packageRoot, '.claude', 'agents'), dest: path.join(target, 'agents') },
297
- { src: path.join(packageRoot, '.claude', 'skills'), dest: path.join(target, 'skills') },
298
- { src: path.join(packageRoot, '.claude', 'commands'), dest: path.join(target, 'commands') },
299
- { src: path.join(packageRoot, 'docs'), dest: path.join(target, 'docs') },
300
- { src: path.join(packageRoot, 'CLAUDE.md'), dest: path.join(target, 'CLAUDE.md') },
353
+ { src: path.join(packageRoot, '.claude', 'agents'), dest: path.join(target, 'agents') },
354
+ { src: path.join(packageRoot, '.claude', 'skills'), dest: path.join(target, 'skills') },
355
+ { src: path.join(packageRoot, '.claude', 'commands'), dest: path.join(target, 'commands') },
356
+ { src: path.join(packageRoot, '.claude', 'workflows'), dest: path.join(target, 'workflows') },
357
+ { src: path.join(packageRoot, 'docs'), dest: path.join(target, 'docs') },
358
+ { src: path.join(packageRoot, 'CLAUDE.md'), dest: path.join(target, 'CLAUDE.md') },
301
359
  ];
302
360
  await runInstall('global Claude folder', mappings, force);
303
361
  writeInstalledVersion(target);
304
362
  console.log(` ${clr('green', '✔')} ${bold('Global install complete.')}\n`);
363
+ checkSpawnDepth(homedir);
305
364
  await askMattPocock();
306
365
  console.log(divider());
307
366
  console.log(`\n ${bold('Next steps:')}`);
@@ -0,0 +1,115 @@
1
+ # Token Optimization — Backlog di feature atomiche
2
+
3
+ > Deriva da `docs/token-optimization.md`. Data: 2026-07-24.
4
+ > Ogni voce è **atomica**: implementabile e verificabile in isolamento.
5
+ > "Criticità" = priorità di ottimizzazione (impatto/rischio), NON severità di difetto.
6
+ > Nessun intervento è un bug attivo → nessun `CRITICAL`.
7
+ > Sequenza consigliata = ordine degli ID.
8
+
9
+ ## Quadro sintetico
10
+
11
+ | ID | Intervento | Criticità | Sforzo | Rischio | File toccati | Dipende da |
12
+ |----|-----------|-----------|--------|---------|--------------|-----------|
13
+ | OPT-01 ✅ | `model:` esplicito su ogni agent (→ FTR-007, PR #20) | **HIGH** | Basso | Basso | 15 agent (frontmatter) | — |
14
+ | OPT-02 | Deduplicare CLAUDE.md globale vs progetto | **HIGH** | Minimo | Zero | `~/.claude/CLAUDE.md` | — |
15
+ | OPT-03 | Blocco "Compact instructions" in CLAUDE.md | MEDIUM | Minimo | Zero | `CLAUDE.md` (progetto) | — |
16
+ | OPT-04 | Spostare i cataloghi da CLAUDE.md a reference.md | MEDIUM | Basso | Basso | `CLAUDE.md`, `docs/reference.md` | — |
17
+ | OPT-05 | Procedure on-demand — assessment-manager | MEDIUM | Medio | Basso | `assessment-manager.md` | — |
18
+ | OPT-06 | Procedure on-demand — project-manager | MEDIUM | Medio | Basso | `project-manager.md` | — |
19
+ | OPT-07 | Resource-budget testuale negli assessment agent | MEDIUM | Basso | Basso | 3+ assessment agent | — |
20
+ | OPT-08 | Summary/full split negli output di assessment | **HIGH** | Alto | Medio | assessment agents + int-doc + manager | OPT-07 |
21
+ | OPT-09 | Estrarre calcolo deterministico da assessment-manager | **HIGH** | Alto | Medio | `assessment-manager.md` + nuovo script | — |
22
+ | OPT-10 | generic-software-assessment → ruolo triage | MEDIUM | Medio | Medio | `generic-software-assessment.md` + manager | OPT-08 |
23
+ | OPT-11 | Delegation policy negli orchestratori | LOW | Basso | Basso | 2 orchestratori | — |
24
+ | OPT-12 | Hook di filtro output verboso (opzionale) | LOW | Basso | Basso | `settings.json` + script hook | — |
25
+
26
+ ---
27
+
28
+ ## Feature atomiche
29
+
30
+ ### OPT-01 — `model:` esplicito su ogni agent
31
+ - **Criticità:** HIGH · **Sforzo:** Basso · **Rischio:** Basso
32
+ - **Obiettivo:** ogni agent dichiara il modello adatto al suo ruolo, così nessuno eredita Opus per default.
33
+ - **Scope (solo frontmatter):** aggiungere `model:` ai 15 agent che ne sono privi. Mappatura:
34
+ - `sonnet`: `assessment-manager`, `project-manager`, `developer-backend`, `developer-frontend`, `developer-testing`, `god-class-decomposition`, `domain-model-refactoring`, `dependency-injection-refactoring`, `security-hardening`, `dependency-supply-chain-security`, `define-feature`, `init-agents-md`, `install-toolkit`, `intervention-documentation-standard`
35
+ - `opus`: `review-solution` (unico ruolo con giudizio architetturale profondo)
36
+ - **Fuori scope:** i 7 agent già `haiku` restano invariati.
37
+ - **Criteri di accettazione:** `grep -L "^model:" .claude/agents/*.md` non restituisce nulla; ogni valore ∈ {haiku, sonnet, opus}.
38
+ - **Dipendenze:** nessuna.
39
+
40
+ ### OPT-02 — Deduplicare CLAUDE.md globale vs progetto
41
+ - **Criticità:** HIGH · **Sforzo:** Minimo · **Rischio:** Zero
42
+ - **Obiettivo:** eliminare il duplicato caricato a ogni sessione; il `CLAUDE.md` di progetto resta la fonte unica del catalogo toolkit.
43
+ - **Scope:** ridurre `~/.claude/CLAUDE.md` alle sole preferenze cross-progetto (lingua, stile, convenzioni personali). Rimuovere il catalogo toolkit duplicato.
44
+ - **Criteri di accettazione:** `diff ~/.claude/CLAUDE.md ./CLAUDE.md` NON è più identico; il globale non contiene più le tabelle Skills/Commands/Agents; il Gate Protocol resta accessibile (nel progetto).
45
+ - **Dipendenze:** nessuna. ⚠️ File utente globale — confermare con l'utente prima di modificare.
46
+
47
+ ### OPT-03 — Blocco "Compact instructions" in CLAUDE.md
48
+ - **Criticità:** MEDIUM · **Sforzo:** Minimo · **Rischio:** Zero
49
+ - **Obiettivo:** guidare l'auto-compaction a preservare ciò che conta (decisioni, file, finding IDs) e scartare rumore.
50
+ - **Scope:** aggiungere al `CLAUDE.md` di progetto una sezione `# Compact instructions` (preserva: obiettivo corrente, decisioni confermate, risposte utente, file modificati, errori aperti, finding/artifact IDs; scarta: risultati grep grezzi, output tool riusciti, spiegazioni ripetute, piani superati).
51
+ - **Criteri di accettazione:** la sezione esiste in `CLAUDE.md`; nessun'altra modifica.
52
+ - **Dipendenze:** nessuna. (Coordinare con OPT-04 se si tocca lo stesso file.)
53
+
54
+ ### OPT-04 — Spostare i cataloghi da CLAUDE.md a reference.md
55
+ - **Criticità:** MEDIUM · **Sforzo:** Basso · **Rischio:** Basso
56
+ - **Obiettivo:** CLAUDE.md sotto ~200 righe, solo essenziali operativi; il catalogo di scoperta vive in reference.md.
57
+ - **Scope:** spostare le tabelle Skills / Commands / Agents / Procedures in `docs/reference.md`. In `CLAUDE.md` restano: Dependencies, How it works, override procedure, **Gate Protocol**. Aggiungere in CLAUDE.md un puntatore a reference.md.
58
+ - **Criteri di accettazione:** `CLAUDE.md` < 200 righe; nessuna tabella-catalogo persa (presente in reference.md); Gate Protocol ancora in CLAUDE.md.
59
+ - **Dipendenze:** nessuna.
60
+
61
+ ### OPT-05 — Procedure on-demand (assessment-manager)
62
+ - **Criticità:** MEDIUM · **Sforzo:** Medio · **Rischio:** Basso
63
+ - **Obiettivo:** leggere ogni procedura nella fase in cui serve, non tutte all'avvio.
64
+ - **Scope:** in `assessment-manager.md`, spostare le istruzioni "read at startup" così che `token-estimation.md`/`pricing.md` si leggano in Phase 3-4, `assessment-findings-gate.md` in Phase 5, ecc.
65
+ - **Criteri di accettazione:** nessuna procedura letta prima della fase che la usa; il comportamento delle fasi resta invariato.
66
+ - **Dipendenze:** nessuna. (Se si fa OPT-09, `token-estimation.md` sparisce del tutto dal contesto LLM.)
67
+
68
+ ### OPT-06 — Procedure on-demand (project-manager)
69
+ - **Criticità:** MEDIUM · **Sforzo:** Medio · **Rischio:** Basso
70
+ - **Obiettivo:** stesso principio di OPT-05 applicato al `project-manager` (che legge ancora più procedure).
71
+ - **Scope:** riorganizzare `project-manager.md` per caricare ogni procedura alla fase pertinente (PR-procedure alla fase PR, ecc.).
72
+ - **Criteri di accettazione:** nessuna procedura caricata anticipatamente; pipeline invariata.
73
+ - **Dipendenze:** nessuna.
74
+
75
+ ### OPT-07 — Resource-budget testuale negli assessment agent
76
+ - **Criticità:** MEDIUM · **Sforzo:** Basso · **Rischio:** Basso
77
+ - **Obiettivo:** limiti di lettura/output come **istruzioni nel prompt** (NON frontmatter — `budget:` non è supportato dall'harness).
78
+ - **Scope:** aggiungere una sezione `## Resource budget` in prosa agli assessment agent (es. "Inspect at most ~25 files; ≤2 evidence snippets per finding; stop when evidence is sufficient — do not explore to increase coverage").
79
+ - **Criteri di accettazione:** la sezione è testo del prompt, non YAML; presente in `generic-software-assessment`, `layered-architecture-assessment`, `concurrency-safety-assessment`.
80
+ - **Dipendenze:** nessuna.
81
+
82
+ ### OPT-08 — Summary/full split negli output di assessment
83
+ - **Criticità:** HIGH · **Sforzo:** Alto · **Rischio:** Medio
84
+ - **Obiettivo:** l'orchestratore legge un **summary compatto**, non il documento intero. Il guadagno reale (non il formato JSON in sé).
85
+ - **Scope:** ogni assessment agent produce `{PREFIX}-{area}.full.md` (dettagli) + `{PREFIX}-{area}.summary` (conteggi per severità, finding IDs, path del full). `assessment-manager` e `intervention-documentation-standard` consumano il summary; il full si apre solo per i finding accettati.
86
+ - **Criteri di accettazione:** ogni agent scrive entrambi i file; il manager non legge i `.full` in Phase 3; l'int-doc apre i full solo per i finding selezionati.
87
+ - **Dipendenze:** OPT-07 (budget di output coerente).
88
+
89
+ ### OPT-09 — Estrarre calcolo deterministico da assessment-manager
90
+ - **Criticità:** HIGH · **Sforzo:** Alto · **Rischio:** Medio
91
+ - **Obiettivo:** togliere dal prompt ~3.500 parole di pseudo-codice (calcolo token/effort, registry write) che un LLM esegue in modo costoso e fragile.
92
+ - **Scope:** spostare Token-Estimate / Effort-Estimate / registry-write in uno script (`scripts/estimate.*`) invocato via Bash; il prompt dell'agent si riduce a "esegui lo script con questi input e verifica l'output".
93
+ - **Criteri di accettazione:** i tre file prodotti sono identici (per input noti) a prima; `assessment-manager.md` perde le sezioni di calcolo passo-passo; nessun errore aritmetico possibile lato LLM.
94
+ - **Dipendenze:** nessuna hard; sinergica con OPT-05.
95
+
96
+ ### OPT-10 — generic-software-assessment → ruolo triage
97
+ - **Criticità:** MEDIUM · **Sforzo:** Medio · **Rischio:** Medio
98
+ - **Obiettivo:** evitare che il generic duplichi il lavoro degli specialisti (layer, security, concurrency) sullo stesso codebase.
99
+ - **Scope:** trasformare `generic-software-assessment` in triage: scansione superficiale che decide quali specialisti attivare e copre solo le aree non coperte (Opzione A della gap analysis).
100
+ - **Criteri di accettazione:** il generic non riesamina aree già coperte da uno specialista attivo; l'output indica gli specialisti raccomandati.
101
+ - **Dipendenze:** meglio dopo OPT-08 (contratto di output stabile).
102
+
103
+ ### OPT-11 — Delegation policy negli orchestratori
104
+ - **Criticità:** LOW · **Sforzo:** Basso · **Rischio:** Basso
105
+ - **Obiettivo:** regola esplicita "delega un subagent solo se serve" (task indipendente/parallelo, output voluminoso, riuso multiplo); non delegare ciò che una grep/read risolve.
106
+ - **Scope:** aggiungere una sezione `## Delegation policy` a `assessment-manager` e `project-manager`.
107
+ - **Criteri di accettazione:** entrambi gli orchestratori contengono i criteri delega/non-delega.
108
+ - **Dipendenze:** nessuna.
109
+
110
+ ### OPT-12 — Hook di filtro output verboso (opzionale)
111
+ - **Criticità:** LOW · **Sforzo:** Basso · **Rischio:** Basso
112
+ - **Obiettivo:** filtrare output verbosi (build/test/log) prima che entrino nel contesto.
113
+ - **Scope:** `PreToolUse` su Bash in `settings.json` + script che riduce l'output di test/build alle sole righe rilevanti.
114
+ - **Criteri di accettazione:** l'hook appare in `/hooks`; un comando di test mostra solo failures.
115
+ - **Dipendenze:** nessuna. Fare solo se gli assessment inizieranno a lanciare build/test.