cohorte 1.6.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/CHANGELOG.md +84 -2
- package/README.md +57 -57
- package/bin/cli.js +23 -15
- package/core/agents/implementer.template.md +3 -3
- package/core/agents/release.md +1 -1
- package/core/agents/review.md +3 -3
- package/core/commands/{audit.md → cohorte-audit.md} +3 -3
- package/core/commands/{brainstorm.md → cohorte-brainstorm.md} +4 -4
- package/core/commands/{build.md → cohorte-build.md} +15 -15
- package/core/commands/{doctor.md → cohorte-doctor.md} +17 -9
- package/core/commands/{fix.md → cohorte-fix.md} +15 -13
- package/core/commands/{init-pipeline.md → cohorte-init-pipeline.md} +1 -1
- package/core/commands/cohorte-loop.md +110 -0
- package/core/commands/{refactor.md → cohorte-refactor.md} +3 -3
- package/core/commands/{review.md → cohorte-review.md} +20 -19
- package/core/commands/{ship.md → cohorte-ship.md} +5 -5
- package/core/commands/{spec.md → cohorte-spec.md} +13 -13
- package/core/commands/{update-pipeline.md → cohorte-update-pipeline.md} +11 -6
- package/core/hooks/gate.py +101 -6
- package/core/templates/brainstorm-return.md +4 -4
- package/core/templates/decisions.template.md +1 -1
- package/core/templates/design-brief.md +1 -1
- package/core/templates/spec.template.md +7 -7
- package/core/templates/steps/init-pipeline/01-detect-stack.md +1 -1
- package/core/templates/steps/init-pipeline/02-interview-gaps.md +6 -6
- package/core/templates/steps/init-pipeline/03-draft-profile.md +1 -1
- package/core/templates/steps/init-pipeline/04-write-render.md +16 -12
- package/core/templates/steps/init-pipeline/05-report.md +5 -5
- package/core/workflows/audit.js +6 -6
- package/core/workflows/refactor.js +14 -14
- package/core/workflows/review.js +22 -22
- package/dashboard/README.md +2 -2
- package/dashboard/dist/assets/{index-DYyn4p93.js → index-P1I1JGtj.js} +2 -2
- package/dashboard/dist/index.html +1 -1
- package/dashboard/server/doctor.js +69 -19
- package/dashboard/server/index.js +5 -5
- package/dashboard/server/metrics.js +1 -1
- package/install.ps1 +23 -14
- package/install.sh +24 -14
- package/package.json +2 -2
- package/profile/PIPELINE.template.md +17 -16
- package/profile/SCHEMA.md +89 -77
- package/profile/cohorte.config.template.yaml +8 -8
- package/scripts/loop-detach.sh +153 -0
- package/scripts/loop.sh +75 -27
- package/scripts/metrics/collect.mjs +17 -8
- package/scripts/new-feature.sh.template +3 -3
- package/scripts/preflight.sh +40 -4
- package/scripts/remove-feature.sh.template +2 -2
- package/scripts/test-dashboard.mjs +34 -7
- package/scripts/test-gate.mjs +58 -0
- package/scripts/test-loop.mjs +49 -7
- package/scripts/test-metrics.mjs +23 -11
- package/scripts/test-workflows.mjs +7 -7
- package/scripts/validate-core.mjs +45 -23
- package/core/commands/drive.md +0 -80
- /package/core/commands/{align-ds.md → cohorte-align-ds.md} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
// Programmatic port of the /doctor checks (core/commands/doctor.md), for the dashboard.
|
|
2
|
+
// Programmatic port of the /cohorte-doctor checks (core/commands/doctor.md), for the dashboard.
|
|
3
3
|
// Read-only: inspects files only. Checks that need a live process (MCP connectivity,
|
|
4
4
|
// git worktree state, DesignSync) are reported as `skip` with a note — the node server
|
|
5
5
|
// can't run them, and honest "not checked here" beats a false green.
|
|
@@ -20,14 +20,14 @@ const FIXED_AGENTS = new Set([
|
|
|
20
20
|
]);
|
|
21
21
|
|
|
22
22
|
// The spec lifecycle (SCHEMA.md §Spec status). `in-progress` and `blocked` are written by
|
|
23
|
-
// the /
|
|
23
|
+
// the /cohorte-loop driver — they are what makes an interrupted autonomous loop resumable, so a
|
|
24
24
|
// dashboard that flagged them as invalid would report the pipeline's own state as a defect.
|
|
25
25
|
const VALID_STATUS = ['draft', 'frozen', 'in-progress', 'in-review', 'shipped', 'blocked'];
|
|
26
26
|
|
|
27
27
|
// Artifacts the pipeline itself writes into specs/ that are NOT feature specs and have no
|
|
28
|
-
// front-matter status. `/audit` writes specs/refactor-backlog.md by design, so scanning it
|
|
29
|
-
// as a spec made /doctor warn about a file cohorte had just created — a false positive that
|
|
30
|
-
// fired in every project that had ever run /audit. `_`-prefixed files (e.g. _template.md)
|
|
28
|
+
// front-matter status. `/cohorte-audit` writes specs/refactor-backlog.md by design, so scanning it
|
|
29
|
+
// as a spec made /cohorte-doctor warn about a file cohorte had just created — a false positive that
|
|
30
|
+
// fired in every project that had ever run /cohorte-audit. `_`-prefixed files (e.g. _template.md)
|
|
31
31
|
// are already skipped by the reader below.
|
|
32
32
|
const NON_SPEC_FILES = new Set(['refactor-backlog.md']);
|
|
33
33
|
|
|
@@ -62,7 +62,7 @@ function checkCore(v) {
|
|
|
62
62
|
if (v.freshness === -1) {
|
|
63
63
|
return mk('core', 'Core & pointer', 'warn',
|
|
64
64
|
`core ${v.installedVersion} installed (${v.installMode}); npm latest is ${v.latest}`,
|
|
65
|
-
'/update-pipeline (or npx cohorte update)');
|
|
65
|
+
'/cohorte-update-pipeline (or npx cohorte update)');
|
|
66
66
|
}
|
|
67
67
|
const tail = v.latest ? `, npm latest ${v.latest}` : ', npm unreachable';
|
|
68
68
|
return mk('core', 'Core & pointer', 'ok', `core ${v.installedVersion} (${v.installMode})${tail}`);
|
|
@@ -71,12 +71,12 @@ function checkCore(v) {
|
|
|
71
71
|
function checkProfile(profile, hasPipelineMd) {
|
|
72
72
|
if (!hasPipelineMd) {
|
|
73
73
|
return mk('profile', 'Profile (PIPELINE.md)', 'bad', 'PIPELINE.md not found',
|
|
74
|
-
'/init-pipeline (generate the project profile)');
|
|
74
|
+
'/cohorte-init-pipeline (generate the project profile)');
|
|
75
75
|
}
|
|
76
76
|
if (!profile) {
|
|
77
77
|
return mk('profile', 'Profile (PIPELINE.md)', 'bad',
|
|
78
78
|
'PIPELINE.md present but its `yaml pipeline-profile` block is missing or unparseable',
|
|
79
|
-
'/init-pipeline (or fix the fenced yaml block)');
|
|
79
|
+
'/cohorte-init-pipeline (or fix the fenced yaml block)');
|
|
80
80
|
}
|
|
81
81
|
const n = (profile.surfaces || []).length;
|
|
82
82
|
return mk('profile', 'Profile (PIPELINE.md)', n ? 'ok' : 'warn',
|
|
@@ -101,7 +101,7 @@ function checkAgents(profile, projectRoot) {
|
|
|
101
101
|
if (missing.length) {
|
|
102
102
|
return mk('agents', 'Surfaces ↔ agents', 'bad',
|
|
103
103
|
`surface(s) with no rendered agent: ${missing.join(', ')}`,
|
|
104
|
-
'/init-pipeline (re-render surface agents)');
|
|
104
|
+
'/cohorte-init-pipeline (re-render surface agents)');
|
|
105
105
|
}
|
|
106
106
|
if (orphans.length) {
|
|
107
107
|
return mk('agents', 'Surfaces ↔ agents', 'warn',
|
|
@@ -120,7 +120,7 @@ function checkGate(profile, projectRoot) {
|
|
|
120
120
|
const cfg = readJson(path.join(projectRoot, '.claude', 'gate-config.json'));
|
|
121
121
|
if (!cfg) {
|
|
122
122
|
return mk('gate', 'Gate config', 'bad', '.claude/gate-config.json missing or unreadable',
|
|
123
|
-
'/init-pipeline (regenerate gate-config.json from the gate block)');
|
|
123
|
+
'/cohorte-init-pipeline (regenerate gate-config.json from the gate block)');
|
|
124
124
|
}
|
|
125
125
|
const drifted = [];
|
|
126
126
|
if (!sameSet(cfg.deny, gate.deny)) drifted.push('deny');
|
|
@@ -147,6 +147,55 @@ function checkGate(profile, projectRoot) {
|
|
|
147
147
|
(branchGated ? `, ${branchGated} gated on ${gate.default_branch || 'main'}` : '') + ')');
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
// Local-only pipeline artifacts. `.claude/preflight.ok` is the one that BREAKS things when
|
|
151
|
+
// versioned rather than merely being noise: the stamp names the tree it verified, committing
|
|
152
|
+
// it moves HEAD past that, and the committed copy then rides into every fresh clone and
|
|
153
|
+
// worktree — the phase gate either blocks a clean tree or greens one it never checked.
|
|
154
|
+
const LOCAL_ARTIFACTS = [
|
|
155
|
+
{ path: '.claude/preflight.ok', why: 'the phase-gate stamp — a versioned one breaks the gate in every clone and worktree' },
|
|
156
|
+
{ path: '.claude/pipeline-metrics.jsonl', why: 'the per-dispatch metrics sink (local, append-only)' },
|
|
157
|
+
{ path: 'specs/reports/', why: 'the /cohorte-review report buffer (derived, regenerated each run)' },
|
|
158
|
+
];
|
|
159
|
+
|
|
160
|
+
// Does any .gitignore in play cover `rel`? Deliberately literal — it recognizes the exact
|
|
161
|
+
// path, its basename, a trailing-slash dir prefix and a `*.<ext>` glob, which is every form
|
|
162
|
+
// /cohorte-init-pipeline writes. Anything more clever would need a real gitignore engine.
|
|
163
|
+
function ignoreCovers(projectRoot, rel) {
|
|
164
|
+
const base = rel.replace(/\/$/, '').split('/').pop();
|
|
165
|
+
const ext = base.includes('.') ? '*' + base.slice(base.lastIndexOf('.')) : null;
|
|
166
|
+
const files = [
|
|
167
|
+
path.join(projectRoot, '.gitignore'),
|
|
168
|
+
path.join(projectRoot, '.claude', '.gitignore'),
|
|
169
|
+
];
|
|
170
|
+
for (const f of files) {
|
|
171
|
+
const text = readText(f);
|
|
172
|
+
if (!text) continue;
|
|
173
|
+
for (let line of text.split('\n')) {
|
|
174
|
+
line = line.trim();
|
|
175
|
+
if (!line || line.startsWith('#')) continue;
|
|
176
|
+
const p = line.replace(/^\/+/, '').replace(/\/+$/, '');
|
|
177
|
+
if (!p) continue;
|
|
178
|
+
if (p === rel.replace(/\/$/, '') || p === base || p === ext) return true;
|
|
179
|
+
// A directory rule covers everything under it (`.claude/` ignores the stamp too).
|
|
180
|
+
if (rel.startsWith(p + '/')) return true;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function checkLocalArtifacts(projectRoot) {
|
|
187
|
+
const unignored = LOCAL_ARTIFACTS.filter(a => !ignoreCovers(projectRoot, a.path));
|
|
188
|
+
if (!unignored.length) {
|
|
189
|
+
return mk('artifacts', 'Local artifacts', 'ok',
|
|
190
|
+
`${LOCAL_ARTIFACTS.length} local-only artifact path(s) all gitignored`);
|
|
191
|
+
}
|
|
192
|
+
const stamp = unignored.find(a => a.path === '.claude/preflight.ok');
|
|
193
|
+
return mk('artifacts', 'Local artifacts', stamp ? 'bad' : 'warn',
|
|
194
|
+
`not gitignored: ${unignored.map(a => a.path).join(', ')} — ${unignored[0].why}`,
|
|
195
|
+
`add ${unignored.map(a => a.path).join(' + ')} to .gitignore`
|
|
196
|
+
+ (stamp ? ', then `git rm --cached --ignore-unmatch .claude/preflight.ok`' : ''));
|
|
197
|
+
}
|
|
198
|
+
|
|
150
199
|
function gateRegs(settingsPath) {
|
|
151
200
|
const data = readJson(settingsPath);
|
|
152
201
|
const pre = data && data.hooks && Array.isArray(data.hooks.PreToolUse) ? data.hooks.PreToolUse : [];
|
|
@@ -159,7 +208,7 @@ function gateRegs(settingsPath) {
|
|
|
159
208
|
|
|
160
209
|
function checkHooks(projectRoot, globalDir, installMode) {
|
|
161
210
|
// A registration in EITHER scope serves the project: bundled repos get it from
|
|
162
|
-
// /init-pipeline in project settings, but on a machine with the global core the
|
|
211
|
+
// /cohorte-init-pipeline in project settings, but on a machine with the global core the
|
|
163
212
|
// hook usually lives (correctly, exactly once) in global settings — warning
|
|
164
213
|
// there would prescribe a re-registration that double-prompts.
|
|
165
214
|
const scopes = [
|
|
@@ -173,7 +222,7 @@ function checkHooks(projectRoot, globalDir, installMode) {
|
|
|
173
222
|
return mk('hooks', 'Gate hook', 'warn', 'gate.py not registered in project or global settings.json',
|
|
174
223
|
installMode === 'global'
|
|
175
224
|
? 'npx cohorte install --global (re-registers the hook)'
|
|
176
|
-
: '/init-pipeline (register the PreToolUse gate hook)');
|
|
225
|
+
: '/cohorte-init-pipeline (register the PreToolUse gate hook)');
|
|
177
226
|
}
|
|
178
227
|
const total = found.reduce((n, s) => n + s.regs.length, 0);
|
|
179
228
|
if (total > 1) {
|
|
@@ -195,7 +244,7 @@ function checkRetrieval(profile, projectRoot) {
|
|
|
195
244
|
if (!provider || provider === 'none' || String(provider).startsWith('<')) {
|
|
196
245
|
return mk('retrieval', 'Code retrieval', 'skip', 'provider: none');
|
|
197
246
|
}
|
|
198
|
-
// The profile alone isn't proof the provider was ever wired: /init-pipeline
|
|
247
|
+
// The profile alone isn't proof the provider was ever wired: /cohorte-init-pipeline
|
|
199
248
|
// registers it at project scope in .mcp.json. Verify the entry exists on disk;
|
|
200
249
|
// live connectivity still needs a session — note it, don't fake green.
|
|
201
250
|
const mcp = readJson(path.join(projectRoot, '.mcp.json'));
|
|
@@ -204,10 +253,10 @@ function checkRetrieval(profile, projectRoot) {
|
|
|
204
253
|
if (!wired) {
|
|
205
254
|
return mk('retrieval', 'Code retrieval', 'warn',
|
|
206
255
|
`profile says provider: ${provider} but .mcp.json has no matching server entry`,
|
|
207
|
-
'/init-pipeline or /update-pipeline (re-wire the retrieval provider)');
|
|
256
|
+
'/cohorte-init-pipeline or /cohorte-update-pipeline (re-wire the retrieval provider)');
|
|
208
257
|
}
|
|
209
258
|
return mk('retrieval', 'Code retrieval', 'ok',
|
|
210
|
-
`provider: ${provider} — registered in .mcp.json (connectivity needs /doctor in-session)`);
|
|
259
|
+
`provider: ${provider} — registered in .mcp.json (connectivity needs /cohorte-doctor in-session)`);
|
|
211
260
|
}
|
|
212
261
|
|
|
213
262
|
function checkDesign(profile, projectRoot) {
|
|
@@ -234,14 +283,14 @@ function checkIsolation(profile, projectRoot) {
|
|
|
234
283
|
}
|
|
235
284
|
if (problems.length) {
|
|
236
285
|
return mk('isolation', 'Isolation', 'warn', problems.join('; '),
|
|
237
|
-
'/init-pipeline (re-render the isolation scripts)');
|
|
286
|
+
'/cohorte-init-pipeline (re-render the isolation scripts)');
|
|
238
287
|
}
|
|
239
288
|
return mk('isolation', 'Isolation', 'ok', 'feature scripts rendered (worktree state not checked here)');
|
|
240
289
|
}
|
|
241
290
|
|
|
242
291
|
// Workflow variants (review/audit/refactor as deterministic multi-agent runs) are opt-in;
|
|
243
292
|
// the conversational commands stay the default path, so nothing here is ever 'bad'.
|
|
244
|
-
// Whether the session has workflows ENABLED needs a live Claude session — /doctor
|
|
293
|
+
// Whether the session has workflows ENABLED needs a live Claude session — /cohorte-doctor
|
|
245
294
|
// in-session checks that; here we only check what's on disk.
|
|
246
295
|
function checkWorkflows(projectRoot, globalDir, installMode) {
|
|
247
296
|
if (installMode === 'none') return mk('workflows', 'Workflows', 'skip', 'no core installed');
|
|
@@ -269,7 +318,7 @@ function checkWorkflows(projectRoot, globalDir, installMode) {
|
|
|
269
318
|
}
|
|
270
319
|
return mk('workflows', 'Workflows', 'ok',
|
|
271
320
|
'scripts + profile-reader installed — opt-in per run; needs Claude Code ≥ 2.1.154 with ' +
|
|
272
|
-
'workflows enabled (run /doctor in-session to check the live half)');
|
|
321
|
+
'workflows enabled (run /cohorte-doctor in-session to check the live half)');
|
|
273
322
|
}
|
|
274
323
|
|
|
275
324
|
function scanSpecs(projectRoot) {
|
|
@@ -284,7 +333,7 @@ function scanSpecs(projectRoot) {
|
|
|
284
333
|
const body = fm ? fm[1] : '';
|
|
285
334
|
const get = k => { const m = body.match(new RegExp(`^${k}:\\s*(.*)$`, 'm')); return m ? m[1].trim() : null; };
|
|
286
335
|
const status = get('status');
|
|
287
|
-
// The loop driver's resume state, when a /
|
|
336
|
+
// The loop driver's resume state, when a /cohorte-loop is (or was) running on this spec.
|
|
288
337
|
const pass = parseInt(get('loop_pass'), 10);
|
|
289
338
|
const phase = get('loop_phase');
|
|
290
339
|
specs.push({
|
|
@@ -327,6 +376,7 @@ async function state({ projectRoot, globalDir, cliVersion }) {
|
|
|
327
376
|
checkProfile(profile, pipelineMd != null),
|
|
328
377
|
checkAgents(profile, projectRoot),
|
|
329
378
|
checkGate(profile, projectRoot),
|
|
379
|
+
checkLocalArtifacts(projectRoot),
|
|
330
380
|
checkHooks(projectRoot, globalDir, v.installMode),
|
|
331
381
|
checkRetrieval(profile, projectRoot),
|
|
332
382
|
checkDesign(profile, projectRoot),
|
|
@@ -143,8 +143,8 @@ function runAction(req, res, body, { pkgRoot }) {
|
|
|
143
143
|
function runClaude(req, res, body) {
|
|
144
144
|
const project = body.project ? path.resolve(body.project) : null;
|
|
145
145
|
const command = String(body.command || '');
|
|
146
|
-
if (!/^\/(init-pipeline|update-pipeline|audit)$/.test(command)) {
|
|
147
|
-
return sendJson(res, 400, { error: 'unsupported command (only /init-pipeline, /update-pipeline or /audit)' });
|
|
146
|
+
if (!/^\/cohorte-(init-pipeline|update-pipeline|audit)$/.test(command)) {
|
|
147
|
+
return sendJson(res, 400, { error: 'unsupported command (only /cohorte-init-pipeline, /cohorte-update-pipeline or /cohorte-audit)' });
|
|
148
148
|
}
|
|
149
149
|
if (!project || !fs.existsSync(project)) {
|
|
150
150
|
return sendJson(res, 400, { error: 'project path not found' });
|
|
@@ -174,7 +174,7 @@ function runClaude(req, res, body) {
|
|
|
174
174
|
// Full project reset: back up the project's pipeline footprint (.claude/, PIPELINE.md, and
|
|
175
175
|
// optionally specs/) to .claude.bak-<ts>, remove it, then reinstall a fresh BUNDLED core (or,
|
|
176
176
|
// for global-mode projects, leave the shared ~/.claude core untouched). Never touches ~/.claude.
|
|
177
|
-
// Streams progress; ends with __EXIT__ <code>. The profile is regenerated by /init-pipeline after.
|
|
177
|
+
// Streams progress; ends with __EXIT__ <code>. The profile is regenerated by /cohorte-init-pipeline after.
|
|
178
178
|
function runReset(req, res, body, { pkgRoot, globalDir }) {
|
|
179
179
|
const project = body.project ? path.resolve(body.project) : null;
|
|
180
180
|
const purgeSpecs = !!body.purgeSpecs;
|
|
@@ -230,14 +230,14 @@ function runReset(req, res, body, { pkgRoot, globalDir }) {
|
|
|
230
230
|
child.stdout.on('data', d => res.write(d));
|
|
231
231
|
child.stderr.on('data', d => res.write(d));
|
|
232
232
|
child.on('close', code => {
|
|
233
|
-
log('\n✔ Reset complete. Now run /init-pipeline in Claude Code to regenerate PIPELINE.md + the surface agents.');
|
|
233
|
+
log('\n✔ Reset complete. Now run /cohorte-init-pipeline in Claude Code to regenerate PIPELINE.md + the surface agents.');
|
|
234
234
|
done(code);
|
|
235
235
|
});
|
|
236
236
|
child.on('error', err => { log(`\nspawn error: ${err.message}`); done(1); });
|
|
237
237
|
req.on('close', () => { try { child.kill(); } catch { /* already gone */ } });
|
|
238
238
|
} else {
|
|
239
239
|
log('\n✔ Reset complete. The shared global core stays installed in ~/.claude.');
|
|
240
|
-
log('Now run /init-pipeline in Claude Code to regenerate this project\'s PIPELINE.md + agents.');
|
|
240
|
+
log('Now run /cohorte-init-pipeline in Claude Code to regenerate this project\'s PIPELINE.md + agents.');
|
|
241
241
|
done(0);
|
|
242
242
|
}
|
|
243
243
|
} catch (e) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
// Read a project's `.claude/pipeline-metrics.jsonl` (one line per phase batch, appended by
|
|
3
|
-
// /build, /review and /fix) and aggregate it per feature: wall-clock per phase, fix
|
|
3
|
+
// /cohorte-build, /cohorte-review and /cohorte-fix) and aggregate it per feature: wall-clock per phase, fix
|
|
4
4
|
// rounds, and per-surface results. Dependency-free; a missing file is simply "no data yet".
|
|
5
5
|
//
|
|
6
6
|
// Two line formats coexist in the file:
|
package/install.ps1
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
# .\install.ps1 -Update -Global
|
|
15
15
|
#
|
|
16
16
|
# Per-project install copies the core into <target>\.claude; global install copies it once
|
|
17
|
-
# into ~\.claude and registers the gate hook there. Either way you then run `/init-pipeline`
|
|
17
|
+
# into ~\.claude and registers the gate hook there. Either way you then run `/cohorte-init-pipeline`
|
|
18
18
|
# in each repo to generate PIPELINE.md + render the surface agents. Update refreshes ONLY the
|
|
19
19
|
# stack-agnostic files; generated profiles, rendered agents, gate-config.json and any project
|
|
20
20
|
# settings.json are left untouched.
|
|
@@ -152,6 +152,7 @@ try {
|
|
|
152
152
|
Copy-Item (Join-Path $src 'scripts\telemetry-send.sh') (Join-Path $dest 'pipeline\scripts') -Force
|
|
153
153
|
Copy-Item (Join-Path $src 'scripts\preflight.sh') (Join-Path $dest 'pipeline\scripts') -Force
|
|
154
154
|
Copy-Item (Join-Path $src 'scripts\loop.sh') (Join-Path $dest 'pipeline\scripts') -Force
|
|
155
|
+
Copy-Item (Join-Path $src 'scripts\loop-detach.sh') (Join-Path $dest 'pipeline\scripts') -Force
|
|
155
156
|
Copy-Item (Join-Path $src 'core\agents\implementer.template.md') (Join-Path $dest 'pipeline') -Force
|
|
156
157
|
if (Test-Path (Join-Path $src 'CHANGELOG.md')) { Copy-Item (Join-Path $src 'CHANGELOG.md') (Join-Path $dest 'pipeline') -Force }
|
|
157
158
|
[System.IO.File]::WriteAllText((Join-Path $dest 'pipeline\VERSION'), "$ver`n", [System.Text.UTF8Encoding]::new($false))
|
|
@@ -201,6 +202,14 @@ try {
|
|
|
201
202
|
# 1.6.0 renamed /loop → /drive: Claude Code's own built-in /loop shadowed ours, so a leftover
|
|
202
203
|
# commands\loop.md is a command the user can never reach — scrub it rather than leave a decoy.
|
|
203
204
|
Remove-Item -LiteralPath (Join-Path $dest 'commands\loop.md') -Force -ErrorAction SilentlyContinue
|
|
205
|
+
# 2.0.0 prefixed every command with `cohorte-`, which ends the shadowing problem for good.
|
|
206
|
+
# Copy-Item never deletes, so all 13 bare names would survive an upgrade as decoys — and a
|
|
207
|
+
# stale /build is the worst kind: it still dispatches implementers, from a 1.x command file
|
|
208
|
+
# that knows nothing of this core's contract. /drive goes too (it became /cohorte-loop).
|
|
209
|
+
foreach ($c in @('align-ds','audit','brainstorm','build','doctor','drive','fix',
|
|
210
|
+
'init-pipeline','refactor','review','ship','spec','update-pipeline')) {
|
|
211
|
+
Remove-Item -LiteralPath (Join-Path $dest "commands\$c.md") -Force -ErrorAction SilentlyContinue
|
|
212
|
+
}
|
|
204
213
|
# 0.1.19 split the bi-mode questionnaire-researcher into research-agent + questionnaire-architect;
|
|
205
214
|
# copy-over never deletes, so scrub the retired agent lest a dead subagent_type linger.
|
|
206
215
|
Remove-Item -LiteralPath (Join-Path $dest 'agents\questionnaire-researcher.md') -Force -ErrorAction SilentlyContinue
|
|
@@ -224,8 +233,8 @@ try {
|
|
|
224
233
|
|
|
225
234
|
# pipeline capability config is USER-level (vault, Notion DB, kanban boards) — it lives in
|
|
226
235
|
# the user's .claude regardless of install scope. Seed only if neither the consolidated nor
|
|
227
|
-
# the legacy copy exists. Non-interactive here: seeds disabled defaults; /init-pipeline +
|
|
228
|
-
# /update-pipeline wire it (npx's installer offers a quick interview instead).
|
|
236
|
+
# the legacy copy exists. Non-interactive here: seeds disabled defaults; /cohorte-init-pipeline +
|
|
237
|
+
# /cohorte-update-pipeline wire it (npx's installer offers a quick interview instead).
|
|
229
238
|
function Initialize-Config {
|
|
230
239
|
$userClaude = if ($env:CLAUDE_CONFIG_DIR) { $env:CLAUDE_CONFIG_DIR } else { Join-Path $HOME '.claude' }
|
|
231
240
|
$cfg = Join-Path $userClaude 'cohorte.config.yaml'
|
|
@@ -237,11 +246,11 @@ try {
|
|
|
237
246
|
Write-Host " - kept your existing $cfg"
|
|
238
247
|
} elseif ($legacy) {
|
|
239
248
|
Write-Host " - found legacy $legacy — kept as-is (read as a fallback)."
|
|
240
|
-
Write-Host " Run /update-pipeline to migrate it into cohorte.config.yaml + wire the kanban."
|
|
249
|
+
Write-Host " Run /cohorte-update-pipeline to migrate it into cohorte.config.yaml + wire the kanban."
|
|
241
250
|
} else {
|
|
242
251
|
New-Item -ItemType Directory -Force -Path $userClaude | Out-Null
|
|
243
252
|
Copy-Item (Join-Path $src 'profile\cohorte.config.template.yaml') $cfg
|
|
244
|
-
Write-Host " - seeded $cfg (disabled defaults — enable via /init-pipeline or /update-pipeline)"
|
|
253
|
+
Write-Host " - seeded $cfg (disabled defaults — enable via /cohorte-init-pipeline or /cohorte-update-pipeline)"
|
|
245
254
|
}
|
|
246
255
|
}
|
|
247
256
|
|
|
@@ -318,24 +327,24 @@ try {
|
|
|
318
327
|
OK pipeline core installed globally into $dest (version $ver)
|
|
319
328
|
gate hook: $hookState (reads each repo's .claude/gate-config.json; silent where absent)
|
|
320
329
|
|
|
321
|
-
The commands (/init-pipeline, /brainstorm, /build ...) and the review/release agents are now
|
|
330
|
+
The commands (/cohorte-init-pipeline, /cohorte-brainstorm, /cohorte-build ...) and the review/release agents are now
|
|
322
331
|
available in EVERY project on this machine — nothing is copied per repo.
|
|
323
332
|
|
|
324
333
|
Per repo:
|
|
325
334
|
1. Open the project in Claude Code.
|
|
326
|
-
2. Run /init-pipeline — it generates PIPELINE.md, renders the surface agents, writes
|
|
335
|
+
2. Run /cohorte-init-pipeline — it generates PIPELINE.md, renders the surface agents, writes
|
|
327
336
|
.claude/gate-config.json, and drops a committed .claude/pipeline.json pointer so
|
|
328
337
|
teammates know to install the global core ($repoUrl).
|
|
329
|
-
3. Commit PIPELINE.md + .claude/, then /brainstorm to start a feature.
|
|
338
|
+
3. Commit PIPELINE.md + .claude/, then /cohorte-brainstorm to start a feature.
|
|
330
339
|
|
|
331
|
-
Code retrieval (Serena — the default provider /init-pipeline wires per repo):
|
|
340
|
+
Code retrieval (Serena — the default provider /cohorte-init-pipeline wires per repo):
|
|
332
341
|
uv tool install -p 3.13 serena-agent # once per machine
|
|
333
342
|
Make sure the uv tools dir is on PATH (uv tool update-shell) — otherwise the
|
|
334
343
|
registered MCP server silently fails to start.
|
|
335
344
|
|
|
336
345
|
Global kanban config, user-scoped — optional:
|
|
337
346
|
· One consolidated file: ~/.claude/cohorte.config.yaml (don't hand-edit it).
|
|
338
|
-
· /init-pipeline (new project) and /update-pipeline (existing) wire it for you: creating +
|
|
347
|
+
· /cohorte-init-pipeline (new project) and /cohorte-update-pipeline (existing) wire it for you: creating +
|
|
339
348
|
syncing an Obsidian kanban board of the pipeline in your shared vault.
|
|
340
349
|
"@
|
|
341
350
|
return
|
|
@@ -356,11 +365,11 @@ OK pipeline core installed into $dest (version $ver)
|
|
|
356
365
|
|
|
357
366
|
Next:
|
|
358
367
|
1. Open the project in Claude Code.
|
|
359
|
-
2. Run /init-pipeline — it detects your stack, asks the gaps, and generates
|
|
368
|
+
2. Run /cohorte-init-pipeline — it detects your stack, asks the gaps, and generates
|
|
360
369
|
PIPELINE.md + renders one implementer agent per surface.
|
|
361
|
-
3. Commit PIPELINE.md, then /brainstorm to start a feature.
|
|
370
|
+
3. Commit PIPELINE.md, then /cohorte-brainstorm to start a feature.
|
|
362
371
|
|
|
363
|
-
Code retrieval (Serena — the default provider /init-pipeline wires per repo):
|
|
372
|
+
Code retrieval (Serena — the default provider /cohorte-init-pipeline wires per repo):
|
|
364
373
|
uv tool install -p 3.13 serena-agent # once per machine
|
|
365
374
|
Make sure the uv tools dir is on PATH (uv tool update-shell) — otherwise the
|
|
366
375
|
registered MCP server silently fails to start.
|
|
@@ -378,7 +387,7 @@ Prefer one shared core across all your repos? Re-run with -Global.
|
|
|
378
387
|
Write-Host @"
|
|
379
388
|
|
|
380
389
|
OK core refreshed to $ver. Your PIPELINE.md, rendered surface agents, gate-config.json and
|
|
381
|
-
settings.json were left as-is. Re-run /init-pipeline if your stack changed.
|
|
390
|
+
settings.json were left as-is. Re-run /cohorte-init-pipeline if your stack changed.
|
|
382
391
|
"@
|
|
383
392
|
}
|
|
384
393
|
} finally {
|
package/install.sh
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
# sh install.sh --update --global
|
|
17
17
|
#
|
|
18
18
|
# Per-project install copies the core into <target>/.claude; global install copies it once
|
|
19
|
-
# into ~/.claude and registers the gate hook there. Either way you then run `/init-pipeline`
|
|
19
|
+
# into ~/.claude and registers the gate hook there. Either way you then run `/cohorte-init-pipeline`
|
|
20
20
|
# in each repo to generate PIPELINE.md + render the surface agents. Update refreshes ONLY the
|
|
21
21
|
# stack-agnostic files; generated profiles, rendered agents, gate-config.json and any project
|
|
22
22
|
# settings.json are left untouched.
|
|
@@ -108,8 +108,10 @@ copy_core() {
|
|
|
108
108
|
cp "$src/scripts/telemetry-send.sh" "$dest/pipeline/scripts/"
|
|
109
109
|
cp "$src/scripts/preflight.sh" "$dest/pipeline/scripts/"
|
|
110
110
|
cp "$src/scripts/loop.sh" "$dest/pipeline/scripts/"
|
|
111
|
+
cp "$src/scripts/loop-detach.sh" "$dest/pipeline/scripts/"
|
|
111
112
|
chmod +x "$dest/pipeline/scripts/kanban-move.sh" "$dest/pipeline/scripts/telemetry-send.sh" \
|
|
112
|
-
"$dest/pipeline/scripts/preflight.sh" "$dest/pipeline/scripts/loop.sh"
|
|
113
|
+
"$dest/pipeline/scripts/preflight.sh" "$dest/pipeline/scripts/loop.sh" \
|
|
114
|
+
"$dest/pipeline/scripts/loop-detach.sh" 2>/dev/null || true
|
|
113
115
|
cp "$src/core/agents/implementer.template.md" "$dest/pipeline/"
|
|
114
116
|
[ -f "$src/CHANGELOG.md" ] && cp "$src/CHANGELOG.md" "$dest/pipeline/"
|
|
115
117
|
printf '%s\n' "$ver" > "$dest/pipeline/VERSION"
|
|
@@ -161,6 +163,14 @@ copy_fixed_agents() {
|
|
|
161
163
|
# 1.6.0 renamed /loop → /drive: Claude Code's own built-in /loop shadowed ours, so a leftover
|
|
162
164
|
# commands/loop.md is a command the user can never reach — scrub it rather than leave a decoy.
|
|
163
165
|
rm -f "$dest/commands/loop.md"
|
|
166
|
+
# 2.0.0 prefixed every command with `cohorte-`, which ends the shadowing problem for good.
|
|
167
|
+
# Copy-over never deletes, so all 13 bare names would survive an upgrade as decoys — and a
|
|
168
|
+
# stale /build is the worst kind: it still dispatches implementers, from a 1.x command file
|
|
169
|
+
# that knows nothing of this core's contract. /drive goes too (it became /cohorte-loop).
|
|
170
|
+
for c in align-ds audit brainstorm build doctor drive fix init-pipeline \
|
|
171
|
+
refactor review ship spec update-pipeline; do
|
|
172
|
+
rm -f "$dest/commands/$c.md"
|
|
173
|
+
done
|
|
164
174
|
# 0.1.19 split the bi-mode questionnaire-researcher into research-agent + questionnaire-architect;
|
|
165
175
|
# copy-over never deletes, so scrub the retired agent lest a dead subagent_type linger.
|
|
166
176
|
rm -f "$dest/agents/questionnaire-researcher.md"
|
|
@@ -186,7 +196,7 @@ scrub_research_questionnaire() {
|
|
|
186
196
|
# pipeline capability config is USER-level (vault, Notion DB, kanban boards) — it lives in
|
|
187
197
|
# ~/.claude regardless of install scope. Seed it only if neither the consolidated nor the
|
|
188
198
|
# legacy copy exists. This piped installer is non-interactive: it seeds disabled defaults;
|
|
189
|
-
# /init-pipeline + /update-pipeline wire it (npx's installer offers a quick interview instead).
|
|
199
|
+
# /cohorte-init-pipeline + /cohorte-update-pipeline wire it (npx's installer offers a quick interview instead).
|
|
190
200
|
seed_config() {
|
|
191
201
|
base="${CLAUDE_CONFIG_DIR:-$HOME/.claude}"
|
|
192
202
|
cfg="$base/cohorte.config.yaml"
|
|
@@ -198,11 +208,11 @@ seed_config() {
|
|
|
198
208
|
echo " · kept your existing $cfg"
|
|
199
209
|
elif [ -n "$legacy" ]; then
|
|
200
210
|
echo " · found legacy $legacy — kept as-is (read as a fallback)."
|
|
201
|
-
echo " Run /update-pipeline to migrate it into cohorte.config.yaml + wire the kanban."
|
|
211
|
+
echo " Run /cohorte-update-pipeline to migrate it into cohorte.config.yaml + wire the kanban."
|
|
202
212
|
else
|
|
203
213
|
mkdir -p "$base"
|
|
204
214
|
cp "$src/profile/cohorte.config.template.yaml" "$cfg"
|
|
205
|
-
echo " · seeded $cfg (disabled defaults — enable via /init-pipeline or /update-pipeline)"
|
|
215
|
+
echo " · seeded $cfg (disabled defaults — enable via /cohorte-init-pipeline or /cohorte-update-pipeline)"
|
|
206
216
|
fi
|
|
207
217
|
}
|
|
208
218
|
|
|
@@ -290,24 +300,24 @@ if [ "$scope" = "global" ]; then
|
|
|
290
300
|
✓ pipeline core installed globally into $dest (version $ver)
|
|
291
301
|
gate hook: $hook_state (reads each repo's .claude/gate-config.json; silent where absent)
|
|
292
302
|
|
|
293
|
-
The commands (/init-pipeline, /brainstorm, /build …) and the review/release agents are now
|
|
303
|
+
The commands (/cohorte-init-pipeline, /cohorte-brainstorm, /cohorte-build …) and the review/release agents are now
|
|
294
304
|
available in EVERY project on this machine — nothing is copied per repo.
|
|
295
305
|
|
|
296
306
|
Per repo:
|
|
297
307
|
1. Open the project in Claude Code.
|
|
298
|
-
2. Run /init-pipeline — it generates PIPELINE.md, renders the surface agents, writes
|
|
308
|
+
2. Run /cohorte-init-pipeline — it generates PIPELINE.md, renders the surface agents, writes
|
|
299
309
|
.claude/gate-config.json, and drops a committed .claude/pipeline.json pointer so
|
|
300
310
|
teammates know to install the global core ($REPO_URL).
|
|
301
|
-
3. Commit PIPELINE.md + .claude/, then /brainstorm to start a feature.
|
|
311
|
+
3. Commit PIPELINE.md + .claude/, then /cohorte-brainstorm to start a feature.
|
|
302
312
|
|
|
303
|
-
Code retrieval (Serena — the default provider /init-pipeline wires per repo):
|
|
313
|
+
Code retrieval (Serena — the default provider /cohorte-init-pipeline wires per repo):
|
|
304
314
|
uv tool install -p 3.13 serena-agent # once per machine
|
|
305
315
|
Make sure ~/.local/bin is on PATH (uv tool update-shell) — otherwise the
|
|
306
316
|
registered MCP server silently fails to start.
|
|
307
317
|
|
|
308
318
|
Global kanban config, user-scoped — optional:
|
|
309
319
|
· One consolidated file: ~/.claude/cohorte.config.yaml (don't hand-edit it).
|
|
310
|
-
· /init-pipeline (new project) and /update-pipeline (existing) wire it for you: creating +
|
|
320
|
+
· /cohorte-init-pipeline (new project) and /cohorte-update-pipeline (existing) wire it for you: creating +
|
|
311
321
|
syncing an Obsidian kanban board of the pipeline in your shared vault.
|
|
312
322
|
EOF
|
|
313
323
|
exit 0
|
|
@@ -326,11 +336,11 @@ if [ "$mode" = "install" ]; then
|
|
|
326
336
|
|
|
327
337
|
Next:
|
|
328
338
|
1. Open the project in Claude Code.
|
|
329
|
-
2. Run /init-pipeline — it detects your stack, asks the gaps, and generates
|
|
339
|
+
2. Run /cohorte-init-pipeline — it detects your stack, asks the gaps, and generates
|
|
330
340
|
PIPELINE.md + renders one implementer agent per surface.
|
|
331
|
-
3. Commit PIPELINE.md, then /brainstorm to start a feature.
|
|
341
|
+
3. Commit PIPELINE.md, then /cohorte-brainstorm to start a feature.
|
|
332
342
|
|
|
333
|
-
Code retrieval (Serena — the default provider /init-pipeline wires per repo):
|
|
343
|
+
Code retrieval (Serena — the default provider /cohorte-init-pipeline wires per repo):
|
|
334
344
|
uv tool install -p 3.13 serena-agent # once per machine
|
|
335
345
|
Make sure ~/.local/bin is on PATH (uv tool update-shell) — otherwise the
|
|
336
346
|
registered MCP server silently fails to start.
|
|
@@ -346,6 +356,6 @@ else
|
|
|
346
356
|
cat <<EOF
|
|
347
357
|
|
|
348
358
|
✓ core refreshed to $ver. Your PIPELINE.md, rendered surface agents, gate-config.json and
|
|
349
|
-
settings.json were left as-is. Re-run /init-pipeline if your stack changed.
|
|
359
|
+
settings.json were left as-is. Re-run /cohorte-init-pipeline if your stack changed.
|
|
350
360
|
EOF
|
|
351
361
|
fi
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cohorte",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Portable, stack-agnostic multi-agent development pipeline for Claude Code — install the core, run /init-pipeline, and it adapts to your project's stack.",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Portable, stack-agnostic multi-agent development pipeline for Claude Code — install the core, run /cohorte-init-pipeline, and it adapts to your project's stack.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"cohorte": "bin/cli.js"
|
|
7
7
|
},
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# PIPELINE.md — <PROJECT_NAME> profile
|
|
2
2
|
|
|
3
|
-
> **Generated by `/init-pipeline`.** This is the project profile: the single place the
|
|
3
|
+
> **Generated by `/cohorte-init-pipeline`.** This is the project profile: the single place the
|
|
4
4
|
> portable multi-agent pipeline reads for everything stack-specific. The pipeline core
|
|
5
5
|
> under `.claude/` is generic and references THIS file by section — keep project facts
|
|
6
|
-
> here, never hardcoded into agent prompts. Kept current by `/update-pipeline` (reconcile:
|
|
6
|
+
> here, never hardcoded into agent prompts. Kept current by `/cohorte-update-pipeline` (reconcile:
|
|
7
7
|
> new fields are topped up, your values never overwritten). Rendered agent files are
|
|
8
8
|
> regenerated from this profile on every reconcile — customize agents through §Conventions
|
|
9
9
|
> here, never by editing the agent files. Free-form notes belong in `CLAUDE.md`.
|
|
@@ -36,15 +36,15 @@ repo:
|
|
|
36
36
|
# wired. serena = live LSP symbol navigation (default, no index to maintain);
|
|
37
37
|
# graphify = persistent tree-sitter knowledge graph over code + docs (needs an
|
|
38
38
|
# index step + rescans); none = agents fall back to Grep/Glob/Read.
|
|
39
|
-
# Registered by /init-pipeline as a project-scope MCP server (committed .mcp.json).
|
|
39
|
+
# Registered by /cohorte-init-pipeline as a project-scope MCP server (committed .mcp.json).
|
|
40
40
|
retrieval:
|
|
41
41
|
provider: serena # serena | graphify | none
|
|
42
42
|
|
|
43
43
|
# ── surfaces ────────────────────────────────────────────────────────────────
|
|
44
|
-
# One entry per independently-implemented code area. /build dispatches ONE
|
|
44
|
+
# One entry per independently-implemented code area. /cohorte-build dispatches ONE
|
|
45
45
|
# implementer agent per surface, in parallel. Each surface is rendered by
|
|
46
|
-
# /init-pipeline into its own agent file (agent field) with the tools listed.
|
|
47
|
-
# This list GROWS automatically: /build §1.5 adds a surface (and renders its
|
|
46
|
+
# /cohorte-init-pipeline into its own agent file (agent field) with the tools listed.
|
|
47
|
+
# This list GROWS automatically: /cohorte-build §1.5 adds a surface (and renders its
|
|
48
48
|
# agent) when a spec touches a tree no surface owns, or splits a bottleneck
|
|
49
49
|
# surface into specialized sub-surfaces. Keep one owner per tree; shared code
|
|
50
50
|
# (routing/state/DS) is its own single-owner surface. See SCHEMA.md §Specialization.
|
|
@@ -61,7 +61,7 @@ surfaces:
|
|
|
61
61
|
test_cmd: pnpm --filter api test
|
|
62
62
|
# Bridled variants — what agents actually RUN (dot reporter / failures-only /
|
|
63
63
|
# --quiet), so a green run costs lines, not pages. "" ⇒ callers fall back to
|
|
64
|
-
# `<cmd> 2>&1 | tail -40`. /init-pipeline asks for these; never store a bare
|
|
64
|
+
# `<cmd> 2>&1 | tail -40`. /cohorte-init-pipeline asks for these; never store a bare
|
|
65
65
|
# `pnpm test` as the thing agents execute.
|
|
66
66
|
test_quiet_cmd: pnpm --filter api test --reporter=dot
|
|
67
67
|
lint_cmd: pnpm --filter api lint
|
|
@@ -90,7 +90,7 @@ surfaces:
|
|
|
90
90
|
|
|
91
91
|
# ── contract (the only cross-surface sync channel) ──────────────────────────
|
|
92
92
|
contract:
|
|
93
|
-
enabled: <true | false> # false ⇒ no shared contract; skip §2 of /build
|
|
93
|
+
enabled: <true | false> # false ⇒ no shared contract; skip §2 of /cohorte-build
|
|
94
94
|
mechanism: <shared-types-zod | openapi | protobuf | json-schema | none>
|
|
95
95
|
path: packages/shared-types/src # where <feature_id>.<ext> is authored
|
|
96
96
|
ext: ts
|
|
@@ -106,7 +106,7 @@ commands:
|
|
|
106
106
|
format: pnpm format
|
|
107
107
|
typecheck: pnpm check-types
|
|
108
108
|
test: pnpm test
|
|
109
|
-
test_quiet: pnpm test --reporter=dot # bridled variant — what the /review preflight runs
|
|
109
|
+
test_quiet: pnpm test --reporter=dot # bridled variant — what the /cohorte-review preflight runs
|
|
110
110
|
# migration commands — omit / leave "" if the project has no DB migrations
|
|
111
111
|
migrate: "cd apps/api && node ace migration:run"
|
|
112
112
|
make_migration: "cd apps/api && node ace make:migration"
|
|
@@ -119,11 +119,11 @@ rbac:
|
|
|
119
119
|
|
|
120
120
|
# ── design system (optional) ────────────────────────────────────────────────
|
|
121
121
|
design:
|
|
122
|
-
enabled: <true | false> # false ⇒ /align-ds + design gates are no-ops
|
|
122
|
+
enabled: <true | false> # false ⇒ /cohorte-align-ds + design gates are no-ops
|
|
123
123
|
provider: <claude-design | figma | none>
|
|
124
124
|
design_system_project: <uuid-or-id> # the UI-kit source of truth
|
|
125
125
|
design_project: none # legacy fallback for bare-filename design_files only; keep `none` — new specs use full links that carry their own project, so nothing here goes stale on a DS rebuild
|
|
126
|
-
snapshot_dir: apps/web/design-reference # committed DS snapshot for /align-ds diff
|
|
126
|
+
snapshot_dir: apps/web/design-reference # committed DS snapshot for /cohorte-align-ds diff
|
|
127
127
|
direction: design-to-code # NEVER push code→design for a curated DS
|
|
128
128
|
ui_kit_path: apps/web/src/components/ui
|
|
129
129
|
tokens_path: apps/web/src/index.css
|
|
@@ -166,7 +166,8 @@ gate:
|
|
|
166
166
|
- "docker compose"
|
|
167
167
|
# Phase gate: review dispatches require a fresh `.claude/preflight.ok` stamp,
|
|
168
168
|
# written by pipeline/scripts/preflight.sh when typecheck+lint+tests are green —
|
|
169
|
-
# gate.py "ask"s the dispatch when the stamp is missing, stale, or
|
|
169
|
+
# gate.py "ask"s the dispatch when the stamp is missing, stale, or the code changed since.
|
|
170
|
+
# The stamp is local: keep `.claude/preflight.ok` gitignored, never committed.
|
|
170
171
|
preflight:
|
|
171
172
|
enabled: true
|
|
172
173
|
agents: [review] # subagent_types the stamp gates
|
|
@@ -176,7 +177,7 @@ gate:
|
|
|
176
177
|
|
|
177
178
|
> **Note.** The **kanban** board link is **user-scoped** — NOT configured here. Its facts live in the
|
|
178
179
|
> consolidated `~/.claude/cohorte.config.yaml`, read at runtime (the kanban board is keyed by this
|
|
179
|
-
> profile's `name`). This project profile only governs the dev pipeline (`/brainstorm…/ship`).
|
|
180
|
+
> profile's `name`). This project profile only governs the dev pipeline (`/cohorte-brainstorm…/cohorte-ship`).
|
|
180
181
|
|
|
181
182
|
---
|
|
182
183
|
|
|
@@ -205,18 +206,18 @@ gate:
|
|
|
205
206
|
|
|
206
207
|
---
|
|
207
208
|
|
|
208
|
-
## Design brief note (feeds `/spec` §8 and Claude Design)
|
|
209
|
+
## Design brief note (feeds `/cohorte-spec` §8 and Claude Design)
|
|
209
210
|
|
|
210
211
|
- <design system name + primitives to use · mobile-first · copy language · brand/theming constraints>
|
|
211
212
|
- A feature lists its design pages in the spec front-matter `design_files` as **full links** of the form
|
|
212
213
|
`https://claude.ai/design/p/<projectId>?file=<file>` — each carries its own project (`/p/<projectId>`)
|
|
213
214
|
and page (`?file=`), so an agent extracts both and reads it via `DesignSync get_file(<projectId>,
|
|
214
|
-
<file>)`. Paste the link at `/build`'s design gate. No stored project id ⇒ a design-system rebuild
|
|
215
|
+
<file>)`. Paste the link at `/cohorte-build`'s design gate. No stored project id ⇒ a design-system rebuild
|
|
215
216
|
(new project) just means pasting the new links. (Bare file names are legacy, resolved in `design_project`.)
|
|
216
217
|
|
|
217
218
|
---
|
|
218
219
|
|
|
219
|
-
## Personas for `/brainstorm` (optional — the panel)
|
|
220
|
+
## Personas for `/cohorte-brainstorm` (optional — the panel)
|
|
220
221
|
|
|
221
222
|
<Panel members with a job AND a personality who challenge the idea from their angle and
|
|
222
223
|
disagree with each other. Include a role-coverage guard if `rbac.enabled`. Example:>
|