@punks/cli 1.0.2 → 1.0.3

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/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # DevPunks CLI
1
+ # Devpunks CLI
2
2
 
3
3
  `punks` scaffolds the AI operating context for each project phase, from requirements and backlog prep to the repo-aware setup pass.
4
4
  This repo carries the executable CLI plus the canonical bundled scaffold baseline under `src/data` and `skills/`.
@@ -82,6 +82,15 @@ bun run release:publish
82
82
 
83
83
  `bun run release:publish` publishes the current `package.json` version to npm, updates the `latest` and `next` dist-tags, and pushes the matching `v<version>` git tag. Commit and push the version bump before running it; the script refuses dirty worktrees and existing tags that point at another commit.
84
84
 
85
+ Before npm releases, authenticate against the public npm registry:
86
+
87
+ ```bash
88
+ npm login --registry=https://registry.npmjs.org/
89
+ npm whoami
90
+ ```
91
+
92
+ The logged-in account must have publish access to `@punks/cli`.
93
+
85
94
  ## Development
86
95
 
87
96
  ```bash
@@ -25,31 +25,24 @@ export interface LintAssetDefinition {
25
25
 
26
26
  const sharedReactPlacement = {
27
27
  recommendedConfigFile: ".oxlintrc.json",
28
- recommendedFiles: [
29
- "apps/web/**/*.{js,jsx,ts,tsx}",
30
- "packages/ui/**/*.{js,jsx,ts,tsx}",
31
- ],
32
- recommendedWorkspaces: ["apps/web", "packages/ui"],
28
+ recommendedFiles: ["<detected-react-workspace>/**/*.{js,jsx,ts,tsx}"],
29
+ recommendedWorkspaces: ["detected React workspaces"],
33
30
  placementNotes:
34
- "Add as an override for React-rendered code. Keep the same scope for shared UI packages unless the target repo clearly splits product UI into other workspaces.",
31
+ "Add as an override for detected React-rendered code. Keep backend packages outside this override unless they render React.",
35
32
  } as const satisfies LintPlacementDefinition;
36
33
 
37
34
  const webOnlyPlacement = {
38
35
  recommendedConfigFile: ".oxlintrc.json",
39
- recommendedFiles: ["apps/web/**/*.{js,jsx,ts,tsx}"],
40
- recommendedWorkspaces: ["apps/web"],
36
+ recommendedFiles: ["<detected-nextjs-workspace>/**/*.{js,jsx,ts,tsx}"],
37
+ recommendedWorkspaces: ["detected Next.js workspaces"],
41
38
  placementNotes:
42
39
  "Place this in the Next.js app override. If the repo uses a different frontend app path, retarget the file globs to that workspace before composing the final Oxlint config.",
43
40
  } as const satisfies LintPlacementDefinition;
44
41
 
45
42
  const effectPlacement = {
46
43
  recommendedConfigFile: ".oxlintrc.json",
47
- recommendedFiles: [
48
- "apps/server/**/*.{js,jsx,ts,tsx}",
49
- "packages/api/**/*.{js,jsx,ts,tsx}",
50
- "packages/db/**/*.{js,jsx,ts,tsx}",
51
- ],
52
- recommendedWorkspaces: ["apps/server", "packages/api", "packages/db"],
44
+ recommendedFiles: ["<detected-effect-workspace>/**/*.{js,jsx,ts,tsx}"],
45
+ recommendedWorkspaces: ["detected Effect workspaces"],
53
46
  placementNotes:
54
47
  "Apply this only where Effect code lives. If the target repo renames or splits backend workspaces, move the override with those code paths instead of broadening it repo-wide.",
55
48
  } as const satisfies LintPlacementDefinition;
@@ -57,11 +50,10 @@ const effectPlacement = {
57
50
  const vitestPlacement = {
58
51
  recommendedConfigFile: ".oxlintrc.json",
59
52
  recommendedFiles: [
60
- "apps/web/**/*.{test,spec}.{js,jsx,ts,tsx}",
61
- "apps/web/src/test/**/*.{js,jsx,ts,tsx}",
62
- "packages/api/**/*.{test,spec}.{js,jsx,ts,tsx}",
53
+ "<detected-test-workspace>/**/*.{test,spec}.{js,jsx,ts,tsx}",
54
+ "<detected-test-workspace>/src/test/**/*.{js,jsx,ts,tsx}",
63
55
  ],
64
- recommendedWorkspaces: ["apps/web", "packages/api"],
56
+ recommendedWorkspaces: ["detected JavaScript/TypeScript test workspaces"],
65
57
  placementNotes:
66
58
  "Attach this to test-only globs. Expand or narrow the file patterns to match the repo's actual Vitest test layout instead of treating it as a global default.",
67
59
  } as const satisfies LintPlacementDefinition;
@@ -23,11 +23,11 @@ export interface PackCatalogEntry {
23
23
  }
24
24
 
25
25
  export const packCatalog = [
26
- { id: "backend", category: "surface", triggerPackages: [], description: "Backend pack: domain structure and recoverable actions.", skills: ["backend-domain-structure", "backend-recoverable-actions"], lintAssets: [], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "workspace-prompt-spec"], promptDetails: ["shared backend domain baseline", "workspace backend action/recovery guidance"] },
26
+ { id: "backend", category: "surface", triggerPackages: [], description: "Backend pack: domain structure, recoverable actions, and logging.", skills: ["backend-domain-structure", "backend-recoverable-actions", "logging-best-practices"], lintAssets: [], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "workspace-prompt-spec"], promptDetails: ["shared backend domain baseline", "workspace backend action/recovery guidance", "workspace logging/observability guidance"] },
27
27
  { id: "better-auth", category: "detected", triggerPackages: ["better-auth"], description: "Better Auth guidance pack.", skills: ["better-auth-best-practices"], lintAssets: [], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "workspace-prompt-spec"], promptDetails: ["shared auth guardrails", "workspace auth boundaries"] },
28
28
  { id: "debug", category: "default", triggerPackages: [], description: "Default debug pack: debug-agent runtime-evidence workflow.", skills: ["debug-agent"], lintAssets: [], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "workspace-prompt-spec"], promptDetails: ["shared runtime debugging baseline", "workspace evidence-first debugging workflow"] },
29
29
  { id: "docs", category: "default", triggerPackages: [], description: "Default docs pack: docs-maintenance.", skills: ["docs-maintenance"], lintAssets: [], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "docs-prompt-spec"], promptDetails: ["shared docs baseline", "docs scope spec"] },
30
- { id: "drizzle", category: "detected", triggerPackages: ["drizzle-kit", "drizzle-orm"], description: "Drizzle guidance pack.", skills: ["effect-backend-structure", "effect-recoverable-actions"], lintAssets: [], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "workspace-prompt-spec"], promptDetails: ["shared data-layer baseline", "workspace db flow rules"] },
30
+ { id: "drizzle", category: "detected", triggerPackages: ["drizzle-kit", "drizzle-orm"], description: "Drizzle guidance pack.", skills: [], lintAssets: [], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "workspace-prompt-spec"], promptDetails: ["shared data-layer baseline", "workspace db flow rules"] },
31
31
  { id: "effect", category: "detected", triggerPackages: ["effect", "@effect/"], description: "Effect guidance pack family.", skills: ["effect-authoring", "effect-best-practices", "effect-backend-structure", "effect-recoverable-actions"], lintAssets: ["effect-no-barrel-imports"], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "workspace-prompt-spec"], promptDetails: ["shared effect authoring baseline", "workspace service/layer rules"] },
32
32
  { id: "elysia", category: "detected", triggerPackages: ["elysia"], description: "Elysia guidance pack.", skills: ["elysiajs"], lintAssets: [], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "workspace-prompt-spec"], promptDetails: ["shared api-server baseline", "workspace route/plugin rules"] },
33
33
  { id: "frontend", category: "surface", triggerPackages: [], description: "Frontend pack: agent-browser, design taste, and frontend domain structure.", skills: ["agent-browser", "design-taste-frontend", "frontend-domain-structure"], lintAssets: [], hooks: [], promptSurfaces: ["shared-agents", "root-prompt-spec", "workspace-prompt-spec"], promptDetails: ["shared product-ui baseline", "workspace UX/browser guidance", "workspace frontend domain boundaries"] },
@@ -15,6 +15,7 @@ export const skillCatalog = [
15
15
  { id: "agent-browser", sourceDirectory: "skills/agnostic/frontend/agent-browser", tier: "framework", language: null, framework: "browser-automation", requiresTools: ["agent-browser"] },
16
16
  { id: "backend-domain-structure", sourceDirectory: "skills/agnostic/backend/backend-domain-structure", tier: "agnostic", language: null, framework: null, requiresTools: [] },
17
17
  { id: "backend-recoverable-actions", sourceDirectory: "skills/agnostic/backend/backend-recoverable-actions", tier: "agnostic", language: null, framework: null, requiresTools: [] },
18
+ { id: "logging-best-practices", sourceDirectory: "skills/agnostic/backend/logging-best-practices", tier: "agnostic", language: null, framework: null, requiresTools: [] },
18
19
  { id: "better-auth-best-practices", sourceDirectory: "skills/frameworks/better-auth/better-auth-best-practices", tier: "framework", language: "typescript", framework: "better-auth", requiresTools: [] },
19
20
  { id: "create-plan", sourceDirectory: "skills/agnostic/planning/create-plan", tier: "agnostic", language: null, framework: null, requiresTools: [] },
20
21
  { id: "create-spec", sourceDirectory: "skills/agnostic/planning/create-spec", tier: "agnostic", language: null, framework: null, requiresTools: [] },
@@ -52,92 +52,131 @@ const cursorManagedComment =
52
52
  const opencodeManagedComment =
53
53
  "<!-- Generated by scripts/sync-subagents.mjs. Edit .agents/subagents/manifest.mjs instead. -->";
54
54
 
55
- const codexAgentConfig = [
56
- "[agents]",
57
- "max_threads = 6",
58
- "max_depth = 1",
59
- "",
60
- "[features]",
61
- "codex_hooks = true",
62
- "",
63
- "[hooks]",
64
- "SessionStart = [",
65
- ' { matcher = "startup|resume", hooks = [',
66
- ' { type = "command", command = "node \\"$(git rev-parse --show-toplevel)/.codex/hooks/format-edited-file.mjs\\" session-start", statusMessage = "Capturing edited-file baseline", timeout = 30 },',
67
- " ] },",
68
- "]",
69
- "PreToolUse = [",
70
- ' { matcher = "Bash|.*[Pp]ull.?[Rr]equest.*|.*[Pp][Rr].?[Cc]reate.*|.*create[_-]?pull[_-]?request.*", hooks = [',
71
- ' { type = "command", command = "node \\"$(git rev-parse --show-toplevel)/.codex/hooks/require-tests-for-pr.mjs\\" codex", statusMessage = "Checking tests before PR creation", timeout = 600 },',
72
- " ] },",
73
- "]",
74
- "PostToolUse = [",
75
- ' { matcher = "Bash|apply_patch|.*apply.?patch.*|edit|write|multiedit", hooks = [',
76
- ' { type = "command", command = "node \\"$(git rev-parse --show-toplevel)/.codex/hooks/format-edited-file.mjs\\" post", statusMessage = "Auto-formatting edited files", timeout = 30 },',
77
- " ] },",
78
- "]",
79
- "",
80
- ].join("\n");
55
+ function buildCodexAgentConfig({ hasFormatHook, hasTestHook }) {
56
+ const lines = [
57
+ "[agents]",
58
+ "max_threads = 6",
59
+ "max_depth = 1",
60
+ "",
61
+ "[features]",
62
+ "codex_hooks = true",
63
+ "",
64
+ "[hooks]",
65
+ ];
66
+
67
+ if (hasFormatHook) {
68
+ lines.push(
69
+ "SessionStart = [",
70
+ ' { matcher = "startup|resume", hooks = [',
71
+ ' { type = "command", command = "node \\"$(git rev-parse --show-toplevel)/.codex/hooks/format-edited-file.mjs\\" session-start", statusMessage = "Capturing edited-file baseline", timeout = 30 },',
72
+ " ] },",
73
+ "]",
74
+ );
75
+ }
76
+
77
+ if (hasTestHook) {
78
+ lines.push(
79
+ "PreToolUse = [",
80
+ ' { matcher = "Bash|.*[Pp]ull.?[Rr]equest.*|.*[Pp][Rr].?[Cc]reate.*|.*create[_-]?pull[_-]?request.*", hooks = [',
81
+ ' { type = "command", command = "node \\"$(git rev-parse --show-toplevel)/.codex/hooks/require-tests-for-pr.mjs\\" codex", statusMessage = "Checking tests before PR creation", timeout = 600 },',
82
+ " ] },",
83
+ "]",
84
+ );
85
+ }
81
86
 
82
- const claudeSettingsConfig = {
83
- hooks: {
84
- PreToolUse: [
85
- {
86
- matcher: "mcp__github__create_pull_request",
87
- hooks: [
88
- {
89
- type: "command",
90
- command: 'node "$CLAUDE_PROJECT_DIR"/.claude/hooks/require-tests-for-pr.mjs claude',
91
- timeout: 600,
92
- },
93
- ],
94
- },
95
- {
96
- matcher: "Bash",
97
- hooks: [
98
- {
99
- type: "command",
100
- command: 'node "$CLAUDE_PROJECT_DIR"/.claude/hooks/require-tests-for-pr.mjs claude',
101
- timeout: 600,
102
- },
103
- ],
104
- },
105
- ],
106
- PostToolUse: [
107
- {
108
- matcher: "Edit|Write|MultiEdit",
109
- hooks: [
110
- {
111
- type: "command",
112
- command: 'node "$CLAUDE_PROJECT_DIR"/.claude/hooks/format-edited-file.mjs claude',
113
- timeout: 30,
114
- },
115
- ],
116
- },
117
- ],
118
- },
119
- };
120
-
121
- const cursorHooksConfig = {
122
- version: 1,
123
- hooks: {
124
- beforeMCPExecution: [
125
- {
126
- command: "node .cursor/hooks/require-tests-for-pr.mjs cursor",
127
- },
128
- ],
129
- beforeShellExecution: [
130
- {
131
- command: "node .cursor/hooks/require-tests-for-pr.mjs cursor",
132
- },
133
- ],
134
- afterFileEdit: [
135
- {
136
- command: "node .cursor/hooks/format-edited-file.mjs cursor",
137
- },
138
- ],
139
- },
140
- };
87
+ if (hasFormatHook) {
88
+ lines.push(
89
+ "PostToolUse = [",
90
+ ' { matcher = "Bash|apply_patch|.*apply.?patch.*|edit|write|multiedit", hooks = [',
91
+ ' { type = "command", command = "node \\"$(git rev-parse --show-toplevel)/.codex/hooks/format-edited-file.mjs\\" post", statusMessage = "Auto-formatting edited files", timeout = 30 },',
92
+ " ] },",
93
+ "]",
94
+ );
95
+ }
96
+
97
+ lines.push("");
98
+ return lines.join("\n");
99
+ }
100
+
101
+ function buildClaudeSettingsConfig({ hasFormatHook, hasTestHook }) {
102
+ return {
103
+ hooks: {
104
+ ...(hasTestHook
105
+ ? {
106
+ PreToolUse: [
107
+ {
108
+ matcher: "mcp__github__create_pull_request",
109
+ hooks: [
110
+ {
111
+ type: "command",
112
+ command: 'node "$CLAUDE_PROJECT_DIR"/.claude/hooks/require-tests-for-pr.mjs claude',
113
+ timeout: 600,
114
+ },
115
+ ],
116
+ },
117
+ {
118
+ matcher: "Bash",
119
+ hooks: [
120
+ {
121
+ type: "command",
122
+ command: 'node "$CLAUDE_PROJECT_DIR"/.claude/hooks/require-tests-for-pr.mjs claude',
123
+ timeout: 600,
124
+ },
125
+ ],
126
+ },
127
+ ],
128
+ }
129
+ : {}),
130
+ ...(hasFormatHook
131
+ ? {
132
+ PostToolUse: [
133
+ {
134
+ matcher: "Edit|Write|MultiEdit",
135
+ hooks: [
136
+ {
137
+ type: "command",
138
+ command: 'node "$CLAUDE_PROJECT_DIR"/.claude/hooks/format-edited-file.mjs claude',
139
+ timeout: 30,
140
+ },
141
+ ],
142
+ },
143
+ ],
144
+ }
145
+ : {}),
146
+ },
147
+ };
148
+ }
149
+
150
+ function buildCursorHooksConfig({ hasFormatHook, hasTestHook }) {
151
+ return {
152
+ version: 1,
153
+ hooks: {
154
+ ...(hasTestHook
155
+ ? {
156
+ beforeMCPExecution: [
157
+ {
158
+ command: "node .cursor/hooks/require-tests-for-pr.mjs cursor",
159
+ },
160
+ ],
161
+ beforeShellExecution: [
162
+ {
163
+ command: "node .cursor/hooks/require-tests-for-pr.mjs cursor",
164
+ },
165
+ ],
166
+ }
167
+ : {}),
168
+ ...(hasFormatHook
169
+ ? {
170
+ afterFileEdit: [
171
+ {
172
+ command: "node .cursor/hooks/format-edited-file.mjs cursor",
173
+ },
174
+ ],
175
+ }
176
+ : {}),
177
+ },
178
+ };
179
+ }
141
180
 
142
181
  function getSkillNames(agent) {
143
182
  if (Array.isArray(agent.skills)) {
@@ -306,6 +345,18 @@ async function ensureSymlink(linkPath, targetPath) {
306
345
  await symlink(relativeTarget, linkPath);
307
346
  }
308
347
 
348
+ async function pathExists(filePath) {
349
+ try {
350
+ await lstat(filePath);
351
+ return true;
352
+ } catch (error) {
353
+ if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
354
+ return false;
355
+ }
356
+ throw error;
357
+ }
358
+ }
359
+
309
360
  async function writeManagedFiles(directory, extension, renderedByName) {
310
361
  await mkdir(directory, { recursive: true });
311
362
 
@@ -340,38 +391,26 @@ async function syncHookSurface() {
340
391
  await mkdir(cursorHooksDir, { recursive: true });
341
392
  await mkdir(opencodePluginsDir, { recursive: true });
342
393
 
343
- await ensureSymlink(
344
- path.join(codexHooksDir, "format-edited-file.mjs"),
345
- path.join(sharedHooksPath, "format-edited-file.mjs"),
346
- );
347
- await ensureSymlink(
348
- path.join(codexHooksDir, "require-tests-for-pr.mjs"),
349
- path.join(sharedHooksPath, "require-tests-for-pr.mjs"),
350
- );
351
- await ensureSymlink(
352
- path.join(claudeHooksDir, "format-edited-file.mjs"),
353
- path.join(sharedHooksPath, "format-edited-file.mjs"),
354
- );
355
- await ensureSymlink(
356
- path.join(claudeHooksDir, "require-tests-for-pr.mjs"),
357
- path.join(sharedHooksPath, "require-tests-for-pr.mjs"),
358
- );
359
- await ensureSymlink(
360
- path.join(cursorHooksDir, "format-edited-file.mjs"),
361
- path.join(sharedHooksPath, "format-edited-file.mjs"),
362
- );
363
- await ensureSymlink(
364
- path.join(cursorHooksDir, "require-tests-for-pr.mjs"),
365
- path.join(sharedHooksPath, "require-tests-for-pr.mjs"),
366
- );
367
- await ensureSymlink(
368
- path.join(opencodePluginsDir, "format-edited-file.mjs"),
369
- path.join(sharedHooksPath, "format-edited-file.mjs"),
370
- );
371
- await ensureSymlink(
372
- path.join(opencodePluginsDir, "require-tests-for-pr.mjs"),
373
- path.join(sharedHooksPath, "require-tests-for-pr.mjs"),
374
- );
394
+ for (const hookName of ["format-edited-file.mjs", "require-tests-for-pr.mjs"]) {
395
+ const sourcePath = path.join(sharedHooksPath, hookName);
396
+ const targetPaths = [
397
+ path.join(codexHooksDir, hookName),
398
+ path.join(claudeHooksDir, hookName),
399
+ path.join(cursorHooksDir, hookName),
400
+ path.join(opencodePluginsDir, hookName),
401
+ ];
402
+
403
+ if (await pathExists(sourcePath)) {
404
+ for (const targetPath of targetPaths) {
405
+ await ensureSymlink(targetPath, sourcePath);
406
+ }
407
+ continue;
408
+ }
409
+
410
+ for (const targetPath of targetPaths) {
411
+ await rm(targetPath, { force: true, recursive: true });
412
+ }
413
+ }
375
414
  }
376
415
 
377
416
  async function syncSkillMirrors() {
@@ -404,10 +443,14 @@ async function main() {
404
443
  await mkdir(path.dirname(codexConfigPath), { recursive: true });
405
444
  await mkdir(path.dirname(claudeSettingsPath), { recursive: true });
406
445
  await mkdir(path.dirname(cursorHooksJsonPath), { recursive: true });
407
- await writeFile(codexConfigPath, codexAgentConfig, "utf8");
446
+ const availableHooks = {
447
+ hasFormatHook: await pathExists(path.join(sharedHooksPath, "format-edited-file.mjs")),
448
+ hasTestHook: await pathExists(path.join(sharedHooksPath, "require-tests-for-pr.mjs")),
449
+ };
450
+ await writeFile(codexConfigPath, buildCodexAgentConfig(availableHooks), "utf8");
408
451
  await rm(path.join(codexDir, "hooks.json"), { force: true });
409
- await writeFile(claudeSettingsPath, encodeJson(claudeSettingsConfig), "utf8");
410
- await writeFile(cursorHooksJsonPath, encodeJson(cursorHooksConfig), "utf8");
452
+ await writeFile(claudeSettingsPath, encodeJson(buildClaudeSettingsConfig(availableHooks)), "utf8");
453
+ await writeFile(cursorHooksJsonPath, encodeJson(buildCursorHooksConfig(availableHooks)), "utf8");
411
454
  await writeManagedFiles(claudeAgentsDir, "md", claudeFiles);
412
455
  await writeManagedFiles(codexAgentsDir, "toml", codexFiles);
413
456
  await writeManagedFiles(cursorAgentsDir, "md", cursorFiles);
@@ -62,6 +62,11 @@ const capabilityPacks = {
62
62
  "Repo documentation maintenance, routing, and human-facing durable knowledge capture.",
63
63
  skills: ["docs-maintenance"],
64
64
  },
65
+ "review-core": {
66
+ description:
67
+ "Cross-cutting review, simplification, and architecture-friction analysis for changed code.",
68
+ skills: ["simplify", "improve-codebase-architecture"],
69
+ },
65
70
  "python-core": {
66
71
  description:
67
72
  "Python project structure, code style, design boundaries, and everyday implementation guidance.",
@@ -102,7 +107,31 @@ const skillActivationInstructions = [
102
107
  "Do not rely on role name or inherited context alone; scoped AGENTS.md skill routing is part of the task contract.",
103
108
  ];
104
109
 
110
+ const reviewActivationInstructions = [
111
+ ...skillActivationInstructions,
112
+ "Stay read-only unless the parent explicitly asks for fixes.",
113
+ "Lead with findings, sorted by severity, with precise file/line references.",
114
+ "Use `simplify` to evaluate whether recently changed code can be clearer, smaller, or less stateful.",
115
+ "Use `improve-codebase-architecture` only when the review reveals cross-module coupling, shallow-module sprawl, testability friction, or AI-navigation problems worth surfacing.",
116
+ ];
117
+
105
118
  const agents = [
119
+ {
120
+ name: "code-review",
121
+ description:
122
+ "Use for cross-cutting code review centered on bugs, regressions, simplification opportunities, architecture friction, and review-ready findings across changed code.",
123
+ ownedPaths: ["**/*"],
124
+ guidanceFiles: ["AGENTS.md"],
125
+ activationInstructions: reviewActivationInstructions,
126
+ packs: ["review-core"],
127
+ skills: ["simplify", "improve-codebase-architecture"],
128
+ boundaries: [
129
+ "Review first: identify concrete defects, behavioral risks, missing tests, and simplification opportunities before summarizing.",
130
+ "Do not edit files unless the parent explicitly assigns implementation after the review.",
131
+ "Keep architecture notes grounded in observed code friction; return candidate refactors or follow-up RFC recommendations instead of speculative rewrites.",
132
+ "If the task asks for feature work rather than review, tell the parent to use the relevant implementation specialist.",
133
+ ],
134
+ },
106
135
  {
107
136
  name: "docs-maintenance",
108
137
  description: