@martinffx/atelier 1.4.0 → 2.0.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/dist/atelier.js CHANGED
@@ -31996,10 +31996,13 @@ var coerce = {
31996
31996
  };
31997
31997
  var NEVER = INVALID;
31998
31998
  // src/constants.ts
31999
- var HARNESS_NAMES = ["claude", "opencode", "codex"];
32000
- var AGENT_NAMES = ["recon", "oracle", "architect"];
31999
+ var Harness = ["claude", "opencode", "codex", "cursor"];
32000
+ var AGENT_NAMES = ["sentinel", "oracle", "architect"];
32001
+ var LEGACY_AGENT_NAME = "recon";
32001
32002
 
32002
32003
  // src/utils/errors.ts
32004
+ var harnessChoices = `${Harness.slice(0, -1).join(", ")}, or ${Harness.at(-1)}`;
32005
+
32003
32006
  class AtelierError extends Error {
32004
32007
  code;
32005
32008
  exitCode;
@@ -32013,19 +32016,19 @@ class AtelierError extends Error {
32013
32016
 
32014
32017
  class ConfigNotFoundError extends AtelierError {
32015
32018
  constructor(command) {
32016
- super(`.atelier/config.json not found. Run \`atelier ${command} --harness <claude|opencode|codex>\` first.`, "CONFIG_NOT_FOUND", 1);
32019
+ super(`.atelier/config.json not found. Run \`atelier ${command} --harness <${Harness.join("|")}>\` first.`, "CONFIG_NOT_FOUND", 1);
32017
32020
  }
32018
32021
  }
32019
32022
 
32020
32023
  class HarnessRequiredError extends AtelierError {
32021
32024
  constructor() {
32022
- super("`--yes` requires `--harness` (claude, opencode, or codex).", "HARNESS_REQUIRED", 1);
32025
+ super(`\`--yes\` requires \`--harness\` (${harnessChoices}).`, "HARNESS_REQUIRED", 1);
32023
32026
  }
32024
32027
  }
32025
32028
 
32026
32029
  class InvalidHarnessError extends AtelierError {
32027
32030
  constructor(value) {
32028
- super(`Invalid harness "${value}". Must be claude, opencode, or codex.`, "INVALID_HARNESS", 1);
32031
+ super(`Invalid harness "${value}". Must be ${harnessChoices}.`, "INVALID_HARNESS", 1);
32029
32032
  }
32030
32033
  }
32031
32034
  class FileWriteError extends AtelierError {
@@ -32041,7 +32044,7 @@ class HarnessConfigError extends AtelierError {
32041
32044
  }
32042
32045
  class InvalidConfigError extends AtelierError {
32043
32046
  constructor(cause, { suggestReinit = false } = {}) {
32044
- const suffix = suggestReinit ? " Run `atelier init --harness <claude|opencode|codex>` to reconfigure." : "";
32047
+ const suffix = suggestReinit ? ` Run \`atelier init --harness <${Harness.join("|")}>\` to reconfigure.` : "";
32045
32048
  super(`Invalid configuration: ${cause}.${suffix}`, "INVALID_CONFIG", 1);
32046
32049
  }
32047
32050
  }
@@ -32131,18 +32134,46 @@ function readConfig(path2 = CONFIG_PATH) {
32131
32134
  });
32132
32135
  }
32133
32136
  try {
32134
- return ok(validateConfig(parsed));
32137
+ return ok(validateConfig(migrateLegacyAgentName(parsed)));
32135
32138
  } catch (validationErr) {
32136
32139
  const message = validationErr instanceof Error ? validationErr.message : String(validationErr);
32137
32140
  return err({ type: "invalid", message });
32138
32141
  }
32139
32142
  }
32143
+ function migrateLegacyAgentName(config) {
32144
+ if (typeof config !== "object" || config === null) {
32145
+ return config;
32146
+ }
32147
+ const migrated = { ...config };
32148
+ for (const harness of Harness) {
32149
+ const section = migrated[harness];
32150
+ if (typeof section !== "object" || section === null || !Array.isArray(section.agents)) {
32151
+ continue;
32152
+ }
32153
+ const agents = section.agents;
32154
+ migrated[harness] = {
32155
+ ...section,
32156
+ agents: agents.map((agent) => {
32157
+ if (typeof agent !== "object" || agent === null) {
32158
+ return agent;
32159
+ }
32160
+ const entry = agent;
32161
+ return {
32162
+ ...entry,
32163
+ template: entry.template === LEGACY_AGENT_NAME ? "sentinel" : entry.template,
32164
+ name: entry.name === LEGACY_AGENT_NAME ? "sentinel" : entry.name
32165
+ };
32166
+ })
32167
+ };
32168
+ }
32169
+ return migrated;
32170
+ }
32140
32171
  function isOldFlatConfig(config) {
32141
32172
  if (typeof config !== "object" || config === null) {
32142
32173
  return false;
32143
32174
  }
32144
32175
  const record = config;
32145
- return typeof record.harness === "string" && record.claude == null && record.codex == null && record.opencode == null;
32176
+ return typeof record.harness === "string" && Harness.every((harness) => record[harness] == null);
32146
32177
  }
32147
32178
  function writeConfig(config, path2 = CONFIG_PATH) {
32148
32179
  const dir = dirname(path2);
@@ -32153,7 +32184,7 @@ function writeConfig(config, path2 = CONFIG_PATH) {
32153
32184
  `);
32154
32185
  }
32155
32186
  function getConfiguredHarnesses(config) {
32156
- return HARNESS_NAMES.filter((harness) => config[harness] !== undefined);
32187
+ return Harness.filter((harness) => config[harness] !== undefined);
32157
32188
  }
32158
32189
  function removeConfigDir(path2 = CONFIG_PATH) {
32159
32190
  const dir = dirname(path2);
@@ -32292,7 +32323,7 @@ async function init(options2) {
32292
32323
  }
32293
32324
  let harness;
32294
32325
  if (harnessOption) {
32295
- if (!HARNESS_NAMES.includes(harnessOption)) {
32326
+ if (!Harness.includes(harnessOption)) {
32296
32327
  throw new InvalidHarnessError(harnessOption);
32297
32328
  }
32298
32329
  harness = harnessOption;
@@ -32302,7 +32333,7 @@ async function init(options2) {
32302
32333
  type: "list",
32303
32334
  name: "harness",
32304
32335
  message: "Which harness are you using?",
32305
- choices: HARNESS_NAMES
32336
+ choices: Harness
32306
32337
  }
32307
32338
  ]);
32308
32339
  harness = answer.harness;
@@ -32348,7 +32379,7 @@ Files to write:`);
32348
32379
  Atelier initialized for ${harness}.`);
32349
32380
  console.log(`
32350
32381
  Next step:`);
32351
- if (harness === "opencode" && section.provider === "openai") {
32382
+ if (harness === "opencode" && "provider" in section && section.provider === "openai") {
32352
32383
  console.log(" opencode auth login --provider openai # connect your OpenAI account");
32353
32384
  }
32354
32385
  console.log(" npx skills add martinffx/atelier # install skills");
@@ -32361,7 +32392,7 @@ import { homedir as homedir4 } from "os";
32361
32392
  // src/commands/utils.ts
32362
32393
  async function resolveHarness(config, harnessOption, command) {
32363
32394
  if (harnessOption) {
32364
- if (!HARNESS_NAMES.includes(harnessOption)) {
32395
+ if (!Harness.includes(harnessOption)) {
32365
32396
  throw new InvalidHarnessError(harnessOption);
32366
32397
  }
32367
32398
  const configured2 = getConfiguredHarnesses(config);
@@ -32493,6 +32524,9 @@ var SimpleConfigSchema = exports_external.object({
32493
32524
  default_model: exports_external.string().min(1),
32494
32525
  agents: exports_external.array(AgentSchema).min(1)
32495
32526
  });
32527
+ var CursorConfigSchema = exports_external.object({
32528
+ agents: exports_external.array(AgentSchema).min(1)
32529
+ }).strict();
32496
32530
  var OPENCODE_PROVIDERS = ["opencode-zen", "opencode-go", "amazon-bedrock", "openai"];
32497
32531
  var OpenCodeConfigSchema = exports_external.object({
32498
32532
  provider: exports_external.enum(OPENCODE_PROVIDERS),
@@ -32505,7 +32539,7 @@ var OpenCodeConfigSchema = exports_external.object({
32505
32539
  var ANTHROPIC_MODELS = ["haiku", "sonnet", "opus", "opusplan"];
32506
32540
  var DEFAULT_MODELS = {
32507
32541
  default_model: "opusplan",
32508
- recon: "haiku",
32542
+ sentinel: "haiku",
32509
32543
  oracle: "opus",
32510
32544
  architect: "opus"
32511
32545
  };
@@ -32545,6 +32579,7 @@ function installAgents(section, basePath) {
32545
32579
  } catch (err2) {
32546
32580
  throw new FileWriteError(agentsDir, err2 instanceof Error ? err2.message : String(err2));
32547
32581
  }
32582
+ rmSync2(join7(agentsDir, `${LEGACY_AGENT_NAME}.md`), { force: true });
32548
32583
  for (const agent of config.agents) {
32549
32584
  const template = readTemplate(agent.template);
32550
32585
  const frontmatter = `---
@@ -32599,6 +32634,7 @@ function remove2(section, basePath) {
32599
32634
  rmSync2(file, { force: true });
32600
32635
  }
32601
32636
  }
32637
+ rmSync2(join7(agentsDir, `${LEGACY_AGENT_NAME}.md`), { force: true });
32602
32638
  removeDirIfEmpty(agentsDir);
32603
32639
  removeAtelierSettings(claudeDir);
32604
32640
  }
@@ -32717,28 +32753,28 @@ var PROVIDER_MODELS = {
32717
32753
  };
32718
32754
  var DEFAULT_MODELS2 = {
32719
32755
  "opencode-zen": {
32720
- recon: "opencode/minimax-m2.7",
32756
+ sentinel: "opencode/minimax-m2.7",
32721
32757
  oracle: "opencode/kimi-k2.6",
32722
32758
  architect: "opencode/deepseek-v4-pro",
32723
32759
  build: "opencode/deepseek-v4-flash",
32724
32760
  plan: "opencode/deepseek-v4-pro"
32725
32761
  },
32726
32762
  "opencode-go": {
32727
- recon: "opencode-go/minimax-m2.7",
32763
+ sentinel: "opencode-go/minimax-m2.7",
32728
32764
  oracle: "opencode-go/kimi-k2.6",
32729
32765
  architect: "opencode-go/deepseek-v4-pro",
32730
32766
  build: "opencode-go/deepseek-v4-flash",
32731
32767
  plan: "opencode-go/deepseek-v4-pro"
32732
32768
  },
32733
32769
  "amazon-bedrock": {
32734
- recon: "amazon-bedrock/anthropic-claude-haiku-4-5",
32770
+ sentinel: "amazon-bedrock/anthropic-claude-haiku-4-5",
32735
32771
  oracle: "amazon-bedrock/anthropic-claude-opus-4-7",
32736
32772
  architect: "amazon-bedrock/anthropic-claude-opus-4-7",
32737
32773
  build: "amazon-bedrock/anthropic-claude-sonnet-4-5",
32738
32774
  plan: "amazon-bedrock/anthropic-claude-haiku-4-5"
32739
32775
  },
32740
32776
  openai: {
32741
- recon: "openai/gpt-5.6-luna",
32777
+ sentinel: "openai/gpt-5.6-luna",
32742
32778
  oracle: "openai/gpt-5.6-sol",
32743
32779
  architect: "openai/gpt-5.6-sol",
32744
32780
  build: "openai/gpt-5.6-terra",
@@ -32790,6 +32826,7 @@ function installAgents2(section, basePath) {
32790
32826
  } catch (err2) {
32791
32827
  throw new FileWriteError(agentsDir, err2 instanceof Error ? err2.message : String(err2));
32792
32828
  }
32829
+ rmSync3(join8(agentsDir, `${LEGACY_AGENT_NAME}.md`), { force: true });
32793
32830
  for (const agent of config.agents) {
32794
32831
  const template = readTemplate(agent.template);
32795
32832
  const frontmatter = `---
@@ -32816,13 +32853,13 @@ function mergeHarnessConfig2(section, basePath) {
32816
32853
  } catch (err2) {
32817
32854
  throw new FileWriteError(basePath, err2 instanceof Error ? err2.message : String(err2));
32818
32855
  }
32819
- const recon = config.agents.find((a) => a.name === "recon");
32856
+ const sentinel = config.agents.find((a) => a.name === "sentinel");
32820
32857
  const architect = config.agents.find((a) => a.name === "architect");
32821
32858
  const atelierFields = {
32822
32859
  agent: {
32823
32860
  build: {
32824
32861
  mode: "primary",
32825
- model: config.build_model || recon?.model || DEFAULT_MODELS2[config.provider].build
32862
+ model: config.build_model || sentinel?.model || DEFAULT_MODELS2[config.provider].build
32826
32863
  },
32827
32864
  plan: {
32828
32865
  mode: "primary",
@@ -32874,6 +32911,7 @@ function removeAgentFiles(opencodeRoot, config) {
32874
32911
  rmSync3(file, { force: true });
32875
32912
  }
32876
32913
  }
32914
+ rmSync3(join8(agentsDir, `${LEGACY_AGENT_NAME}.md`), { force: true });
32877
32915
  removeDirIfEmpty2(agentsDir);
32878
32916
  }
32879
32917
  function removeDirIfEmpty2(dir) {
@@ -34045,7 +34083,7 @@ var OPENAI_MODELS = [
34045
34083
  ];
34046
34084
  var DEFAULT_MODELS3 = {
34047
34085
  default_model: "gpt-5.6-terra",
34048
- recon: "gpt-5.6-luna",
34086
+ sentinel: "gpt-5.6-luna",
34049
34087
  oracle: "gpt-5.6-sol",
34050
34088
  architect: "gpt-5.6-sol"
34051
34089
  };
@@ -34098,6 +34136,7 @@ function installAgents3(section, basePath) {
34098
34136
  } catch (err2) {
34099
34137
  throw new FileWriteError(agentsDir, err2 instanceof Error ? err2.message : String(err2));
34100
34138
  }
34139
+ rmSync4(join9(agentsDir, `${LEGACY_AGENT_NAME}.toml`), { force: true });
34101
34140
  for (const agent of config.agents) {
34102
34141
  const template = readTemplate(agent.template);
34103
34142
  const content = {
@@ -34167,6 +34206,7 @@ function remove4(section, basePath) {
34167
34206
  rmSync4(file, { force: true });
34168
34207
  }
34169
34208
  }
34209
+ rmSync4(join9(agentsDir, `${LEGACY_AGENT_NAME}.toml`), { force: true });
34170
34210
  removeDirIfEmpty3(agentsDir);
34171
34211
  cleanCodexConfig(codexDir);
34172
34212
  removeEmptyCodexDir(codexDir);
@@ -34246,22 +34286,123 @@ function isObject(value) {
34246
34286
  return typeof value === "object" && value !== null && !Array.isArray(value);
34247
34287
  }
34248
34288
 
34289
+ // src/adapters/cursor.ts
34290
+ import { existsSync as existsSync6, mkdirSync as mkdirSync5, readdirSync as readdirSync4, rmSync as rmSync5, rmdirSync as rmdirSync4, writeFileSync as writeFileSync6 } from "fs";
34291
+ import { join as join10 } from "path";
34292
+ var CURSOR_MODELS = [
34293
+ "composer-2.5",
34294
+ "cursor-grok-4.5-high",
34295
+ "gpt-5.6-luna-medium",
34296
+ "gpt-5.6-terra-medium",
34297
+ "gpt-5.6-sol-medium",
34298
+ "claude-opus-4-8-high",
34299
+ "claude-sonnet-5-high",
34300
+ "kimi-k2.7-code",
34301
+ "glm-5.2-high"
34302
+ ];
34303
+ var DEFAULT_MODELS4 = {
34304
+ sentinel: "composer-2.5",
34305
+ oracle: "claude-opus-4-8-high",
34306
+ architect: "gpt-5.6-sol-medium"
34307
+ };
34308
+ var cursorAdapter = {
34309
+ name: "cursor",
34310
+ configSchema: CursorConfigSchema,
34311
+ defaultSection: defaultSection4,
34312
+ modelsForProvider: modelsForProvider4,
34313
+ promptSection: promptSection4,
34314
+ installAgents: installAgents4,
34315
+ mergeHarnessConfig: mergeHarnessConfig4,
34316
+ fileList: fileList4,
34317
+ remove: remove5
34318
+ };
34319
+ function defaultSection4() {
34320
+ return {
34321
+ agents: AGENT_NAMES.map((name) => ({ template: name, name, model: DEFAULT_MODELS4[name] }))
34322
+ };
34323
+ }
34324
+ function modelsForProvider4(_provider) {
34325
+ return CURSOR_MODELS;
34326
+ }
34327
+ async function promptSection4(prompt2, section) {
34328
+ const config = section;
34329
+ const answers = await prompt2.prompt(AGENT_NAMES.map((name) => ({
34330
+ type: "list",
34331
+ name,
34332
+ message: `Select model for ${name}`,
34333
+ choices: CURSOR_MODELS,
34334
+ default: config.agents.find((agent) => agent.name === name)?.model ?? DEFAULT_MODELS4[name]
34335
+ })));
34336
+ return {
34337
+ agents: AGENT_NAMES.map((name) => ({
34338
+ template: name,
34339
+ name,
34340
+ model: answers[name] ?? DEFAULT_MODELS4[name]
34341
+ }))
34342
+ };
34343
+ }
34344
+ function installAgents4(section, basePath) {
34345
+ const config = section;
34346
+ const agentsDir = join10(basePath, ".cursor", "agents");
34347
+ try {
34348
+ mkdirSync5(agentsDir, { recursive: true });
34349
+ } catch (err2) {
34350
+ throw new FileWriteError(agentsDir, err2 instanceof Error ? err2.message : String(err2));
34351
+ }
34352
+ rmSync5(join10(agentsDir, `${LEGACY_AGENT_NAME}.md`), { force: true });
34353
+ for (const agent of config.agents) {
34354
+ const template = readTemplate(agent.template);
34355
+ const content = `---
34356
+ name: ${agent.name}
34357
+ description: ${template.description}
34358
+ model: ${agent.model}
34359
+ ---
34360
+ ${template.body}`;
34361
+ const agentPath = join10(agentsDir, `${agent.name}.md`);
34362
+ writeFileSync6(agentPath, content);
34363
+ console.log(`Created ${shortPath(agentPath)}`);
34364
+ }
34365
+ }
34366
+ function mergeHarnessConfig4(_section, _basePath) {}
34367
+ function fileList4(basePath) {
34368
+ return AGENT_NAMES.map((name) => {
34369
+ const path2 = join10(basePath, ".cursor", "agents", `${name}.md`);
34370
+ return { path: path2, exists: existsSync6(path2) };
34371
+ });
34372
+ }
34373
+ function remove5(section, basePath) {
34374
+ const config = section;
34375
+ const agentsDir = join10(basePath, ".cursor", "agents");
34376
+ try {
34377
+ for (const agent of config.agents) {
34378
+ rmSync5(join10(agentsDir, `${agent.name}.md`), { force: true });
34379
+ }
34380
+ rmSync5(join10(agentsDir, `${LEGACY_AGENT_NAME}.md`), { force: true });
34381
+ if (existsSync6(agentsDir) && readdirSync4(agentsDir).length === 0) {
34382
+ rmdirSync4(agentsDir);
34383
+ }
34384
+ } catch (err2) {
34385
+ throw new FileWriteError(agentsDir, err2 instanceof Error ? err2.message : String(err2));
34386
+ }
34387
+ }
34388
+
34249
34389
  // src/adapters/index.ts
34250
34390
  registerAdapter(claudeAdapter);
34251
34391
  registerAdapter(opencodeAdapter);
34252
34392
  registerAdapter(codexAdapter);
34393
+ registerAdapter(cursorAdapter);
34253
34394
 
34254
34395
  // src/atelier.ts
34255
- var harnessChoices = HARNESS_NAMES.join(", ");
34396
+ var harnessChoices2 = Harness.join(", ");
34256
34397
  var program2 = new Command;
34257
- program2.name("atelier").description("Atelier CLI - configure Claude Code, OpenCode, and Codex for spec-driven development").version("0.1.0");
34258
- program2.command("init", { isDefault: true }).description("Initialize atelier globally").option(`--harness <type>`, `Harness type (${harnessChoices})`).option("--yes", "Non-interactive mode with defaults").action((options2) => {
34398
+ program2.name("atelier").description("Atelier CLI - configure Claude Code, OpenCode, Codex, and Cursor for spec-driven development").version("0.1.0");
34399
+ program2.command("init", { isDefault: true }).description("Initialize atelier globally").option(`--harness <type>`, `Harness type (${harnessChoices2})`).option("--yes", "Non-interactive mode with defaults").action((options2) => {
34259
34400
  init(options2).catch(handleError);
34260
34401
  });
34261
- program2.command("update").description("Update atelier agents").option(`--harness <type>`, `Harness type (${harnessChoices})`).action((options2) => {
34402
+ program2.command("update").description("Update atelier agents").option(`--harness <type>`, `Harness type (${harnessChoices2})`).action((options2) => {
34262
34403
  update(options2).catch(handleError);
34263
34404
  });
34264
- program2.command("remove").description("Remove a configured harness from atelier").option(`--harness <type>`, `Harness type (${harnessChoices})`).action((options2) => {
34405
+ program2.command("remove").description("Remove a configured harness from atelier").option(`--harness <type>`, `Harness type (${harnessChoices2})`).action((options2) => {
34265
34406
  remove(options2).catch(handleError);
34266
34407
  });
34267
34408
  program2.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@martinffx/atelier",
3
- "version": "1.4.0",
3
+ "version": "2.0.0",
4
4
  "description": "Personal development toolkit - spec-driven development, code quality, deep thinking, and ecosystem patterns",
5
5
  "type": "module",
6
6
  "bin": {
@@ -12,6 +12,7 @@
12
12
  "claude-code",
13
13
  "opencode",
14
14
  "codex",
15
+ "cursor",
15
16
  "ai-agents",
16
17
  "spec-driven-development"
17
18
  ],
@@ -34,7 +34,7 @@ Use these concrete harness subagent types. If an exact match is unavailable, use
34
34
 
35
35
  | `subagent_type` | Purpose |
36
36
  |-----------------|---------|
37
- | `recon` | Triage only: changed-file analysis, context retrieval, reviewer selection |
37
+ | `sentinel` | Triage only: changed-file analysis, context retrieval, reviewer selection |
38
38
  | `oracle` | Parallel reviewer personas, evidence-based critique, failure-mode analysis, challenge validation |
39
39
  | `architect` | Architecture, design-boundary, data-model, and API-contract review |
40
40
 
@@ -67,7 +67,7 @@ Follows [code-subagents](../code-subagents/SKILL.md) patterns:
67
67
 
68
68
  | Agent | Used In Step |
69
69
  |-------|--------------|
70
- | `recon` | Triage only (context retrieval, file analysis) |
70
+ | `sentinel` | Triage only (context retrieval, file analysis) |
71
71
  | `oracle` | Reviewers and challenge validation |
72
72
  | `architect` | Architect (architecture review) |
73
73
 
@@ -34,12 +34,12 @@ Capture the list of changed files and the full diff.
34
34
 
35
35
  **Purpose:** Analyze diff to determine context, select reviewers, identify relevant skills to look for.
36
36
 
37
- **Uses:** `recon` agent.
37
+ **Uses:** `sentinel` agent.
38
38
 
39
39
  ### Subagent Invocation
40
40
 
41
41
  ```yaml
42
- subagent_type: recon
42
+ subagent_type: sentinel
43
43
  description: "Triage diff for code review"
44
44
  prompt: |
45
45
  Analyze this code diff to determine review needs.
@@ -364,7 +364,7 @@ Display findings in terminal per [output.md](./output.md).
364
364
  | Step | Subagent | Uses | Parallel? | Purpose |
365
365
  |------|----------|------|----------|---------|
366
366
  | 1 | Get Diff | inline | — | `git diff <branch>` |
367
- | 2 | Triage | `recon` agent | No | Detect context, select reviewers, identify relevant skills to look for |
367
+ | 2 | Triage | `sentinel` agent | No | Detect context, select reviewers, identify relevant skills to look for |
368
368
  | 3 | Reviewers | `oracle` agent | Yes (per reviewer) | Specialty analysis |
369
369
  | 4 | Synthesis | inline | No | Deduplicate and group |
370
370
  | 5 | Architect | `architect` agent | No | Architecture review |
@@ -1,25 +1,23 @@
1
1
  ---
2
2
  name: code-subagents
3
3
  description: >
4
- Subagent dispatch patterns for implementation tasks. Use when spec-implement has multiple
5
- tasks to execute and subagents are available. Covers parallel dispatch for independent work,
6
- the two-stage review cycle (spec compliance then code quality), focused prompt construction,
7
- and integration of results. Trigger when executing plan tasks with subagent support, when
8
- facing 2+ independent problems, or when the user asks to use subagents for implementation.
4
+ Implementation subagent dispatch patterns. Use when independent implementation work is
5
+ available and subagents can execute it. Covers parallel dispatch, shared-tree patch
6
+ snapshots, one combined review per completed batch, and serial integration.
9
7
  user-invocable: false
10
8
  ---
11
9
 
12
- # Spec Subagents
10
+ # Implementation Subagents
13
11
 
14
- Fresh subagent per task. Two-stage review after each. Parallel when independent, sequential
15
- when dependent.
12
+ Fresh subagent per task. One combined review per completed batch. Parallel when independent,
13
+ sequential when dependent.
16
14
 
17
15
  ## When to Use Subagents
18
16
 
19
17
  **Use when:**
20
- - Executing tasks from plan.json with subagent support available
21
- - 2+ independent tasks that don't share state or files
22
- - Each problem can be understood without context from others
18
+ - 2+ independent work items do not share state or files
19
+ - Each work item has explicit requirements, constraints, files, and validation
20
+ - Each problem can be understood without context from the other work items
23
21
 
24
22
  **Don't use when:**
25
23
  - Tasks are tightly coupled (editing the same files)
@@ -53,6 +51,13 @@ Task C (notification tests) ──→ review → complete
53
51
  **Independence check:** Would fixing Task A affect Task B? Would they edit the same files?
54
52
  If no to both, dispatch in parallel.
55
53
 
54
+ For shared-tree parallel work:
55
+
56
+ 1. Assign each task an exclusive file list before dispatch
57
+ 2. Do not let implementers stage or commit changes
58
+ 3. Capture a path-scoped `git diff` for each task when it reports completion
59
+ 4. Run tasks sequentially if their file ownership overlaps or cannot be isolated
60
+
56
61
  ---
57
62
 
58
63
  ## Prompt Templates
@@ -60,15 +65,14 @@ If no to both, dispatch in parallel.
60
65
  Use these templates when dispatching subagents. Each template is battle-tested — don't
61
66
  improvise, use them as-is and fill in the variables.
62
67
 
63
- - **[references/implementer-prompt.md](references/implementer-prompt.md)** — Dispatch an implementer. Includes self-review checklist.
64
- - **[references/spec-reviewer-prompt.md](references/spec-reviewer-prompt.md)** — Spec compliance review. "Do not trust the report."
65
- - **[references/code-quality-reviewer-prompt.md](references/code-quality-reviewer-prompt.md)** — Code quality review. Critical/Important/Minor severity.
68
+ - **[references/implementor-prompt.md](references/implementor-prompt.md)** — Dispatch an implementer. Includes self-review checklist.
69
+ - **[references/batch-reviewer-prompt.md](references/batch-reviewer-prompt.md)** — Combined plan and code-quality review for one completed batch.
66
70
 
67
71
  ### Prompt quality rules
68
72
 
69
73
  - **Focused** — one task, one problem domain
70
- - **Self-contained** — all context needed is in the prompt. Don't make the subagent
71
- read the plan file; provide the full task text
74
+ - **Self-contained** — all context needed is in the prompt. Provide the complete work-item
75
+ requirements; do not make the subagent recover context
72
76
  - **Specific about files** — exact paths, not "the relevant files"
73
77
  - **Specific about output** — what should the subagent return?
74
78
  - **Constrained** — what should they NOT touch?
@@ -84,63 +88,30 @@ improvise, use them as-is and fill in the variables.
84
88
 
85
89
  ---
86
90
 
87
- ## Two-Stage Review
88
-
89
- Every completed task gets two reviews in order. Do not skip either. Do not reverse the order.
90
-
91
- ### Stage 1: Spec Compliance
92
-
93
- Does the implementation match what was specified?
91
+ ## Batch Review
94
92
 
95
- ```markdown
96
- ## Spec Review
93
+ Run one combined review after every completed batch, not separate reviews for each task.
97
94
 
98
- Review the implementation against the task specification:
99
-
100
- **Task spec:** [paste task from plan.json]
101
-
102
- **Files changed:** [list from subagent output]
103
-
104
- Check:
105
- 1. Are all requirements from the task spec implemented?
106
- 2. Is anything implemented that wasn't specified? (over-building)
107
- 3. Do tests cover the specified acceptance criteria?
108
- 4. Does the implementation match the design in design.md?
109
-
110
- Report: List any gaps or extras. Mark ✅ if compliant, ❌ if not.
111
- ```
95
+ Give one fresh reviewer:
112
96
 
113
- If the spec reviewer finds issues → the implementer subagent fixes them → spec reviewer
114
- reviews again. Repeat until ✅.
97
+ - The complete requirements for work items in the batch
98
+ - The relevant constraints
99
+ - The path-scoped patch captured for each task
100
+ - The implementers' reports and validation results
115
101
 
116
- ### Stage 2: Code Quality
102
+ The reviewer checks both requirements compliance and code quality:
117
103
 
118
- Is the implementation well-built?
104
+ 1. Every requirement and acceptance criterion is implemented
105
+ 2. The batch follows the supplied constraints
106
+ 3. No unrequested work or out-of-scope files are included
107
+ 4. Tests are meaningful and cover the right boundaries
108
+ 5. The code follows existing patterns without unnecessary complexity
119
109
 
120
- ```markdown
121
- ## Code Quality Review
110
+ Use [references/batch-reviewer-prompt.md](references/batch-reviewer-prompt.md) as written.
122
111
 
123
- Review the implementation for code quality:
124
-
125
- **Files changed:** [list]
126
-
127
- Check:
128
- 1. Does the code follow existing patterns and conventions?
129
- 2. Are tests meaningful (not just asserting true)?
130
- 3. Is there unnecessary complexity?
131
- 4. Are edge cases handled?
132
- 5. Is the code clean (no dead code, no unnecessary comments)?
133
-
134
- Rate issues as Critical (blocks merge), Important (should fix), or Minor (nice to have).
135
- ```
136
-
137
- If the quality reviewer finds Critical or Important issues → implementer fixes → reviewer
138
- reviews again. Minor issues can be noted and moved past.
139
-
140
- ### Why this order matters
141
-
142
- Spec compliance first because there's no point polishing code that doesn't meet the spec.
143
- Quality second because compliant code still needs to be well-built.
112
+ If the reviewer finds Critical or Important issues, send each issue back to the relevant
113
+ implementer, refresh its path-scoped patch, and review the batch again. Minor issues may be
114
+ noted and moved past.
144
115
 
145
116
  ---
146
117
 
@@ -161,9 +132,11 @@ they're thinking rather than guessing.
161
132
  After subagents complete (especially parallel dispatch):
162
133
 
163
134
  1. **Read each summary** — understand what changed
164
- 2. **Check for conflicts** — did any agents edit the same code?
165
- 3. **Run full test suite** — verify all changes work together
166
- 4. **Update task tracking** — mark tasks complete: beads `bd close <id>`, or harness todo list
135
+ 2. **Capture task patches** — use each task's exclusive file list
136
+ 3. **Review the batch** — one combined requirements and quality review
137
+ 4. **Run full test suite** — verify all changes work together
138
+ 5. **Commit** — the coordinator commits the reviewed batch serially
139
+ 6. **Update progress tracking** — when the caller uses it
167
140
 
168
141
  If there are conflicts between parallel results, resolve them manually. Don't dispatch
169
142
  another subagent to merge — that requires too much context.
@@ -176,9 +149,5 @@ If a subagent fails a task:
176
149
 
177
150
  - **Don't fix it manually** — that pollutes your context
178
151
  - **Dispatch a fix subagent** with specific instructions about what went wrong
179
- - **If it fails twice**, stop and escalate to the human. The plan may need revision.
180
-
181
- If failure reveals a design problem:
182
-
183
- > "This task is failing because [reason]. The design in design.md may need to change.
184
- > Want me to go back to spec-brainstorm?"
152
+ - **If it fails twice**, stop and escalate to the human. The requirements or constraints may
153
+ need revision.
@@ -0,0 +1,44 @@
1
+ # Batch Reviewer Prompt Template
2
+
3
+ Use this template after all tasks in an implementation batch report completion. Review the
4
+ captured task patches, not a commit range.
5
+
6
+ ## Template
7
+
8
+ ```
9
+ You are reviewing one completed implementation batch for requirements compliance and code quality.
10
+
11
+ ## Batch Requirements
12
+
13
+ {BATCH_REQUIREMENTS}
14
+
15
+ ## Constraints
16
+
17
+ {CONSTRAINTS}
18
+
19
+ ## Task Patches
20
+
21
+ {BATCH_PATCHES}
22
+
23
+ ## Implementer Reports and Validation
24
+
25
+ {IMPLEMENTER_REPORTS}
26
+
27
+ ## CRITICAL: Verify the Patches
28
+
29
+ Do not trust the implementer reports. Review the captured patches and relevant code directly.
30
+
31
+ Check:
32
+ 1. Every requirement and acceptance criterion is implemented
33
+ 2. The implementation follows the supplied constraints
34
+ 3. No unrequested work or out-of-scope files are included
35
+ 4. Tests are meaningful and cover the right boundaries
36
+ 5. The code follows existing patterns without unnecessary complexity
37
+ 6. Error cases and edge conditions are handled
38
+
39
+ ## Report
40
+
41
+ - **Strengths:** What was done well
42
+ - **Issues:** Critical, Important, or Minor findings with file:line references and fixes
43
+ - **Assessment:** Approved, Approved with minor issues, or Changes requested
44
+ ```