agentcohort 0.1.0 → 0.2.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 (35) hide show
  1. package/README.md +97 -19
  2. package/dist/args.d.ts +1 -0
  3. package/dist/args.js +9 -0
  4. package/dist/cli.js +45 -2
  5. package/dist/config.d.ts +32 -0
  6. package/dist/config.js +100 -0
  7. package/dist/configCmd.d.ts +27 -0
  8. package/dist/configCmd.js +54 -0
  9. package/dist/defaults.d.ts +21 -0
  10. package/dist/defaults.js +22 -0
  11. package/dist/diff.d.ts +24 -0
  12. package/dist/diff.js +64 -0
  13. package/dist/installer.d.ts +2 -0
  14. package/dist/installer.js +5 -1
  15. package/dist/promptModels.d.ts +13 -0
  16. package/dist/promptModels.js +66 -0
  17. package/dist/render.d.ts +11 -0
  18. package/dist/render.js +35 -0
  19. package/dist/templates/CLAUDE.section.md +19 -0
  20. package/dist/templates/agents/bug-fixer.md +14 -0
  21. package/dist/templates/agents/bug-hunter.md +14 -0
  22. package/dist/templates/agents/expert-council.md +14 -0
  23. package/dist/templates/agents/feature-implementer.md +14 -0
  24. package/dist/templates/agents/feature-planner.md +14 -0
  25. package/dist/templates/agents/final-reviewer.md +14 -0
  26. package/dist/templates/agents/perf-optimizer.md +14 -0
  27. package/dist/templates/agents/perf-reviewer.md +14 -0
  28. package/dist/templates/agents/performance-hunter.md +14 -0
  29. package/dist/templates/agents/regression-guard.md +14 -0
  30. package/dist/templates/agents/repo-scout.md +14 -0
  31. package/dist/templates/agents/reproduction-engineer.md +14 -0
  32. package/dist/templates/agents/root-cause-analyst.md +14 -0
  33. package/dist/templates/agents/solution-architect.md +14 -0
  34. package/dist/templates/agents/test-verifier.md +14 -0
  35. package/package.json +7 -3
package/README.md CHANGED
@@ -14,25 +14,27 @@ shipping.
14
14
 
15
15
  ## Install
16
16
 
17
+ `agentcohort` is a CLI — install it **globally**, once:
18
+
17
19
  ```bash
18
- npm i agentcohort
20
+ npm i -g agentcohort
19
21
  ```
20
22
 
21
- Or run it without installing:
23
+ Or run it without installing anything (per-project, ad-hoc):
22
24
 
23
25
  ```bash
24
26
  npx agentcohort init
25
27
  ```
26
28
 
27
- > The npm package is `agentcohort`; the CLI command it installs is
28
- > just `agentcohort`.
29
+ > The npm package is `agentcohort`; the CLI command it installs is also
30
+ > `agentcohort`.
29
31
 
30
32
  ## Quick start
31
33
 
32
- From the root of the project you want to equip:
33
-
34
34
  ```bash
35
- agentcohort init
35
+ npm i -g agentcohort # once, globally
36
+ cd path/to/your-project # any project you want to equip
37
+ agentcohort init # installs agents + commands + routing rules here
36
38
  ```
37
39
 
38
40
  Then open Claude Code in that project and run:
@@ -91,6 +93,20 @@ production-grade correctness, no shallow fixes, no fixing without evidence, and
91
93
  **a bug audit never fixes** — it produces a recommendation and stops at a human
92
94
  approval gate.
93
95
 
96
+ ### How agents respect your CLAUDE.md and skills
97
+
98
+ Every installed agent boots by reading your project's `CLAUDE.md`
99
+ content **outside** the `# Agentcohort Routing Rules` section and by
100
+ checking for installed skills that match the current task. The rules:
101
+
102
+ - Your project rules take precedence over an agent's default prompt.
103
+ - An agent invokes a matching skill instead of re-implementing it.
104
+ - Agentcohort's defaults apply only where your project is silent.
105
+
106
+ This means `agentcohort` slots into a project that already has its own
107
+ CLAUDE.md and skills (e.g. `superpowers`) — it does not override what
108
+ you've already set up.
109
+
94
110
  ## Using the workflow commands (inside Claude Code)
95
111
 
96
112
  | Command | Pipeline | Use it for |
@@ -111,6 +127,58 @@ approval gate.
111
127
  - **Sonnet** — implementation, testing, bug & performance hunting.
112
128
  - **Opus** — architecture, root-cause analysis, expert council, final review.
113
129
 
130
+ ## Customizing model strategy
131
+
132
+ `agentcohort init` will (interactively) prompt you to either use the
133
+ default Claude model IDs or pick your own for each tier. Your choice is
134
+ saved to `.agentcohort.json` at the project root and reused on later
135
+ runs.
136
+
137
+ To revisit your choice without re-installing everything, run:
138
+
139
+ ```bash
140
+ agentcohort config
141
+ ```
142
+
143
+ This re-prompts for the three tier model IDs, shows a diff of which
144
+ installed agents would change, and applies the changes with your
145
+ confirmation.
146
+
147
+ To force a re-prompt during install (instead of using the existing
148
+ `.agentcohort.json`), run:
149
+
150
+ ```bash
151
+ agentcohort init --reconfigure
152
+ ```
153
+
154
+ ### `.agentcohort.json` schema (v1)
155
+
156
+ ```json
157
+ {
158
+ "$schema": "https://raw.githubusercontent.com/Thiendekaco/agentcohort/main/schema/agentcohort-config-v1.json",
159
+ "version": 1,
160
+ "models": {
161
+ "premium": "claude-opus-4-7",
162
+ "mid": "claude-sonnet-4-6",
163
+ "cheap": "claude-haiku-4-5-20251001"
164
+ }
165
+ }
166
+ ```
167
+
168
+ - **premium** — architecture, root-cause analysis, expert council, final
169
+ review.
170
+ - **mid** — implementation, testing, bug & performance hunting.
171
+ - **cheap** — fast read-only repo scout.
172
+
173
+ Hand-editing one of the installed `.claude/agents/*.md` files to use a
174
+ specific model ID is respected: subsequent `agentcohort init` and
175
+ `agentcohort config` runs leave that hand-edit alone (the tool only
176
+ rewrites lines that are still tier aliases or match the previous
177
+ config's IDs).
178
+
179
+ Model IDs are not validated by the tool — if the ID is invalid, Claude
180
+ Code will fail at agent spawn time.
181
+
114
182
  ## Customizing agents
115
183
 
116
184
  The installed files are plain Markdown and **yours to edit**:
@@ -144,7 +212,8 @@ before changing them (or back them up with `--backup`).
144
212
  - **`--dry-run`** performs zero writes and zero backups.
145
213
  - Backups are written next to the original as
146
214
  `<file>.backup-YYYYMMDD-HHMMSS` and never overwrite an existing backup.
147
- - Cross-platform (Windows/macOS/Linux), zero runtime dependencies, no
215
+ - Cross-platform (Windows/macOS/Linux); a single runtime dependency
216
+ (`@inquirer/prompts` for the interactive model-tier prompt), no
148
217
  shell-specific behavior.
149
218
 
150
219
  ## Development
@@ -155,27 +224,36 @@ npm run build # tsc -> dist/, then copies templates
155
224
  npm test # vitest
156
225
  ```
157
226
 
158
- ## Releases
227
+ ## Branching & releases
228
+
229
+ Two long-lived branches:
230
+
231
+ - **`dev`** — integration / staging. All feature PRs target `dev`. Nothing
232
+ here publishes to npm; this is the place to bundle PRs together, run
233
+ manual smoke tests, and verify the release as a whole.
234
+ - **`main`** — production. Only ever updated by merging `dev` → `main`.
235
+ Every push to `main` triggers the [`Release`](.github/workflows/release.yml)
236
+ workflow.
159
237
 
160
- Publishing is automated. **The version in `package.json` is the version that
161
- gets published.** Every push to `main` runs the
162
- [`Release`](.github/workflows/release.yml) workflow, which:
238
+ The workflow does:
163
239
 
164
240
  1. installs, builds and runs the full test suite;
165
241
  2. publishes the **current** `package.json` version to npm —
166
242
  https://www.npmjs.com/package/agentcohort (so the very first
167
- release is exactly `0.1.0`, nothing skipped);
243
+ release was exactly `0.1.0`, nothing skipped);
168
244
  3. creates the annotated git tag `vX.Y.Z` on the published commit;
169
245
  4. bumps to the next dev version (`patch` by default) and pushes a
170
246
  `chore(release): published vX.Y.Z, open vX.Y.(Z+1) [skip ci]` commit back
171
247
  to `main`.
172
248
 
173
- So: to cut a normal release, just push to `main`. To release a `minor`/`major`
174
- instead, bump `package.json` yourself in a regular commit before pushing (or
175
- use the *Run workflow* button to control how the **next** pending version is
176
- opened). If the pending version is already on npm, publish is skipped and the
177
- job still succeeds (safe re-runs). The `[skip ci]` marker stops the release
178
- commit from re-triggering the workflow (no publish loop).
249
+ So the normal release cycle is: open PR → `dev` review & merge → smoke
250
+ test on `dev` open PR `dev` `main` merge → workflow publishes. To
251
+ ship a `minor`/`major` instead of `patch`, bump `package.json` yourself
252
+ in the PR before merging (or use the *Run workflow* button to control
253
+ how the **next** pending version is opened). If the pending version is
254
+ already on npm, publish is skipped and the job still succeeds (safe
255
+ re-runs). The `[skip ci]` marker stops the release commit from
256
+ re-triggering the workflow (no publish loop).
179
257
 
180
258
  **One-time setup:** add an npm **Automation** access token as the repository
181
259
  secret `NPM_TOKEN` (GitHub → Settings → Secrets and variables → Actions →
package/dist/args.d.ts CHANGED
@@ -4,6 +4,7 @@ export interface ParsedArgs {
4
4
  dryRun: boolean;
5
5
  force: boolean;
6
6
  backup: boolean;
7
+ reconfigure: boolean;
7
8
  help: boolean;
8
9
  version: boolean;
9
10
  unknown: string[];
package/dist/args.js CHANGED
@@ -9,6 +9,7 @@ const FLAGS = {
9
9
  '--dry-run': 'dryRun',
10
10
  '--force': 'force',
11
11
  '--backup': 'backup',
12
+ '--reconfigure': 'reconfigure',
12
13
  '--help': 'help',
13
14
  '-h': 'help',
14
15
  '--version': 'version',
@@ -22,6 +23,7 @@ function parseArgs(argv) {
22
23
  dryRun: false,
23
24
  force: false,
24
25
  backup: false,
26
+ reconfigure: false,
25
27
  help: false,
26
28
  version: false,
27
29
  unknown: [],
@@ -56,6 +58,9 @@ ${b('USAGE')}
56
58
  ${b('COMMANDS')}
57
59
  init Install agents, workflow commands and routing rules
58
60
  into ./.claude and ./CLAUDE.md of the current project.
61
+ config Re-prompt the model-tier strategy, show a diff of
62
+ any pending changes to installed agents, and apply
63
+ them with confirmation.
59
64
 
60
65
  ${b('OPTIONS')}
61
66
  --yes, -y Non-interactive. Safe defaults: new files created;
@@ -67,6 +72,9 @@ ${b('OPTIONS')}
67
72
  section without prompting (no backup unless --backup).
68
73
  --backup Always back up a file before overwriting it.
69
74
  Backup name: <file>.backup-YYYYMMDD-HHMMSS
75
+ --reconfigure (init only) Re-prompt model-tier strategy even if a
76
+ .agentcohort.json already exists. Requires a TTY;
77
+ not compatible with --yes.
70
78
  --help, -h Show this help.
71
79
  --version, -v Print the version.
72
80
 
@@ -75,6 +83,7 @@ ${b('WHAT GETS INSTALLED')}
75
83
  reviewer, bug-hunter, root-cause-analyst, ...).
76
84
  .claude/commands/ 7 workflow commands.
77
85
  CLAUDE.md Appends a "# Agentcohort Routing Rules" section.
86
+ .agentcohort.json (Only when user customizes model-tier strategy.)
78
87
 
79
88
  ${b('WORKFLOW COMMANDS (run inside Claude Code)')}
80
89
  /auto-flow Classify the task and pick the right workflow.
package/dist/cli.js CHANGED
@@ -2,8 +2,13 @@
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.main = main;
5
+ const prompts_1 = require("@inquirer/prompts");
6
+ const core_1 = require("@inquirer/core");
5
7
  const installer_1 = require("./installer");
6
8
  const prompt_1 = require("./prompt");
9
+ const promptModels_1 = require("./promptModels");
10
+ const configCmd_1 = require("./configCmd");
11
+ const config_1 = require("./config");
7
12
  const logger_1 = require("./logger");
8
13
  const paths_1 = require("./paths");
9
14
  const args_1 = require("./args");
@@ -55,11 +60,15 @@ async function main(argv = process.argv.slice(2)) {
55
60
  process.stdout.write((0, args_1.helpText)() + '\n');
56
61
  return 0;
57
62
  }
58
- if (args.command !== 'init') {
63
+ if (args.command !== 'init' && args.command !== 'config') {
59
64
  process.stderr.write((0, logger_1.paint)(`✗ Unknown command: ${args.command}\n`, 'red'));
60
65
  process.stdout.write((0, args_1.helpText)() + '\n');
61
66
  return 1;
62
67
  }
68
+ if (args.reconfigure && (args.yes || args.force)) {
69
+ process.stderr.write((0, logger_1.paint)('✗ --reconfigure requires interactive mode (cannot combine with --yes or --force).\n', 'red'));
70
+ return 1;
71
+ }
63
72
  const stdinTTY = Boolean(process.stdin.isTTY);
64
73
  const stdoutTTY = Boolean(process.stdout.isTTY);
65
74
  const interactive = !args.yes && !args.force && !args.dryRun && stdinTTY && stdoutTTY;
@@ -73,10 +82,39 @@ async function main(argv = process.argv.slice(2)) {
73
82
  logger.info('Non-interactive environment detected — using safe defaults (like --yes).');
74
83
  }
75
84
  try {
85
+ const cwd = process.cwd();
86
+ if (args.command === 'config') {
87
+ if (!interactive) {
88
+ process.stderr.write((0, logger_1.paint)('✗ `agentcohort config` requires interactive mode (TTY). Edit .agentcohort.json directly to set models non-interactively.\n', 'red'));
89
+ return 1;
90
+ }
91
+ const result = await (0, configCmd_1.runConfigCmd)({
92
+ cwd,
93
+ promptModelStrategy: promptModels_1.promptModelStrategy,
94
+ confirm: (message) => (0, prompts_1.confirm)({ message, default: true }),
95
+ });
96
+ const msg = {
97
+ 'no-changes': 'No changes. Configuration is up to date.',
98
+ 'no-agents': 'Config saved. No installed agents found — run `agentcohort init` to install.',
99
+ 'cancelled': 'Cancelled. No changes made.',
100
+ 'applied': `Applied ${result.changes.length} change(s) to installed agents.`,
101
+ }[result.status];
102
+ process.stdout.write(`${(0, logger_1.paint)('•', 'cyan')} ${msg}\n`);
103
+ return 0;
104
+ }
105
+ // command === 'init'
106
+ let existingConfig = (0, config_1.loadConfig)(cwd);
107
+ let models = (0, config_1.resolveModels)(existingConfig);
108
+ if (interactive && (existingConfig === null || args.reconfigure)) {
109
+ const newModels = await (0, promptModels_1.promptModelStrategy)(existingConfig?.models);
110
+ // Persist config BEFORE install so a partial install can be re-run idempotently.
111
+ (0, config_1.writeConfig)(cwd, { version: 1, models: newModels });
112
+ models = newModels;
113
+ }
76
114
  if (interactive)
77
115
  resolverHandle = (0, prompt_1.createInteractiveResolver)();
78
116
  const result = await (0, installer_1.runInit)({
79
- cwd: process.cwd(),
117
+ cwd,
80
118
  yes: args.yes,
81
119
  dryRun: args.dryRun,
82
120
  force: args.force,
@@ -84,12 +122,17 @@ async function main(argv = process.argv.slice(2)) {
84
122
  interactive,
85
123
  resolver: resolverHandle?.resolve,
86
124
  logger,
125
+ models,
87
126
  });
88
127
  printSummary(result);
89
128
  return 0;
90
129
  }
91
130
  catch (err) {
92
131
  const message = err instanceof Error ? err.message : String(err);
132
+ if (err instanceof core_1.ExitPromptError) {
133
+ process.stderr.write((0, logger_1.paint)('\nCancelled. No changes made.\n', 'yellow'));
134
+ return 130;
135
+ }
93
136
  process.stderr.write((0, logger_1.paint)(`\n✗ ${message}\n`, 'red'));
94
137
  return 1;
95
138
  }
@@ -0,0 +1,32 @@
1
+ export declare const CONFIG_FILENAME = ".agentcohort.json";
2
+ export interface ModelsConfig {
3
+ premium: string;
4
+ mid: string;
5
+ cheap: string;
6
+ }
7
+ export interface AgentcohortConfig {
8
+ version: 1;
9
+ models: ModelsConfig;
10
+ }
11
+ /**
12
+ * Validate that `raw` is a well-formed AgentcohortConfig. Returns the
13
+ * parsed config (with unknown top-level keys stripped). Throws on any
14
+ * violation.
15
+ */
16
+ export declare function validateConfig(raw: unknown): AgentcohortConfig;
17
+ /**
18
+ * Load `.agentcohort.json` from `projectRoot`. Returns null if absent.
19
+ * Throws a structured error if the file exists but is malformed.
20
+ */
21
+ export declare function loadConfig(projectRoot: string): AgentcohortConfig | null;
22
+ /**
23
+ * Write `cfg` to `.agentcohort.json` in `projectRoot`. Includes a
24
+ * `$schema` field for editor autocomplete. Idempotent at the byte
25
+ * level: writing the same config twice produces identical bytes.
26
+ */
27
+ export declare function writeConfig(projectRoot: string, cfg: AgentcohortConfig): void;
28
+ /**
29
+ * Resolve a ModelsConfig from a possibly-null config. When null,
30
+ * returns DEFAULT_MODELS.
31
+ */
32
+ export declare function resolveModels(cfg: AgentcohortConfig | null): ModelsConfig;
package/dist/config.js ADDED
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CONFIG_FILENAME = void 0;
4
+ exports.validateConfig = validateConfig;
5
+ exports.loadConfig = loadConfig;
6
+ exports.writeConfig = writeConfig;
7
+ exports.resolveModels = resolveModels;
8
+ const node_fs_1 = require("node:fs");
9
+ const node_path_1 = require("node:path");
10
+ const defaults_1 = require("./defaults");
11
+ exports.CONFIG_FILENAME = '.agentcohort.json';
12
+ const TIERS = ['premium', 'mid', 'cheap'];
13
+ function fail(reason) {
14
+ throw new Error(`Invalid .agentcohort.json: ${reason}. Expected schema: { version: 1, models: { premium: string, mid: string, cheap: string } }`);
15
+ }
16
+ /**
17
+ * Validate that `raw` is a well-formed AgentcohortConfig. Returns the
18
+ * parsed config (with unknown top-level keys stripped). Throws on any
19
+ * violation.
20
+ */
21
+ function validateConfig(raw) {
22
+ if (raw === null || typeof raw !== 'object' || Array.isArray(raw)) {
23
+ fail('not an object');
24
+ }
25
+ const obj = raw;
26
+ if (obj.version !== 1) {
27
+ fail(`unsupported version ${JSON.stringify(obj.version)}; expected 1`);
28
+ }
29
+ const models = obj.models;
30
+ if (models === null || typeof models !== 'object' || Array.isArray(models)) {
31
+ fail('models must be an object');
32
+ }
33
+ const m = models;
34
+ const out = {};
35
+ for (const tier of TIERS) {
36
+ const v = m[tier];
37
+ if (typeof v !== 'string') {
38
+ fail(`models.${tier} must be a string`);
39
+ }
40
+ if (v.trim().length === 0) {
41
+ fail(`models.${tier} must be a non-empty, non-whitespace string`);
42
+ }
43
+ out[tier] = v;
44
+ }
45
+ return { version: 1, models: out };
46
+ }
47
+ /**
48
+ * Load `.agentcohort.json` from `projectRoot`. Returns null if absent.
49
+ * Throws a structured error if the file exists but is malformed.
50
+ */
51
+ function loadConfig(projectRoot) {
52
+ const path = (0, node_path_1.join)(projectRoot, exports.CONFIG_FILENAME);
53
+ if (!(0, node_fs_1.existsSync)(path))
54
+ return null;
55
+ let parsed;
56
+ try {
57
+ parsed = JSON.parse((0, node_fs_1.readFileSync)(path, 'utf8'));
58
+ }
59
+ catch (err) {
60
+ const msg = err instanceof Error ? err.message : String(err);
61
+ fail(`malformed JSON (${msg})`);
62
+ }
63
+ return validateConfig(parsed);
64
+ }
65
+ const SCHEMA_URL = 'https://raw.githubusercontent.com/Thiendekaco/agentcohort/main/schema/agentcohort-config-v1.json';
66
+ function serializeConfig(cfg) {
67
+ const ordered = {
68
+ $schema: SCHEMA_URL,
69
+ version: cfg.version,
70
+ models: {
71
+ premium: cfg.models.premium,
72
+ mid: cfg.models.mid,
73
+ cheap: cfg.models.cheap,
74
+ },
75
+ };
76
+ return JSON.stringify(ordered, null, 2) + '\n';
77
+ }
78
+ /**
79
+ * Write `cfg` to `.agentcohort.json` in `projectRoot`. Includes a
80
+ * `$schema` field for editor autocomplete. Idempotent at the byte
81
+ * level: writing the same config twice produces identical bytes.
82
+ */
83
+ function writeConfig(projectRoot, cfg) {
84
+ const path = (0, node_path_1.join)(projectRoot, exports.CONFIG_FILENAME);
85
+ (0, node_fs_1.writeFileSync)(path, serializeConfig(cfg), 'utf8');
86
+ }
87
+ /**
88
+ * Resolve a ModelsConfig from a possibly-null config. When null,
89
+ * returns DEFAULT_MODELS.
90
+ */
91
+ function resolveModels(cfg) {
92
+ if (cfg === null) {
93
+ return {
94
+ premium: defaults_1.DEFAULT_MODELS.premium,
95
+ mid: defaults_1.DEFAULT_MODELS.mid,
96
+ cheap: defaults_1.DEFAULT_MODELS.cheap,
97
+ };
98
+ }
99
+ return cfg.models;
100
+ }
@@ -0,0 +1,27 @@
1
+ import { ModelsConfig } from './config';
2
+ import { ModelChange } from './diff';
3
+ export type ConfigCmdStatus = 'no-changes' | 'no-agents' | 'cancelled' | 'applied';
4
+ export interface ConfigCmdResult {
5
+ status: ConfigCmdStatus;
6
+ changes: ModelChange[];
7
+ }
8
+ export interface ConfigCmdOptions {
9
+ cwd: string;
10
+ /** Inject the prompt function — production passes the real TUI, tests pass a mock. */
11
+ promptModelStrategy: (current?: ModelsConfig) => Promise<ModelsConfig>;
12
+ /** Inject the diff-confirm function — same reason. */
13
+ confirm: (message: string) => Promise<boolean>;
14
+ }
15
+ /**
16
+ * Run the `agentcohort config` subcommand.
17
+ *
18
+ * 1. Load existing config (or null → defaults).
19
+ * 2. Prompt user for a new ModelsConfig (pre-filled with current).
20
+ * 3. If no models changed: write config (idempotent) → 'no-changes'.
21
+ * 4. Compute the diff of installed agent files.
22
+ * 5. If diff is empty (e.g. no .claude/agents dir): write config → 'no-agents'.
23
+ * 6. Otherwise: confirm with user. Decline → 'cancelled'. Accept →
24
+ * write config + rewrite each affected file's `model:` line in
25
+ * place (preserves the rest byte-for-byte) → 'applied'.
26
+ */
27
+ export declare function runConfigCmd(opts: ConfigCmdOptions): Promise<ConfigCmdResult>;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runConfigCmd = runConfigCmd;
4
+ const node_path_1 = require("node:path");
5
+ const config_1 = require("./config");
6
+ const diff_1 = require("./diff");
7
+ const node_fs_1 = require("node:fs");
8
+ /**
9
+ * Run the `agentcohort config` subcommand.
10
+ *
11
+ * 1. Load existing config (or null → defaults).
12
+ * 2. Prompt user for a new ModelsConfig (pre-filled with current).
13
+ * 3. If no models changed: write config (idempotent) → 'no-changes'.
14
+ * 4. Compute the diff of installed agent files.
15
+ * 5. If diff is empty (e.g. no .claude/agents dir): write config → 'no-agents'.
16
+ * 6. Otherwise: confirm with user. Decline → 'cancelled'. Accept →
17
+ * write config + rewrite each affected file's `model:` line in
18
+ * place (preserves the rest byte-for-byte) → 'applied'.
19
+ */
20
+ async function runConfigCmd(opts) {
21
+ const existing = (0, config_1.loadConfig)(opts.cwd);
22
+ const oldModels = (0, config_1.resolveModels)(existing);
23
+ const newModels = await opts.promptModelStrategy(existing?.models);
24
+ const noChange = newModels.premium === oldModels.premium &&
25
+ newModels.mid === oldModels.mid &&
26
+ newModels.cheap === oldModels.cheap;
27
+ const newConfig = { version: 1, models: newModels };
28
+ const agentDir = (0, node_path_1.join)(opts.cwd, '.claude', 'agents');
29
+ if (noChange) {
30
+ (0, config_1.writeConfig)(opts.cwd, newConfig);
31
+ if (!(0, node_fs_1.existsSync)(agentDir)) {
32
+ return { status: 'no-agents', changes: [] };
33
+ }
34
+ return { status: 'no-changes', changes: [] };
35
+ }
36
+ const changes = (0, diff_1.computeFrontmatterModelDiff)(agentDir, oldModels, newModels);
37
+ if (changes.length === 0) {
38
+ (0, config_1.writeConfig)(opts.cwd, newConfig);
39
+ return { status: 'no-agents', changes: [] };
40
+ }
41
+ const message = `Apply ${changes.length} model change${changes.length === 1 ? '' : 's'}?`;
42
+ const accepted = await opts.confirm(message);
43
+ if (!accepted) {
44
+ return { status: 'cancelled', changes };
45
+ }
46
+ (0, config_1.writeConfig)(opts.cwd, newConfig);
47
+ for (const c of changes) {
48
+ const path = (0, node_path_1.join)(agentDir, c.file);
49
+ const current = (0, node_fs_1.readFileSync)(path, 'utf8');
50
+ const rewritten = current.replace(/^model:[ \t]+\S+[ \t]*$/m, `model: ${c.to}`);
51
+ (0, node_fs_1.writeFileSync)(path, rewritten, 'utf8');
52
+ }
53
+ return { status: 'applied', changes };
54
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Single source of truth for default Claude model IDs and the
3
+ * alias-to-tier mapping the installer uses when rewriting agent
4
+ * templates.
5
+ *
6
+ * When a new Claude model ships, update DEFAULT_MODELS here and the
7
+ * change flows through both the default install path and the prompt
8
+ * defaults.
9
+ */
10
+ export declare const DEFAULT_MODELS: {
11
+ readonly premium: "claude-opus-4-7";
12
+ readonly mid: "claude-sonnet-4-6";
13
+ readonly cheap: "claude-haiku-4-5-20251001";
14
+ };
15
+ export declare const TIER_ALIASES: {
16
+ readonly opus: "premium";
17
+ readonly sonnet: "mid";
18
+ readonly haiku: "cheap";
19
+ };
20
+ export type Tier = keyof typeof DEFAULT_MODELS;
21
+ export type TierAlias = keyof typeof TIER_ALIASES;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ /**
3
+ * Single source of truth for default Claude model IDs and the
4
+ * alias-to-tier mapping the installer uses when rewriting agent
5
+ * templates.
6
+ *
7
+ * When a new Claude model ships, update DEFAULT_MODELS here and the
8
+ * change flows through both the default install path and the prompt
9
+ * defaults.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.TIER_ALIASES = exports.DEFAULT_MODELS = void 0;
13
+ exports.DEFAULT_MODELS = {
14
+ premium: 'claude-opus-4-7',
15
+ mid: 'claude-sonnet-4-6',
16
+ cheap: 'claude-haiku-4-5-20251001',
17
+ };
18
+ exports.TIER_ALIASES = {
19
+ opus: 'premium',
20
+ sonnet: 'mid',
21
+ haiku: 'cheap',
22
+ };
package/dist/diff.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ import type { ModelsConfig } from './config';
2
+ export interface ModelChange {
3
+ file: string;
4
+ from: string;
5
+ to: string;
6
+ }
7
+ /**
8
+ * For each `.md` file in `installedAgentDir`, decide whether changing
9
+ * the model config from `oldModels` to `newModels` would alter the
10
+ * file's frontmatter `model:` line. Returns the list of changes (file
11
+ * name + from/to model IDs).
12
+ *
13
+ * A file is treated three ways:
14
+ * 1. Tier alias in frontmatter (`model: opus|sonnet|haiku`): treat
15
+ * as `oldModels[tier(alias)]` and check whether
16
+ * `newModels[tier(alias)]` differs.
17
+ * 2. Concrete ID matching one of oldModels: that's a previously
18
+ * rendered file; we know its tier, so check whether the new
19
+ * config differs.
20
+ * 3. Concrete ID NOT in oldModels: a hand-edit. Skipped.
21
+ *
22
+ * Returns [] if the dir does not exist.
23
+ */
24
+ export declare function computeFrontmatterModelDiff(installedAgentDir: string, oldModels: ModelsConfig, newModels: ModelsConfig): ModelChange[];
package/dist/diff.js ADDED
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.computeFrontmatterModelDiff = computeFrontmatterModelDiff;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ const defaults_1 = require("./defaults");
7
+ /**
8
+ * For each `.md` file in `installedAgentDir`, decide whether changing
9
+ * the model config from `oldModels` to `newModels` would alter the
10
+ * file's frontmatter `model:` line. Returns the list of changes (file
11
+ * name + from/to model IDs).
12
+ *
13
+ * A file is treated three ways:
14
+ * 1. Tier alias in frontmatter (`model: opus|sonnet|haiku`): treat
15
+ * as `oldModels[tier(alias)]` and check whether
16
+ * `newModels[tier(alias)]` differs.
17
+ * 2. Concrete ID matching one of oldModels: that's a previously
18
+ * rendered file; we know its tier, so check whether the new
19
+ * config differs.
20
+ * 3. Concrete ID NOT in oldModels: a hand-edit. Skipped.
21
+ *
22
+ * Returns [] if the dir does not exist.
23
+ */
24
+ function computeFrontmatterModelDiff(installedAgentDir, oldModels, newModels) {
25
+ if (!(0, node_fs_1.existsSync)(installedAgentDir))
26
+ return [];
27
+ const oldById = {
28
+ [oldModels.premium]: 'premium',
29
+ [oldModels.mid]: 'mid',
30
+ [oldModels.cheap]: 'cheap',
31
+ };
32
+ const changes = [];
33
+ for (const file of (0, node_fs_1.readdirSync)(installedAgentDir).sort()) {
34
+ if (!file.endsWith('.md'))
35
+ continue;
36
+ const text = (0, node_fs_1.readFileSync)((0, node_path_1.join)(installedAgentDir, file), 'utf8');
37
+ const m = text.match(/^model:[ \t]+(\S+)[ \t]*$/m);
38
+ if (!m?.[1])
39
+ continue;
40
+ const value = m[1];
41
+ let tier;
42
+ let from = '';
43
+ if (value === 'opus' || value === 'sonnet' || value === 'haiku') {
44
+ tier = defaults_1.TIER_ALIASES[value];
45
+ if (!tier)
46
+ continue; // satisfy strict TS
47
+ from = oldModels[tier];
48
+ }
49
+ else {
50
+ const tierFromId = oldById[value];
51
+ if (!tierFromId) {
52
+ // hand-edited specific ID → skip
53
+ continue;
54
+ }
55
+ tier = tierFromId;
56
+ from = value;
57
+ }
58
+ const to = newModels[tier];
59
+ if (from !== to) {
60
+ changes.push({ file, from, to });
61
+ }
62
+ }
63
+ return changes;
64
+ }
@@ -1,6 +1,7 @@
1
1
  import { EntryKind } from './manifest';
2
2
  import type { ConflictResolver } from './prompt';
3
3
  import type { Logger } from './logger';
4
+ import type { ModelsConfig } from './config';
4
5
  export type Disposition = 'created' | 'overwritten' | 'appended-section' | 'replaced-section' | 'skipped' | 'unchanged';
5
6
  export interface ActionRecord {
6
7
  targetRelPath: string;
@@ -19,6 +20,7 @@ export interface InitOptions {
19
20
  backup: boolean;
20
21
  /** When false, conflicts are resolved by safe automatic defaults. */
21
22
  interactive: boolean;
23
+ models: ModelsConfig;
22
24
  resolver?: ConflictResolver;
23
25
  now?: () => Date;
24
26
  logger?: Logger;
package/dist/installer.js CHANGED
@@ -7,6 +7,7 @@ const fileOps_1 = require("./fileOps");
7
7
  const claudeMd_1 = require("./claudeMd");
8
8
  const manifest_1 = require("./manifest");
9
9
  const paths_1 = require("./paths");
10
+ const render_1 = require("./render");
10
11
  /** Pick a non-clobbering backup path (never overwrite an existing backup). */
11
12
  function uniqueBackupPath(target, date) {
12
13
  const base = (0, fileOps_1.backupPathFor)(target, date);
@@ -100,7 +101,10 @@ async function runInit(options) {
100
101
  return { projectRoot, actions, dryRun: options.dryRun };
101
102
  // ---- per-entry handlers (closures over decide/record/doBackup) ----
102
103
  async function handleRegular(entry) {
103
- const template = (0, node_fs_1.readFileSync)(entry.templateAbsPath, 'utf8');
104
+ const rawTemplate = (0, node_fs_1.readFileSync)(entry.templateAbsPath, 'utf8');
105
+ const template = entry.targetRelPath.startsWith('.claude/agents/')
106
+ ? (0, render_1.renderAgentTemplate)(rawTemplate, options.models)
107
+ : rawTemplate;
104
108
  const existing = (0, fileOps_1.readIfExists)(entry.targetAbsPath);
105
109
  if (existing === null) {
106
110
  if (!options.dryRun)
@@ -0,0 +1,13 @@
1
+ import type { ModelsConfig } from './config';
2
+ /**
3
+ * Interactive 1-step or 2-step prompt that returns a ModelsConfig.
4
+ *
5
+ * Step 1: select "Use defaults (auto)" or "Customize each tier".
6
+ * Step 2 (custom only): three input prompts for premium / mid / cheap.
7
+ *
8
+ * When `current` is provided, prompts pre-fill with it. Otherwise the
9
+ * defaults are pre-filled.
10
+ *
11
+ * Throws ExitPromptError on Ctrl+C — the caller catches and exits 130.
12
+ */
13
+ export declare function promptModelStrategy(current?: ModelsConfig): Promise<ModelsConfig>;
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.promptModelStrategy = promptModelStrategy;
4
+ const prompts_1 = require("@inquirer/prompts");
5
+ const defaults_1 = require("./defaults");
6
+ /**
7
+ * Interactive 1-step or 2-step prompt that returns a ModelsConfig.
8
+ *
9
+ * Step 1: select "Use defaults (auto)" or "Customize each tier".
10
+ * Step 2 (custom only): three input prompts for premium / mid / cheap.
11
+ *
12
+ * When `current` is provided, prompts pre-fill with it. Otherwise the
13
+ * defaults are pre-filled.
14
+ *
15
+ * Throws ExitPromptError on Ctrl+C — the caller catches and exits 130.
16
+ */
17
+ async function promptModelStrategy(current) {
18
+ const base = current ?? {
19
+ premium: defaults_1.DEFAULT_MODELS.premium,
20
+ mid: defaults_1.DEFAULT_MODELS.mid,
21
+ cheap: defaults_1.DEFAULT_MODELS.cheap,
22
+ };
23
+ const mode = await (0, prompts_1.select)({
24
+ message: 'Model strategy:',
25
+ choices: [
26
+ {
27
+ name: 'Use defaults (recommended)',
28
+ value: 'auto',
29
+ description: `premium=${defaults_1.DEFAULT_MODELS.premium}, mid=${defaults_1.DEFAULT_MODELS.mid}, cheap=${defaults_1.DEFAULT_MODELS.cheap}`,
30
+ },
31
+ {
32
+ name: 'Customize each tier',
33
+ value: 'custom',
34
+ description: 'Enter a specific model ID for premium / mid / cheap',
35
+ },
36
+ ],
37
+ default: current ? 'custom' : 'auto',
38
+ });
39
+ if (mode === 'auto') {
40
+ return {
41
+ premium: defaults_1.DEFAULT_MODELS.premium,
42
+ mid: defaults_1.DEFAULT_MODELS.mid,
43
+ cheap: defaults_1.DEFAULT_MODELS.cheap,
44
+ };
45
+ }
46
+ const premium = await (0, prompts_1.input)({
47
+ message: 'Premium tier model ID (architecture, root cause, review):',
48
+ default: base.premium,
49
+ validate: (v) => (v.trim().length > 0 ? true : 'must not be empty'),
50
+ });
51
+ const mid = await (0, prompts_1.input)({
52
+ message: 'Mid tier model ID (implementation, tests, hunting):',
53
+ default: base.mid,
54
+ validate: (v) => (v.trim().length > 0 ? true : 'must not be empty'),
55
+ });
56
+ const cheap = await (0, prompts_1.input)({
57
+ message: 'Cheap tier model ID (repo scout):',
58
+ default: base.cheap,
59
+ validate: (v) => (v.trim().length > 0 ? true : 'must not be empty'),
60
+ });
61
+ return {
62
+ premium: premium.trim(),
63
+ mid: mid.trim(),
64
+ cheap: cheap.trim(),
65
+ };
66
+ }
@@ -0,0 +1,11 @@
1
+ import type { ModelsConfig } from './config';
2
+ /**
3
+ * Rewrite the `model:` line inside the YAML frontmatter from a tier
4
+ * alias (haiku/sonnet/opus) to the user's concrete model ID. Leaves
5
+ * everything else (including hand-edited specific IDs in the
6
+ * frontmatter, and any `model:` text in the body) unchanged.
7
+ *
8
+ * Pure and idempotent: rendering an already-rendered file returns it
9
+ * unchanged.
10
+ */
11
+ export declare function renderAgentTemplate(content: string, models: ModelsConfig): string;
package/dist/render.js ADDED
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderAgentTemplate = renderAgentTemplate;
4
+ const defaults_1 = require("./defaults");
5
+ /**
6
+ * Rewrite the `model:` line inside the YAML frontmatter from a tier
7
+ * alias (haiku/sonnet/opus) to the user's concrete model ID. Leaves
8
+ * everything else (including hand-edited specific IDs in the
9
+ * frontmatter, and any `model:` text in the body) unchanged.
10
+ *
11
+ * Pure and idempotent: rendering an already-rendered file returns it
12
+ * unchanged.
13
+ */
14
+ function renderAgentTemplate(content, models) {
15
+ if (!content.startsWith('---'))
16
+ return content;
17
+ // Find the end of the YAML frontmatter (the second `---` on its own line).
18
+ const fmEndRe = /^---[ \t]*\r?\n([\s\S]*?\r?\n)---[ \t]*\r?\n/;
19
+ const fmMatch = content.match(fmEndRe);
20
+ if (!fmMatch)
21
+ return content;
22
+ const fmEnd = fmMatch[0].length;
23
+ const frontmatter = content.slice(0, fmEnd);
24
+ const body = content.slice(fmEnd);
25
+ const aliasRe = /^model:[ \t]+(haiku|sonnet|opus)[ \t]*$/m;
26
+ const aliasMatch = frontmatter.match(aliasRe);
27
+ if (!aliasMatch)
28
+ return content;
29
+ const alias = aliasMatch[1];
30
+ const tier = defaults_1.TIER_ALIASES[alias];
31
+ const newModelId = models[tier];
32
+ const newLine = `model: ${newModelId}`;
33
+ const newFrontmatter = frontmatter.replace(aliasRe, newLine);
34
+ return newFrontmatter + body;
35
+ }
@@ -8,6 +8,25 @@
8
8
  This project runs as an **AI software-engineering organization**. Default to
9
9
  routing work through the workflow commands instead of ad-hoc editing.
10
10
 
11
+ ## Interoperability & precedence
12
+
13
+ These rules govern how the installed agents interact with the rest of
14
+ your project's setup. They apply to every agent and every workflow.
15
+
16
+ - **Your project rules win.** Anything you write in this CLAUDE.md
17
+ *outside* this `# Agentcohort Routing Rules` section takes precedence
18
+ over an installed agent's prompt. On conflict, agents follow your
19
+ rules.
20
+ - **Installed skills must be invoked when they match.** If you have a
21
+ skill (e.g. `superpowers:*`, `gstack`, etc.) that fits the current
22
+ task, the agent invokes it instead of re-implementing the same logic.
23
+ - **Agent prompts are a baseline, not ground truth.** When your
24
+ CLAUDE.md specifies a tool, framework, commit style, or workflow, the
25
+ agent uses your choice — not the default in its prompt.
26
+ - **Pipeline commands remain the default routing.** `/dev-flow`,
27
+ `/bug-audit`, and the others are the default. A user-defined flow in
28
+ your CLAUDE.md takes precedence when present.
29
+
11
30
  ## Operating standard (all agents)
12
31
 
13
32
  - Operate at **top 1% principal/staff software-engineer** level.
@@ -5,6 +5,20 @@ tools: Read, Glob, Grep, Edit, Write, Bash
5
5
  model: sonnet
6
6
  ---
7
7
 
8
+ <!-- boot-directive-start -->
9
+
10
+ # Boot directive — read before acting
11
+
12
+ 1. Read project CLAUDE.md (especially content OUTSIDE the
13
+ `# Agentcohort Routing Rules` section). User project rules take
14
+ precedence over this agent prompt where they conflict.
15
+ 2. Check available skills. If any skill matches what you're about to do,
16
+ invoke it first — don't re-implement what a skill provides.
17
+ 3. Your role below is the default playbook. User CLAUDE.md and skills
18
+ override this playbook on conflict.
19
+
20
+ <!-- boot-directive-end -->
21
+
8
22
  # Role
9
23
 
10
24
  You are the **Bug Fixer**. You correct the proven root cause of an approved
@@ -5,6 +5,20 @@ tools: Read, Glob, Grep, Bash
5
5
  model: sonnet
6
6
  ---
7
7
 
8
+ <!-- boot-directive-start -->
9
+
10
+ # Boot directive — read before acting
11
+
12
+ 1. Read project CLAUDE.md (especially content OUTSIDE the
13
+ `# Agentcohort Routing Rules` section). User project rules take
14
+ precedence over this agent prompt where they conflict.
15
+ 2. Check available skills. If any skill matches what you're about to do,
16
+ invoke it first — don't re-implement what a skill provides.
17
+ 3. Your role below is the default playbook. User CLAUDE.md and skills
18
+ override this playbook on conflict.
19
+
20
+ <!-- boot-directive-end -->
21
+
8
22
  # Role
9
23
 
10
24
  You are the **Bug Hunter**. You find what is broken or fragile before users
@@ -5,6 +5,20 @@ tools: Read, Glob, Grep
5
5
  model: opus
6
6
  ---
7
7
 
8
+ <!-- boot-directive-start -->
9
+
10
+ # Boot directive — read before acting
11
+
12
+ 1. Read project CLAUDE.md (especially content OUTSIDE the
13
+ `# Agentcohort Routing Rules` section). User project rules take
14
+ precedence over this agent prompt where they conflict.
15
+ 2. Check available skills. If any skill matches what you're about to do,
16
+ invoke it first — don't re-implement what a skill provides.
17
+ 3. Your role below is the default playbook. User CLAUDE.md and skills
18
+ override this playbook on conflict.
19
+
20
+ <!-- boot-directive-end -->
21
+
8
22
  # Role
9
23
 
10
24
  You are the **Expert Council** — a single agent that deliberates as four
@@ -5,6 +5,20 @@ tools: Read, Glob, Grep, Edit, Write, Bash
5
5
  model: sonnet
6
6
  ---
7
7
 
8
+ <!-- boot-directive-start -->
9
+
10
+ # Boot directive — read before acting
11
+
12
+ 1. Read project CLAUDE.md (especially content OUTSIDE the
13
+ `# Agentcohort Routing Rules` section). User project rules take
14
+ precedence over this agent prompt where they conflict.
15
+ 2. Check available skills. If any skill matches what you're about to do,
16
+ invoke it first — don't re-implement what a skill provides.
17
+ 3. Your role below is the default playbook. User CLAUDE.md and skills
18
+ override this playbook on conflict.
19
+
20
+ <!-- boot-directive-end -->
21
+
8
22
  # Role
9
23
 
10
24
  You are the **Feature Implementer**. You execute the plan exactly, making the
@@ -5,6 +5,20 @@ tools: Read, Glob, Grep
5
5
  model: sonnet
6
6
  ---
7
7
 
8
+ <!-- boot-directive-start -->
9
+
10
+ # Boot directive — read before acting
11
+
12
+ 1. Read project CLAUDE.md (especially content OUTSIDE the
13
+ `# Agentcohort Routing Rules` section). User project rules take
14
+ precedence over this agent prompt where they conflict.
15
+ 2. Check available skills. If any skill matches what you're about to do,
16
+ invoke it first — don't re-implement what a skill provides.
17
+ 3. Your role below is the default playbook. User CLAUDE.md and skills
18
+ override this playbook on conflict.
19
+
20
+ <!-- boot-directive-end -->
21
+
8
22
  # Role
9
23
 
10
24
  You are the **Feature Planner**. You convert intent into an unambiguous,
@@ -5,6 +5,20 @@ tools: Read, Glob, Grep, Bash
5
5
  model: opus
6
6
  ---
7
7
 
8
+ <!-- boot-directive-start -->
9
+
10
+ # Boot directive — read before acting
11
+
12
+ 1. Read project CLAUDE.md (especially content OUTSIDE the
13
+ `# Agentcohort Routing Rules` section). User project rules take
14
+ precedence over this agent prompt where they conflict.
15
+ 2. Check available skills. If any skill matches what you're about to do,
16
+ invoke it first — don't re-implement what a skill provides.
17
+ 3. Your role below is the default playbook. User CLAUDE.md and skills
18
+ override this playbook on conflict.
19
+
20
+ <!-- boot-directive-end -->
21
+
8
22
  # Role
9
23
 
10
24
  You are the **Final Reviewer**. You are the last line of defense before code
@@ -5,6 +5,20 @@ tools: Read, Glob, Grep, Edit, Bash
5
5
  model: sonnet
6
6
  ---
7
7
 
8
+ <!-- boot-directive-start -->
9
+
10
+ # Boot directive — read before acting
11
+
12
+ 1. Read project CLAUDE.md (especially content OUTSIDE the
13
+ `# Agentcohort Routing Rules` section). User project rules take
14
+ precedence over this agent prompt where they conflict.
15
+ 2. Check available skills. If any skill matches what you're about to do,
16
+ invoke it first — don't re-implement what a skill provides.
17
+ 3. Your role below is the default playbook. User CLAUDE.md and skills
18
+ override this playbook on conflict.
19
+
20
+ <!-- boot-directive-end -->
21
+
8
22
  # Role
9
23
 
10
24
  You are the **Performance Optimizer**. You make it faster without making it
@@ -5,6 +5,20 @@ tools: Read, Glob, Grep, Bash
5
5
  model: opus
6
6
  ---
7
7
 
8
+ <!-- boot-directive-start -->
9
+
10
+ # Boot directive — read before acting
11
+
12
+ 1. Read project CLAUDE.md (especially content OUTSIDE the
13
+ `# Agentcohort Routing Rules` section). User project rules take
14
+ precedence over this agent prompt where they conflict.
15
+ 2. Check available skills. If any skill matches what you're about to do,
16
+ invoke it first — don't re-implement what a skill provides.
17
+ 3. Your role below is the default playbook. User CLAUDE.md and skills
18
+ override this playbook on conflict.
19
+
20
+ <!-- boot-directive-end -->
21
+
8
22
  # Role
9
23
 
10
24
  You are the **Performance Reviewer**. You make sure the speedup did not buy
@@ -5,6 +5,20 @@ tools: Read, Glob, Grep, Bash
5
5
  model: sonnet
6
6
  ---
7
7
 
8
+ <!-- boot-directive-start -->
9
+
10
+ # Boot directive — read before acting
11
+
12
+ 1. Read project CLAUDE.md (especially content OUTSIDE the
13
+ `# Agentcohort Routing Rules` section). User project rules take
14
+ precedence over this agent prompt where they conflict.
15
+ 2. Check available skills. If any skill matches what you're about to do,
16
+ invoke it first — don't re-implement what a skill provides.
17
+ 3. Your role below is the default playbook. User CLAUDE.md and skills
18
+ override this playbook on conflict.
19
+
20
+ <!-- boot-directive-end -->
21
+
8
22
  # Role
9
23
 
10
24
  You are the **Performance Hunter**. You locate where time and resources
@@ -5,6 +5,20 @@ tools: Read, Glob, Grep, Edit, Bash
5
5
  model: sonnet
6
6
  ---
7
7
 
8
+ <!-- boot-directive-start -->
9
+
10
+ # Boot directive — read before acting
11
+
12
+ 1. Read project CLAUDE.md (especially content OUTSIDE the
13
+ `# Agentcohort Routing Rules` section). User project rules take
14
+ precedence over this agent prompt where they conflict.
15
+ 2. Check available skills. If any skill matches what you're about to do,
16
+ invoke it first — don't re-implement what a skill provides.
17
+ 3. Your role below is the default playbook. User CLAUDE.md and skills
18
+ override this playbook on conflict.
19
+
20
+ <!-- boot-directive-end -->
21
+
8
22
  # Role
9
23
 
10
24
  You are the **Regression Guard**. Your tests are the bug's permanent tombstone:
@@ -5,6 +5,20 @@ tools: Read, Glob, Grep
5
5
  model: haiku
6
6
  ---
7
7
 
8
+ <!-- boot-directive-start -->
9
+
10
+ # Boot directive — read before acting
11
+
12
+ 1. Read project CLAUDE.md (especially content OUTSIDE the
13
+ `# Agentcohort Routing Rules` section). User project rules take
14
+ precedence over this agent prompt where they conflict.
15
+ 2. Check available skills. If any skill matches what you're about to do,
16
+ invoke it first — don't re-implement what a skill provides.
17
+ 3. Your role below is the default playbook. User CLAUDE.md and skills
18
+ override this playbook on conflict.
19
+
20
+ <!-- boot-directive-end -->
21
+
8
22
  # Role
9
23
 
10
24
  You are the **Repo Scout**. You go in first, map the terrain, and come back
@@ -5,6 +5,20 @@ tools: Read, Glob, Grep, Bash, Edit
5
5
  model: sonnet
6
6
  ---
7
7
 
8
+ <!-- boot-directive-start -->
9
+
10
+ # Boot directive — read before acting
11
+
12
+ 1. Read project CLAUDE.md (especially content OUTSIDE the
13
+ `# Agentcohort Routing Rules` section). User project rules take
14
+ precedence over this agent prompt where they conflict.
15
+ 2. Check available skills. If any skill matches what you're about to do,
16
+ invoke it first — don't re-implement what a skill provides.
17
+ 3. Your role below is the default playbook. User CLAUDE.md and skills
18
+ override this playbook on conflict.
19
+
20
+ <!-- boot-directive-end -->
21
+
8
22
  # Role
9
23
 
10
24
  You are the **Reproduction Engineer**. A bug that cannot be reproduced cannot
@@ -5,6 +5,20 @@ tools: Read, Glob, Grep, Bash
5
5
  model: opus
6
6
  ---
7
7
 
8
+ <!-- boot-directive-start -->
9
+
10
+ # Boot directive — read before acting
11
+
12
+ 1. Read project CLAUDE.md (especially content OUTSIDE the
13
+ `# Agentcohort Routing Rules` section). User project rules take
14
+ precedence over this agent prompt where they conflict.
15
+ 2. Check available skills. If any skill matches what you're about to do,
16
+ invoke it first — don't re-implement what a skill provides.
17
+ 3. Your role below is the default playbook. User CLAUDE.md and skills
18
+ override this playbook on conflict.
19
+
20
+ <!-- boot-directive-end -->
21
+
8
22
  # Role
9
23
 
10
24
  You are the **Root Cause Analyst**. You refuse to stop at the symptom. You
@@ -5,6 +5,20 @@ tools: Read, Glob, Grep
5
5
  model: opus
6
6
  ---
7
7
 
8
+ <!-- boot-directive-start -->
9
+
10
+ # Boot directive — read before acting
11
+
12
+ 1. Read project CLAUDE.md (especially content OUTSIDE the
13
+ `# Agentcohort Routing Rules` section). User project rules take
14
+ precedence over this agent prompt where they conflict.
15
+ 2. Check available skills. If any skill matches what you're about to do,
16
+ invoke it first — don't re-implement what a skill provides.
17
+ 3. Your role below is the default playbook. User CLAUDE.md and skills
18
+ override this playbook on conflict.
19
+
20
+ <!-- boot-directive-end -->
21
+
8
22
  # Role
9
23
 
10
24
  You are the **Solution Architect**. You decide *how* the system should change
@@ -5,6 +5,20 @@ tools: Read, Glob, Grep, Edit, Bash
5
5
  model: sonnet
6
6
  ---
7
7
 
8
+ <!-- boot-directive-start -->
9
+
10
+ # Boot directive — read before acting
11
+
12
+ 1. Read project CLAUDE.md (especially content OUTSIDE the
13
+ `# Agentcohort Routing Rules` section). User project rules take
14
+ precedence over this agent prompt where they conflict.
15
+ 2. Check available skills. If any skill matches what you're about to do,
16
+ invoke it first — don't re-implement what a skill provides.
17
+ 3. Your role below is the default playbook. User CLAUDE.md and skills
18
+ override this playbook on conflict.
19
+
20
+ <!-- boot-directive-end -->
21
+
8
22
  # Role
9
23
 
10
24
  You are the **Test Verifier**. You are the evidence gate: after a change, you
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentcohort",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Install a principal/staff-level Claude Code AI software engineering organization (agents + workflows + routing rules) into any project with one command.",
5
5
  "keywords": [
6
6
  "claude",
@@ -43,7 +43,8 @@
43
43
  },
44
44
  "scripts": {
45
45
  "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
46
- "build": "npm run clean && tsc -p tsconfig.json && node scripts/copy-templates.mjs",
46
+ "sync-boot": "node scripts/sync-boot-directive.mjs",
47
+ "build": "npm run clean && npm run sync-boot && tsc -p tsconfig.json && node scripts/copy-templates.mjs",
47
48
  "test": "vitest run",
48
49
  "test:watch": "vitest",
49
50
  "prepublishOnly": "npm run build && npm test"
@@ -52,5 +53,8 @@
52
53
  "@types/node": "^20.14.0",
53
54
  "typescript": "^5.5.0",
54
55
  "vitest": "^2.0.0"
56
+ },
57
+ "dependencies": {
58
+ "@inquirer/prompts": "^7.10.1"
55
59
  }
56
- }
60
+ }