@martinffx/atelier 1.4.0 → 3.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.
Files changed (93) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +95 -220
  3. package/agents/architect.md +6 -6
  4. package/agents/oracle.md +1 -1
  5. package/agents/{recon.md → sentinel.md} +3 -3
  6. package/dist/atelier.js +167 -26
  7. package/package.json +2 -1
  8. package/skills/atelier-orchestrator/SKILL.md +180 -0
  9. package/skills/atelier-setup/SKILL.md +80 -0
  10. package/skills/code-review/SKILL.md +2 -2
  11. package/skills/code-review/references/reviewers.md +3 -3
  12. package/skills/code-review/references/rq.md +9 -9
  13. package/skills/code-subagents/SKILL.md +44 -75
  14. package/skills/code-subagents/references/batch-reviewer-prompt.md +44 -0
  15. package/skills/code-subagents/references/implementor-prompt.md +10 -11
  16. package/skills/spec-brainstorm/SKILL.md +21 -16
  17. package/skills/spec-finish/SKILL.md +14 -14
  18. package/skills/spec-implement/SKILL.md +42 -42
  19. package/skills/spec-plan/SKILL.md +72 -26
  20. package/skills/spec-plan/references/plan_template.md +77 -0
  21. package/skills/code-subagents/references/code-quality-reviewer-prompt.md +0 -48
  22. package/skills/code-subagents/references/spec-reviewer-prompt.md +0 -62
  23. package/skills/python-architecture/SKILL.md +0 -148
  24. package/skills/python-architecture/references/data-modeling.md +0 -558
  25. package/skills/python-architecture/references/ddd.md +0 -569
  26. package/skills/python-architecture/references/functional-core.md +0 -337
  27. package/skills/python-build-tools/SKILL.md +0 -153
  28. package/skills/python-build-tools/references/basedpyright.md +0 -321
  29. package/skills/python-build-tools/references/ruff.md +0 -225
  30. package/skills/python-build-tools/references/uv.md +0 -257
  31. package/skills/python-fastapi/SKILL.md +0 -184
  32. package/skills/python-fastapi/references/api-design.md +0 -563
  33. package/skills/python-fastapi/references/dependencies.md +0 -479
  34. package/skills/python-fastapi/references/middleware.md +0 -475
  35. package/skills/python-fastapi/references/validation.md +0 -497
  36. package/skills/python-modern-python/SKILL.md +0 -201
  37. package/skills/python-modern-python/references/async.md +0 -76
  38. package/skills/python-modern-python/references/pattern-matching.md +0 -89
  39. package/skills/python-modern-python/references/typing.md +0 -96
  40. package/skills/python-monorepo/SKILL.md +0 -146
  41. package/skills/python-monorepo/references/docker.md +0 -515
  42. package/skills/python-monorepo/references/namespace-packages.md +0 -426
  43. package/skills/python-monorepo/references/workspace-config.md +0 -341
  44. package/skills/python-sqlalchemy/SKILL.md +0 -119
  45. package/skills/python-sqlalchemy/references/async.md +0 -51
  46. package/skills/python-sqlalchemy/references/models.md +0 -67
  47. package/skills/python-sqlalchemy/references/queries.md +0 -57
  48. package/skills/python-temporal/SKILL.md +0 -128
  49. package/skills/python-temporal/references/patterns.md +0 -87
  50. package/skills/python-temporal/references/testing.md +0 -54
  51. package/skills/python-testing/SKILL.md +0 -161
  52. package/skills/python-testing/references/boundaries.md +0 -449
  53. package/skills/python-testing/references/mocking.md +0 -449
  54. package/skills/python-testing/references/pytest.md +0 -524
  55. package/skills/spec-orchestrator/SKILL.md +0 -145
  56. package/skills/typescript-api-design/SKILL.md +0 -396
  57. package/skills/typescript-api-design/references/error-responses.md +0 -469
  58. package/skills/typescript-build-tools/SKILL.md +0 -447
  59. package/skills/typescript-build-tools/references/biome.md +0 -436
  60. package/skills/typescript-build-tools/references/bun.md +0 -432
  61. package/skills/typescript-build-tools/references/turborepo.md +0 -426
  62. package/skills/typescript-build-tools/references/vitest.md +0 -518
  63. package/skills/typescript-drizzle-orm/SKILL.md +0 -398
  64. package/skills/typescript-drizzle-orm/references/cloudflare.md +0 -392
  65. package/skills/typescript-drizzle-orm/references/entity-pattern.md +0 -412
  66. package/skills/typescript-drizzle-orm/references/postgresql.md +0 -191
  67. package/skills/typescript-drizzle-orm/references/repository-pattern.md +0 -479
  68. package/skills/typescript-drizzle-orm/references/sqlite.md +0 -291
  69. package/skills/typescript-dynamodb-toolbox/SKILL.md +0 -370
  70. package/skills/typescript-dynamodb-toolbox/references/entity-layer.md +0 -574
  71. package/skills/typescript-dynamodb-toolbox/references/error-handling.md +0 -495
  72. package/skills/typescript-dynamodb-toolbox/references/modeling.md +0 -332
  73. package/skills/typescript-dynamodb-toolbox/references/repository-layer.md +0 -631
  74. package/skills/typescript-dynamodb-toolbox/references/testing.md +0 -718
  75. package/skills/typescript-dynamodb-toolbox/references/transactions.md +0 -423
  76. package/skills/typescript-effect-ts/SKILL.md +0 -341
  77. package/skills/typescript-effect-ts/references/core.md +0 -412
  78. package/skills/typescript-effect-ts/references/error-handling.md +0 -468
  79. package/skills/typescript-effect-ts/references/resources.md +0 -476
  80. package/skills/typescript-effect-ts/references/schema.md +0 -536
  81. package/skills/typescript-effect-ts/references/services.md +0 -461
  82. package/skills/typescript-fastify/SKILL.md +0 -405
  83. package/skills/typescript-fastify/references/plugins.md +0 -329
  84. package/skills/typescript-fastify/references/typeid.md +0 -315
  85. package/skills/typescript-functional-patterns/SKILL.md +0 -402
  86. package/skills/typescript-functional-patterns/references/adts.md +0 -497
  87. package/skills/typescript-functional-patterns/references/branded-types.md +0 -542
  88. package/skills/typescript-functional-patterns/references/migration-guide.md +0 -695
  89. package/skills/typescript-functional-patterns/references/option-result.md +0 -585
  90. package/skills/typescript-testing/SKILL.md +0 -353
  91. package/skills/typescript-testing/references/mocking.md +0 -675
  92. package/skills/typescript-testing/references/msw.md +0 -852
  93. package/skills/typescript-testing/references/snapshot-testing.md +0 -774
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": "3.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
  ],
@@ -0,0 +1,180 @@
1
+ ---
2
+ name: atelier-orchestrator
3
+ description: >
4
+ Skill routing and workflow orchestration. Selects Inline Plan or Spec-backed Plan, routes
5
+ to the correct workflow skill, and manages transitions between phases. Use when starting
6
+ any conversation or task to determine which planning mode and skill apply.
7
+ user-invocable: false
8
+ ---
9
+
10
+ <EXTREMELY-IMPORTANT>
11
+ If you think there is even a 1% chance a skill might apply to what you are doing, you ABSOLUTELY
12
+ MUST invoke the skill.
13
+
14
+ IF A SKILL APPLIES TO YOUR TASK, YOU DO NOT HAVE A CHOICE. YOU MUST USE IT.
15
+
16
+ This is not negotiable. This is not optional. You cannot rationalize your way out of this.
17
+ </EXTREMELY-IMPORTANT>
18
+
19
+ # Planning Workflow
20
+
21
+ You have skills. You MUST use them. Not "should." Not "when convenient." MUST.
22
+
23
+ Invoke relevant skills BEFORE any response or action. Even a 1% chance a skill might apply
24
+ means you invoke it. If an invoked skill turns out to be wrong for the situation, you don't
25
+ need to follow it. But you must check.
26
+
27
+ ## The One Rule
28
+
29
+ **When an implementation choice exists, never write code until the human has reviewed and
30
+ approved a written plan.** Exact mechanical changes may use the exception below.
31
+
32
+ The plan may be inline in the conversation or backed by persisted spec artifacts. Select
33
+ the mode before invoking an artifact-producing skill, state the choice with one brief
34
+ reason, and let the human override it.
35
+
36
+ ## Planning Modes
37
+
38
+ ### Inline Plan (default)
39
+
40
+ Use for bounded, well-understood work, including ordinary features, bug fixes, refactors,
41
+ configuration changes, and multi-file changes. Route to **spec-plan** with Inline mode
42
+ explicitly selected. It presents a concise plan in conversation, creates no planning artifacts
43
+ or tracker entries, and stops for approval. After approval, implement the plan directly; do
44
+ not invoke `spec-implement`, `spec-finish`, or `code-subagents`.
45
+
46
+ Direct Inline implementation must:
47
+
48
+ - Avoid main/master unless the human explicitly permits it
49
+ - Stay within the approved scope and files
50
+ - Run every validation item in the approved plan
51
+ - Review the final diff for unintended changes
52
+ - Do not commit, push, or open a PR without explicit human instruction
53
+
54
+ When in doubt, choose Inline Plan. File count and estimated duration alone do not make work
55
+ spec-worthy.
56
+
57
+ ### Spec-backed Plan
58
+
59
+ Use when at least one concrete signal exists:
60
+
61
+ - The human explicitly requests a spec or durable planning artifacts
62
+ - Requirements or boundaries need discovery before planning
63
+ - The work materially changes architecture, public contracts, data models, or cross-system behavior
64
+ - Multiple dependent subsystems need decomposition and dependency tracking
65
+ - The plan must survive the conversation for handoff, audit, or multi-person coordination
66
+
67
+ Route through **spec-brainstorm**. This mode produces:
68
+
69
+ ```
70
+ design.md ← spec-brainstorm (requirements + research + architecture)
71
+ plan.json ← spec-plan (tasks, dependencies)
72
+ ```
73
+
74
+ Do not infer substantial work from size alone. If no concrete signal applies, use Inline Plan.
75
+
76
+ ## Skill Routing
77
+
78
+ ```
79
+ atelier-orchestrator → Select and announce planning mode
80
+ spec-brainstorm → Spec-backed discovery + design → design.md
81
+ spec-plan → Inline Plan or Spec-backed Plan → approval
82
+ spec-implement → Execute approved Spec-backed Plans; track tasks
83
+ spec-finish → Post-implementation validation for Spec-backed Plans
84
+ code-subagents → Parallel dispatch for Spec-backed Plan tasks
85
+ ```
86
+
87
+ ### Ordinary bounded work
88
+
89
+ ```
90
+ spec-plan (Inline mode) → approval → implement directly
91
+ ```
92
+
93
+ ### Substantial work or explicit spec request
94
+
95
+ ```
96
+ spec-brainstorm → spec-plan (Spec-backed Plan) → approval → spec-implement → spec-finish
97
+ ```
98
+
99
+ ### Truly mechanical change
100
+
101
+ A typo or exact single-line replacement may skip planning when there is no implementation
102
+ choice to review. If any choice exists, use an Inline Plan.
103
+
104
+ ## Hard Transitions
105
+
106
+ | After completing... | Next step |
107
+ |---------------------|-----------|
108
+ | spec-brainstorm | spec-plan in Spec-backed mode |
109
+ | approved Inline Plan | implement the approved plan directly |
110
+ | approved Spec-backed Plan | spec-implement in Spec-backed mode |
111
+ | spec-implement | spec-finish |
112
+
113
+ Do not begin implementation without an approved written plan. Spec-backed work must not
114
+ jump from research to implementation.
115
+
116
+ ## Iteration Patterns
117
+
118
+ The workflow is not purely linear. Expect backflows:
119
+
120
+ ### Research → Research (discovery loop)
121
+ - Brainstorm reveals new requirements → loop back to discovery phase
122
+ - Human adds new scope mid-brainstorm → continue discovery
123
+
124
+ ### Plan → Research (design flaw)
125
+ - Planning reveals design assumptions are wrong → back to brainstorm
126
+ - Tasks can't be decomposed without more context → back to brainstorm
127
+
128
+ ### Implement → Plan (missing tasks)
129
+ - Implementation reveals missing work → revise the active plan and get approval
130
+ - Spec-backed work is blocked on an unplanned dependency → update plan.json
131
+
132
+ ### Implement → Research (fundamental issue)
133
+ - Inline planning or implementation develops substantial needs → ask the human whether to
134
+ switch to a Spec-backed Plan
135
+ - Implementation reveals spec-backed design is fundamentally wrong → back to brainstorm
136
+
137
+ ### Finish → Implement (bugs found)
138
+ - Validation finds bugs → back to implement
139
+ - Tests failing → back to implement
140
+
141
+ ### When to escalate
142
+ If you loop 2+ times on the same issue, stop and ask the human:
143
+
144
+ > "We've looped on [issue] twice. Should we reconsider the approach?"
145
+
146
+ ## Red Flags — You Are Rationalizing
147
+
148
+ | What you're thinking | Why it's wrong |
149
+ |----------------------|----------------|
150
+ | "This is too simple for a persisted spec" | Use an Inline Plan instead |
151
+ | "I already know how to do this" | Knowing how ≠ having the human's approval for how |
152
+ | "The human seems impatient" | Wasting time on wrong code is worse than planning |
153
+ | "I'll just do a quick prototype" | Prototypes become production. Plan it. |
154
+ | "I need to explore the code first" | Gather enough context for an Inline Plan; use brainstorm only when discovery is substantial |
155
+ | "Let me just fix this one thing" | One thing becomes three. Plan it. |
156
+ | "I can plan in my head" | Plans in your head can't be reviewed or annotated |
157
+ | "This is just a refactor" | Refactors still need at least an Inline Plan |
158
+ | "I'll write the plan after" | Post-hoc plans are fiction. Plan before. |
159
+ | "I need more context first" | Skills tell you HOW to gather context. Check first. |
160
+ | "The spec workflow is overkill" | It may be. Default to an Inline Plan unless substantial-work signals exist. |
161
+ | "I know what that skill says" | Skills evolve. Read current version. Invoke it. |
162
+ | "This feels productive" | Undisciplined action wastes time. Skills prevent this. |
163
+
164
+ ## Skill Types
165
+
166
+ **Process skills** (spec-brainstorm, spec-plan, spec-implement, spec-finish): Follow exactly.
167
+ Don't adapt away discipline.
168
+
169
+ **Knowledge skills** (oracle-grill-me, oracle-domain-modelling): Adapt principles to
170
+ context. These inform decisions within the workflow.
171
+
172
+ **Discipline skills** (oracle-debug): Strict methodology that must be followed
173
+ exactly — no adaptation that bypasses root-cause investigation.
174
+
175
+ Process skills come first. Knowledge skills get invoked by process skills when needed.
176
+
177
+ ## User Instructions
178
+
179
+ "Add X" or "Fix Y" doesn't mean skip workflows. Instructions say WHAT, not HOW.
180
+ The skills define HOW.
@@ -0,0 +1,80 @@
1
+ ---
2
+ name: atelier-setup
3
+ description: Configure a repository's generic agent guidance for Atelier's development workflow. Use only when the user explicitly invokes atelier-setup; it inspects existing repository instructions and domain-document conventions, previews an idempotent project-guidance update, and writes only after approval. It does not install Atelier, configure a harness, or scaffold empty workflow artifacts.
4
+ user-invocable: true
5
+ ---
6
+
7
+ # Atelier Setup
8
+
9
+ Set up generic repository guidance that Atelier skills need without taking ownership of the
10
+ developer's installation, harness configuration, or project structure. Explore first, present
11
+ the proposed edit exactly, and write only after the developer approves it.
12
+
13
+ ## 1. Explore
14
+
15
+ Read the repository before proposing any change:
16
+
17
+ - Root `AGENTS.md` and `CLAUDE.md`, if present. Note whether either already has an `## Agent skills`
18
+ heading.
19
+ - Root `CONTEXT.md` and `CONTEXT-MAP.md`.
20
+ - `docs/adr/` and any context-local `docs/adr/` directories.
21
+ - Genuine monorepo signals: a workspace manifest, or multiple independently deployable packages
22
+ with their own source directories.
23
+
24
+ Do not create, install, configure, or modify anything during exploration.
25
+
26
+ ## 2. Present Findings
27
+
28
+ Summarize what exists and recommend a domain-document layout:
29
+
30
+ - **Single-context** is the default: domain language belongs in root `CONTEXT.md`; architectural
31
+ decisions belong in root `docs/adr/`.
32
+ - **Multi-context** is appropriate only when the repository has genuinely separate bounded
33
+ contexts. `CONTEXT-MAP.md` belongs at the root and points to each context's `CONTEXT.md` and
34
+ `docs/adr/` directory.
35
+
36
+ Explain that these documents remain lazy: do not create `CONTEXT.md`, `CONTEXT-MAP.md`, or an ADR
37
+ directory until another Atelier skill has resolved terminology or made a decision worth recording.
38
+
39
+ Select the instruction file to edit:
40
+
41
+ 1. If both files exist, ask which file should own the agent guidance; do not duplicate it.
42
+ 2. Otherwise use root `AGENTS.md` when it exists.
43
+ 3. Otherwise use root `CLAUDE.md` when it exists.
44
+ 4. If neither exists, ask which instruction file to create; do not choose on the developer's behalf.
45
+
46
+ Show the developer the selected file, domain layout, and the exact `## Agent skills` block that will be
47
+ written. Stop and wait for explicit approval.
48
+
49
+ ## 3. Write After Approval
50
+
51
+ Add the following block to the selected instruction file:
52
+
53
+ ```markdown
54
+ ## Agent skills
55
+
56
+ ### Planning and implementation
57
+
58
+ Use `atelier-orchestrator` at the start of development work. It selects an Inline Plan for bounded
59
+ changes or a Spec-backed Plan when durable design and coordination artifacts are warranted.
60
+
61
+ ### Domain documentation
62
+
63
+ Before working in a domain area, read root `CONTEXT-MAP.md` when present and follow it to the
64
+ relevant context documentation. Otherwise, read root `CONTEXT.md` when present. Read relevant
65
+ architectural decisions under `docs/adr/` and any context-specific ADR directories.
66
+
67
+ If these documents do not exist, proceed silently. Create or update them only when domain
68
+ terminology or an architectural decision has been resolved.
69
+ ```
70
+
71
+ If an `## Agent skills` section already exists, update the `### Planning and implementation` and
72
+ `### Domain documentation` subsections in place rather than appending duplicates. Preserve other
73
+ subsections and all content outside the section, including user edits. Do not create any other
74
+ files or directories.
75
+
76
+ ## 4. Report
77
+
78
+ State which instruction file changed and the chosen domain-document layout. Remind the developer
79
+ that the layout is a convention only: the first domain-modelling or architectural-decision task
80
+ creates the relevant documents when it has substantive content.
@@ -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