compound-agent 1.3.0 → 1.3.2
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 +36 -0
- package/README.md +2 -0
- package/dist/cli.js +612 -326
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import { getLlama, resolveModelFile } from 'node-llama-cpp';
|
|
4
4
|
import { mkdirSync, writeFileSync, statSync, unlinkSync, existsSync, readFileSync, copyFileSync, chmodSync, readdirSync } from 'fs';
|
|
5
|
-
import { homedir } from 'os';
|
|
5
|
+
import { homedir, tmpdir } from 'os';
|
|
6
6
|
import path, { join, dirname, resolve, relative } from 'path';
|
|
7
7
|
import * as fs from 'fs/promises';
|
|
8
8
|
import { readFile, mkdir, appendFile, writeFile, chmod, rm, rename, readdir } from 'fs/promises';
|
|
9
9
|
import { createHash } from 'crypto';
|
|
10
10
|
import { z } from 'zod';
|
|
11
11
|
import { createRequire } from 'module';
|
|
12
|
-
import { execSync, execFileSync } from 'child_process';
|
|
12
|
+
import { execSync, execFileSync, spawn } from 'child_process';
|
|
13
13
|
import chalk from 'chalk';
|
|
14
14
|
|
|
15
15
|
// src/cli-utils.ts
|
|
@@ -1135,6 +1135,171 @@ function registerCompoundCommands(program2) {
|
|
|
1135
1135
|
var _require = createRequire(import.meta.url);
|
|
1136
1136
|
var _pkg = _require("../package.json");
|
|
1137
1137
|
var VERSION = _pkg.version;
|
|
1138
|
+
var SAMPLE_RATE = 22050;
|
|
1139
|
+
var BITS = 16;
|
|
1140
|
+
var MAX_AMP = 24576;
|
|
1141
|
+
var NOTE = {
|
|
1142
|
+
C3: 131,
|
|
1143
|
+
E3: 165,
|
|
1144
|
+
G3: 196,
|
|
1145
|
+
C4: 262,
|
|
1146
|
+
E4: 330,
|
|
1147
|
+
G4: 392,
|
|
1148
|
+
C5: 523,
|
|
1149
|
+
E5: 659,
|
|
1150
|
+
G5: 784,
|
|
1151
|
+
C6: 1047
|
|
1152
|
+
};
|
|
1153
|
+
function envelope(i, total, attack, release) {
|
|
1154
|
+
if (i < attack) return i / attack;
|
|
1155
|
+
if (i > total - release) return (total - i) / release;
|
|
1156
|
+
return 1;
|
|
1157
|
+
}
|
|
1158
|
+
function tone(freq, durationMs, amp = 1) {
|
|
1159
|
+
const samples = Math.floor(SAMPLE_RATE * durationMs / 1e3);
|
|
1160
|
+
const attack = Math.min(Math.floor(samples * 0.05), 200);
|
|
1161
|
+
const release = Math.min(Math.floor(samples * 0.15), 400);
|
|
1162
|
+
const out2 = [];
|
|
1163
|
+
for (let i = 0; i < samples; i++) {
|
|
1164
|
+
const env = envelope(i, samples, attack, release);
|
|
1165
|
+
out2.push(Math.sin(2 * Math.PI * freq * i / SAMPLE_RATE) * env * amp);
|
|
1166
|
+
}
|
|
1167
|
+
return out2;
|
|
1168
|
+
}
|
|
1169
|
+
function chord(freqs, durationMs, amp = 1) {
|
|
1170
|
+
const tones = freqs.map((f) => tone(f, durationMs, 1));
|
|
1171
|
+
const len = tones[0].length;
|
|
1172
|
+
const out2 = [];
|
|
1173
|
+
const scale = amp / freqs.length;
|
|
1174
|
+
for (let i = 0; i < len; i++) {
|
|
1175
|
+
let sum = 0;
|
|
1176
|
+
for (const t of tones) sum += t[i];
|
|
1177
|
+
out2.push(sum * scale);
|
|
1178
|
+
}
|
|
1179
|
+
return out2;
|
|
1180
|
+
}
|
|
1181
|
+
function silence(durationMs) {
|
|
1182
|
+
return new Array(Math.floor(SAMPLE_RATE * durationMs / 1e3)).fill(0);
|
|
1183
|
+
}
|
|
1184
|
+
function composeMelody() {
|
|
1185
|
+
const samples = [];
|
|
1186
|
+
samples.push(...tone(NOTE.C3, 250, 0.3));
|
|
1187
|
+
samples.push(...silence(150));
|
|
1188
|
+
samples.push(...tone(NOTE.C3, 250, 0.35));
|
|
1189
|
+
samples.push(...silence(100));
|
|
1190
|
+
samples.push(...tone(NOTE.E3, 200, 0.3));
|
|
1191
|
+
samples.push(...silence(80));
|
|
1192
|
+
samples.push(...tone(NOTE.C4, 140, 0.45));
|
|
1193
|
+
samples.push(...silence(30));
|
|
1194
|
+
samples.push(...tone(NOTE.E4, 140, 0.5));
|
|
1195
|
+
samples.push(...silence(30));
|
|
1196
|
+
samples.push(...tone(NOTE.G4, 140, 0.5));
|
|
1197
|
+
samples.push(...silence(30));
|
|
1198
|
+
samples.push(...tone(NOTE.C5, 160, 0.55));
|
|
1199
|
+
samples.push(...silence(30));
|
|
1200
|
+
samples.push(...tone(NOTE.E5, 160, 0.55));
|
|
1201
|
+
samples.push(...silence(30));
|
|
1202
|
+
samples.push(...tone(NOTE.G5, 180, 0.6));
|
|
1203
|
+
samples.push(...silence(60));
|
|
1204
|
+
samples.push(...tone(NOTE.C4, 100, 0.4));
|
|
1205
|
+
samples.push(...tone(NOTE.E4, 100, 0.45));
|
|
1206
|
+
samples.push(...tone(NOTE.G4, 100, 0.45));
|
|
1207
|
+
samples.push(...tone(NOTE.C5, 120, 0.5));
|
|
1208
|
+
samples.push(...tone(NOTE.E5, 120, 0.55));
|
|
1209
|
+
samples.push(...tone(NOTE.G5, 140, 0.6));
|
|
1210
|
+
samples.push(...silence(60));
|
|
1211
|
+
samples.push(...tone(NOTE.C6, 80, 0.3));
|
|
1212
|
+
samples.push(...silence(40));
|
|
1213
|
+
samples.push(...tone(NOTE.G5, 80, 0.35));
|
|
1214
|
+
samples.push(...silence(40));
|
|
1215
|
+
samples.push(...tone(NOTE.C6, 80, 0.3));
|
|
1216
|
+
samples.push(...silence(40));
|
|
1217
|
+
samples.push(...tone(NOTE.E5, 100, 0.35));
|
|
1218
|
+
samples.push(...silence(60));
|
|
1219
|
+
samples.push(...chord([NOTE.C4, NOTE.E4, NOTE.G4], 600, 0.7));
|
|
1220
|
+
samples.push(...chord([NOTE.C4, NOTE.E4, NOTE.G4, NOTE.C5], 500, 0.6));
|
|
1221
|
+
samples.push(...chord([NOTE.C3, NOTE.G3, NOTE.C4], 1200, 0.35));
|
|
1222
|
+
return samples;
|
|
1223
|
+
}
|
|
1224
|
+
function encodeWav(samples) {
|
|
1225
|
+
const dataSize = samples.length * (BITS / 8);
|
|
1226
|
+
const fileSize = 44 + dataSize;
|
|
1227
|
+
const buf = Buffer.alloc(fileSize);
|
|
1228
|
+
buf.write("RIFF", 0);
|
|
1229
|
+
buf.writeUInt32LE(fileSize - 8, 4);
|
|
1230
|
+
buf.write("WAVE", 8);
|
|
1231
|
+
buf.write("fmt ", 12);
|
|
1232
|
+
buf.writeUInt32LE(16, 16);
|
|
1233
|
+
buf.writeUInt16LE(1, 20);
|
|
1234
|
+
buf.writeUInt16LE(1, 22);
|
|
1235
|
+
buf.writeUInt32LE(SAMPLE_RATE, 24);
|
|
1236
|
+
buf.writeUInt32LE(SAMPLE_RATE * BITS / 8, 28);
|
|
1237
|
+
buf.writeUInt16LE(BITS / 8, 32);
|
|
1238
|
+
buf.writeUInt16LE(BITS, 34);
|
|
1239
|
+
buf.write("data", 36);
|
|
1240
|
+
buf.writeUInt32LE(dataSize, 40);
|
|
1241
|
+
let offset = 44;
|
|
1242
|
+
for (const s of samples) {
|
|
1243
|
+
const clamped = Math.max(-1, Math.min(1, s));
|
|
1244
|
+
buf.writeInt16LE(Math.round(clamped * MAX_AMP), offset);
|
|
1245
|
+
offset += 2;
|
|
1246
|
+
}
|
|
1247
|
+
return buf;
|
|
1248
|
+
}
|
|
1249
|
+
function spawnPlayer(filePath) {
|
|
1250
|
+
try {
|
|
1251
|
+
switch (process.platform) {
|
|
1252
|
+
case "darwin":
|
|
1253
|
+
return spawn("afplay", [filePath], { stdio: "ignore", detached: true });
|
|
1254
|
+
case "linux":
|
|
1255
|
+
return spawn("aplay", ["-q", filePath], { stdio: "ignore", detached: true });
|
|
1256
|
+
case "win32":
|
|
1257
|
+
return spawn("powershell", [
|
|
1258
|
+
"-c",
|
|
1259
|
+
`(New-Object Media.SoundPlayer '${filePath}').PlaySync()`
|
|
1260
|
+
], { stdio: "ignore", detached: true });
|
|
1261
|
+
default:
|
|
1262
|
+
return null;
|
|
1263
|
+
}
|
|
1264
|
+
} catch {
|
|
1265
|
+
return null;
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
function playBannerAudio() {
|
|
1269
|
+
try {
|
|
1270
|
+
const wav = encodeWav(composeMelody());
|
|
1271
|
+
const tmpPath = join(tmpdir(), `ca-banner-${process.pid}.wav`);
|
|
1272
|
+
writeFileSync(tmpPath, wav);
|
|
1273
|
+
const proc = spawnPlayer(tmpPath);
|
|
1274
|
+
if (!proc) {
|
|
1275
|
+
try {
|
|
1276
|
+
unlinkSync(tmpPath);
|
|
1277
|
+
} catch {
|
|
1278
|
+
}
|
|
1279
|
+
return null;
|
|
1280
|
+
}
|
|
1281
|
+
proc.unref();
|
|
1282
|
+
const cleanup2 = () => {
|
|
1283
|
+
try {
|
|
1284
|
+
proc.kill();
|
|
1285
|
+
} catch {
|
|
1286
|
+
}
|
|
1287
|
+
try {
|
|
1288
|
+
unlinkSync(tmpPath);
|
|
1289
|
+
} catch {
|
|
1290
|
+
}
|
|
1291
|
+
};
|
|
1292
|
+
proc.on("exit", () => {
|
|
1293
|
+
try {
|
|
1294
|
+
unlinkSync(tmpPath);
|
|
1295
|
+
} catch {
|
|
1296
|
+
}
|
|
1297
|
+
});
|
|
1298
|
+
return { stop: cleanup2 };
|
|
1299
|
+
} catch {
|
|
1300
|
+
return null;
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1138
1303
|
|
|
1139
1304
|
// src/setup/banner.ts
|
|
1140
1305
|
var W = 62;
|
|
@@ -1316,6 +1481,7 @@ async function playInstallBanner() {
|
|
|
1316
1481
|
const ps = [];
|
|
1317
1482
|
const write = (s) => process.stdout.write(s);
|
|
1318
1483
|
write("\x1B[?25l\x1B[2J\x1B[H");
|
|
1484
|
+
const audio = playBannerAudio();
|
|
1319
1485
|
const restoreCursor = () => process.stdout.write("\x1B[?25h\x1B[0m");
|
|
1320
1486
|
process.on("exit", restoreCursor);
|
|
1321
1487
|
try {
|
|
@@ -1327,7 +1493,7 @@ async function playInstallBanner() {
|
|
|
1327
1493
|
put(cvs, nx(CENTER), ny(CENTER), seedCh[f % 4], seedCo[f % 4]);
|
|
1328
1494
|
write(flush(cvs));
|
|
1329
1495
|
write(`
|
|
1330
|
-
${CO.DIM}Seed detected
|
|
1496
|
+
${CO.DIM}Seed detected...\x1B[K${CO.VOID}
|
|
1331
1497
|
`);
|
|
1332
1498
|
await sleep(60);
|
|
1333
1499
|
}
|
|
@@ -1374,7 +1540,7 @@ async function playInstallBanner() {
|
|
|
1374
1540
|
let active = 0;
|
|
1375
1541
|
for (let i = 0; i < nc; i++) if (isGrown[i]) active++;
|
|
1376
1542
|
write(`
|
|
1377
|
-
\x1B[0;35mNodes \x1B[1;36m${active}\x1B[0;35m/${nc}\x1B[0m \x1B[0;90mGrowing neural tendrils...\x1B[0m
|
|
1543
|
+
\x1B[0;35mNodes \x1B[1;36m${active}\x1B[0;35m/${nc}\x1B[0m \x1B[0;90mGrowing neural tendrils...\x1B[K\x1B[0m
|
|
1378
1544
|
`);
|
|
1379
1545
|
await sleep(40);
|
|
1380
1546
|
}
|
|
@@ -1397,7 +1563,7 @@ async function playInstallBanner() {
|
|
|
1397
1563
|
renderParticles(cvs, ps, f);
|
|
1398
1564
|
write(flush(cvs));
|
|
1399
1565
|
write(`
|
|
1400
|
-
${CO.SETTLED}Crystallizing pathways
|
|
1566
|
+
${CO.SETTLED}Crystallizing pathways...\x1B[K${CO.VOID}
|
|
1401
1567
|
`);
|
|
1402
1568
|
await sleep(60);
|
|
1403
1569
|
}
|
|
@@ -1473,6 +1639,7 @@ async function playInstallBanner() {
|
|
|
1473
1639
|
await sleep(120);
|
|
1474
1640
|
}
|
|
1475
1641
|
} finally {
|
|
1642
|
+
audio?.stop();
|
|
1476
1643
|
process.removeListener("exit", restoreCursor);
|
|
1477
1644
|
restoreCursor();
|
|
1478
1645
|
write("\n");
|
|
@@ -1489,6 +1656,30 @@ function checkBeadsAvailable() {
|
|
|
1489
1656
|
};
|
|
1490
1657
|
}
|
|
1491
1658
|
}
|
|
1659
|
+
function checkBeadsInitialized(repoRoot) {
|
|
1660
|
+
return existsSync(join(repoRoot, ".beads"));
|
|
1661
|
+
}
|
|
1662
|
+
function checkBeadsHealthy(repoRoot) {
|
|
1663
|
+
try {
|
|
1664
|
+
execSync("bd doctor", { cwd: repoRoot, shell: "/bin/sh", stdio: "pipe", encoding: "utf-8" });
|
|
1665
|
+
return { healthy: true };
|
|
1666
|
+
} catch (e) {
|
|
1667
|
+
const msg = e instanceof Error && "stderr" in e ? String(e.stderr).trim() : "bd doctor failed";
|
|
1668
|
+
return { healthy: false, message: msg };
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
function runFullBeadsCheck(repoRoot) {
|
|
1672
|
+
const cli = checkBeadsAvailable();
|
|
1673
|
+
if (!cli.available) {
|
|
1674
|
+
return { cliAvailable: false, initialized: false, healthy: false, healthMessage: cli.message };
|
|
1675
|
+
}
|
|
1676
|
+
const initialized = checkBeadsInitialized(repoRoot);
|
|
1677
|
+
if (!initialized) {
|
|
1678
|
+
return { cliAvailable: true, initialized: false, healthy: false };
|
|
1679
|
+
}
|
|
1680
|
+
const health = checkBeadsHealthy(repoRoot);
|
|
1681
|
+
return { cliAvailable: true, initialized: true, healthy: health.healthy, healthMessage: health.message };
|
|
1682
|
+
}
|
|
1492
1683
|
|
|
1493
1684
|
// src/memory/capture/quality.ts
|
|
1494
1685
|
var DEFAULT_SIMILARITY_THRESHOLD = 0.8;
|
|
@@ -2562,6 +2753,22 @@ function printPnpmConfigStatus(result) {
|
|
|
2562
2753
|
console.log(` pnpm config: Added onlyBuiltDependencies [${result.added.join(", ")}]`);
|
|
2563
2754
|
}
|
|
2564
2755
|
}
|
|
2756
|
+
function printBeadsFullStatus(check) {
|
|
2757
|
+
console.log(` Beads CLI: ${check.cliAvailable ? "OK" : "not found"}`);
|
|
2758
|
+
if (check.cliAvailable) {
|
|
2759
|
+
console.log(` Beads repo: ${check.initialized ? "OK" : "not initialized (run: bd init)"}`);
|
|
2760
|
+
if (check.initialized) {
|
|
2761
|
+
console.log(` Beads health: ${check.healthy ? "OK" : `issues found${check.healthMessage ? ` \u2014 ${check.healthMessage}` : ""}`}`);
|
|
2762
|
+
}
|
|
2763
|
+
}
|
|
2764
|
+
}
|
|
2765
|
+
function printScopeStatus(scope) {
|
|
2766
|
+
if (scope.isUserScope) {
|
|
2767
|
+
console.log(" Scope: user-scope (reduced compounding value)");
|
|
2768
|
+
} else {
|
|
2769
|
+
console.log(" Scope: OK (repository scope)");
|
|
2770
|
+
}
|
|
2771
|
+
}
|
|
2565
2772
|
async function runStatus(repoRoot) {
|
|
2566
2773
|
const agentsDir = join(repoRoot, ".claude", "agents", "compound");
|
|
2567
2774
|
const commandsDir = join(repoRoot, ".claude", "commands", "compound");
|
|
@@ -2580,12 +2787,10 @@ async function runStatus(repoRoot) {
|
|
|
2580
2787
|
} catch {
|
|
2581
2788
|
}
|
|
2582
2789
|
console.log(` Hooks: ${hooksInstalled ? "installed" : "not installed"}`);
|
|
2583
|
-
const
|
|
2584
|
-
|
|
2790
|
+
const fullBeads = runFullBeadsCheck(repoRoot);
|
|
2791
|
+
printBeadsFullStatus(fullBeads);
|
|
2585
2792
|
const scope = checkUserScope(repoRoot);
|
|
2586
|
-
|
|
2587
|
-
console.log(" Scope: user-scope (reduced compounding value)");
|
|
2588
|
-
}
|
|
2793
|
+
printScopeStatus(scope);
|
|
2589
2794
|
}
|
|
2590
2795
|
var REQUIRED_PATTERNS = ["node_modules/", ".claude/.cache/"];
|
|
2591
2796
|
var SECTION_COMMENT = "# compound-agent";
|
|
@@ -4160,21 +4365,21 @@ npx ca prime
|
|
|
4160
4365
|
|
|
4161
4366
|
// src/setup/templates/docs.ts
|
|
4162
4367
|
var DOC_TEMPLATES = {
|
|
4163
|
-
"
|
|
4368
|
+
"README.md": `---
|
|
4164
4369
|
version: "{{VERSION}}"
|
|
4165
4370
|
last-updated: "{{DATE}}"
|
|
4166
|
-
summary: "
|
|
4371
|
+
summary: "Overview and getting started guide for compound-agent"
|
|
4167
4372
|
---
|
|
4168
4373
|
|
|
4169
|
-
#
|
|
4374
|
+
# Compound Agent
|
|
4170
4375
|
|
|
4171
|
-
A
|
|
4376
|
+
A learning system for Claude Code that captures, indexes, and retrieves lessons learned during development sessions -- so the same mistakes are not repeated.
|
|
4172
4377
|
|
|
4173
4378
|
---
|
|
4174
4379
|
|
|
4175
|
-
##
|
|
4380
|
+
## What is compound-agent?
|
|
4176
4381
|
|
|
4177
|
-
Compound-agent is a TypeScript CLI plugin for Claude Code
|
|
4382
|
+
Compound-agent is a TypeScript CLI plugin for Claude Code. When Claude makes a mistake and gets corrected, or discovers a useful pattern, that knowledge is stored as a **memory item** in \`.claude/lessons/index.jsonl\`. Future sessions search this memory before planning and implementing.
|
|
4178
4383
|
|
|
4179
4384
|
The system uses:
|
|
4180
4385
|
|
|
@@ -4183,17 +4388,21 @@ The system uses:
|
|
|
4183
4388
|
- **Semantic embeddings** (EmbeddingGemma-300M via node-llama-cpp) for vector similarity search
|
|
4184
4389
|
- **Claude Code hooks** to inject memory at session start, before compaction, and on tool failures
|
|
4185
4390
|
|
|
4186
|
-
Memory items have four types: \`lesson\`, \`solution\`, \`pattern\`, and \`preference\`. Each has a trigger
|
|
4391
|
+
Memory items have four types: \`lesson\`, \`solution\`, \`pattern\`, and \`preference\`. Each has a trigger, an insight, tags, severity, and optional citations.
|
|
4187
4392
|
|
|
4188
4393
|
---
|
|
4189
4394
|
|
|
4190
|
-
##
|
|
4191
|
-
|
|
4192
|
-
### Quick start
|
|
4395
|
+
## Quick start
|
|
4193
4396
|
|
|
4194
4397
|
\`\`\`bash
|
|
4195
|
-
#
|
|
4398
|
+
# Initialize in your project:
|
|
4196
4399
|
npx ca init
|
|
4400
|
+
|
|
4401
|
+
# Full setup (includes embedding model download):
|
|
4402
|
+
npx ca setup
|
|
4403
|
+
|
|
4404
|
+
# Verify installation:
|
|
4405
|
+
npx ca doctor
|
|
4197
4406
|
\`\`\`
|
|
4198
4407
|
|
|
4199
4408
|
### What \`init\` does
|
|
@@ -4202,31 +4411,16 @@ npx ca init
|
|
|
4202
4411
|
2. Updates \`AGENTS.md\` with a compound-agent section
|
|
4203
4412
|
3. Adds a reference to \`.claude/CLAUDE.md\`
|
|
4204
4413
|
4. Creates \`.claude/plugin.json\` manifest
|
|
4205
|
-
5. Installs agent templates
|
|
4206
|
-
6. Installs
|
|
4207
|
-
7. Installs
|
|
4208
|
-
8.
|
|
4209
|
-
9. Installs a git pre-commit hook (lesson capture reminder)
|
|
4210
|
-
10. Installs Claude Code hooks (SessionStart, PreCompact, UserPromptSubmit, PostToolUseFailure, PostToolUse)
|
|
4211
|
-
11. For pnpm projects: auto-configures \`onlyBuiltDependencies\` for native addons
|
|
4212
|
-
|
|
4213
|
-
### Full setup (with embedding model)
|
|
4414
|
+
5. Installs agent templates, workflow commands, phase skills, and agent role skills
|
|
4415
|
+
6. Installs a git pre-commit hook (lesson capture reminder)
|
|
4416
|
+
7. Installs Claude Code hooks (SessionStart, PreCompact, UserPromptSubmit, PostToolUseFailure, PostToolUse)
|
|
4417
|
+
8. For pnpm projects: auto-configures \`onlyBuiltDependencies\` for native addons
|
|
4214
4418
|
|
|
4215
|
-
|
|
4216
|
-
npx ca setup
|
|
4217
|
-
\`\`\`
|
|
4419
|
+
\`setup\` does everything \`init\` does, plus downloads the EmbeddingGemma-300M model (~278MB). Use \`--skip-model\` to skip the download.
|
|
4218
4420
|
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
### Verify installation
|
|
4222
|
-
|
|
4223
|
-
\`\`\`bash
|
|
4224
|
-
npx ca doctor
|
|
4225
|
-
\`\`\`
|
|
4226
|
-
|
|
4227
|
-
This checks for \`.claude/\` directory, lessons index, embedding model, Claude hooks, and beads (\`bd\`) availability.
|
|
4421
|
+
---
|
|
4228
4422
|
|
|
4229
|
-
|
|
4423
|
+
## Directory structure
|
|
4230
4424
|
|
|
4231
4425
|
\`\`\`
|
|
4232
4426
|
.claude/
|
|
@@ -4245,29 +4439,57 @@ This checks for \`.claude/\` directory, lessons index, embedding model, Claude h
|
|
|
4245
4439
|
|
|
4246
4440
|
---
|
|
4247
4441
|
|
|
4248
|
-
##
|
|
4442
|
+
## Quick reference
|
|
4443
|
+
|
|
4444
|
+
| Task | Command |
|
|
4445
|
+
|------|---------|
|
|
4446
|
+
| Capture a lesson | \`npx ca learn "insight" --trigger "what happened"\` |
|
|
4447
|
+
| Search memory | \`npx ca search "keywords"\` |
|
|
4448
|
+
| Check plan against memory | \`npx ca check-plan --plan "description"\` |
|
|
4449
|
+
| View stats | \`npx ca stats\` |
|
|
4450
|
+
| Run full workflow | \`/compound:lfg <epic-id>\` |
|
|
4451
|
+
| Health check | \`npx ca doctor\` |
|
|
4452
|
+
|
|
4453
|
+
---
|
|
4454
|
+
|
|
4455
|
+
## Further reading
|
|
4249
4456
|
|
|
4250
|
-
|
|
4457
|
+
- [WORKFLOW.md](WORKFLOW.md) -- The 5-phase development workflow and LFG orchestrator
|
|
4458
|
+
- [CLI_REFERENCE.md](CLI_REFERENCE.md) -- Complete CLI command reference
|
|
4459
|
+
- [SKILLS.md](SKILLS.md) -- Phase skills and agent role skills
|
|
4460
|
+
- [INTEGRATION.md](INTEGRATION.md) -- Memory system, hooks, beads, and agent guidance
|
|
4461
|
+
`,
|
|
4462
|
+
"WORKFLOW.md": `---
|
|
4463
|
+
version: "{{VERSION}}"
|
|
4464
|
+
last-updated: "{{DATE}}"
|
|
4465
|
+
summary: "The 5-phase compound-agent workflow and LFG orchestrator"
|
|
4466
|
+
---
|
|
4467
|
+
|
|
4468
|
+
# Workflow
|
|
4469
|
+
|
|
4470
|
+
Every feature or epic follows five phases. The \`/compound:lfg\` skill chains them with enforcement gates.
|
|
4251
4471
|
|
|
4252
|
-
|
|
4472
|
+
---
|
|
4473
|
+
|
|
4474
|
+
## Phase 1: Brainstorm
|
|
4253
4475
|
|
|
4254
|
-
Explore the problem space before committing to a solution.
|
|
4476
|
+
Explore the problem space before committing to a solution.
|
|
4255
4477
|
|
|
4256
4478
|
- Ask "why" before "how"
|
|
4257
4479
|
- Search memory for similar past features
|
|
4258
4480
|
- Generate multiple approaches, then converge
|
|
4259
4481
|
- Create a beads epic: \`bd create --title="..." --type=epic\`
|
|
4260
4482
|
|
|
4261
|
-
|
|
4483
|
+
## Phase 2: Plan
|
|
4262
4484
|
|
|
4263
|
-
Decompose work into small, testable tasks with dependencies
|
|
4485
|
+
Decompose work into small, testable tasks with dependencies.
|
|
4264
4486
|
|
|
4265
4487
|
- Review brainstorm output
|
|
4266
4488
|
- Create beads tasks: \`bd create --title="..." --type=task\`
|
|
4267
4489
|
- Create Review and Compound blocking tasks (these survive compaction)
|
|
4268
4490
|
- Run \`npx ca worktree wire-deps <epic-id>\` if using worktrees
|
|
4269
4491
|
|
|
4270
|
-
|
|
4492
|
+
## Phase 3: Work
|
|
4271
4493
|
|
|
4272
4494
|
Execute implementation through agent teams using TDD.
|
|
4273
4495
|
|
|
@@ -4276,7 +4498,7 @@ Execute implementation through agent teams using TDD.
|
|
|
4276
4498
|
- Commit incrementally as tests pass
|
|
4277
4499
|
- Run \`/implementation-reviewer\` before closing tasks
|
|
4278
4500
|
|
|
4279
|
-
|
|
4501
|
+
## Phase 4: Review
|
|
4280
4502
|
|
|
4281
4503
|
Multi-agent code review with severity classification.
|
|
4282
4504
|
|
|
@@ -4285,7 +4507,7 @@ Multi-agent code review with severity classification.
|
|
|
4285
4507
|
- Classify findings as P1/P2/P3
|
|
4286
4508
|
- Fix all P1 findings before proceeding
|
|
4287
4509
|
|
|
4288
|
-
|
|
4510
|
+
## Phase 5: Compound
|
|
4289
4511
|
|
|
4290
4512
|
Extract and store lessons learned. This is what makes the system compound.
|
|
4291
4513
|
|
|
@@ -4296,14 +4518,85 @@ Extract and store lessons learned. This is what makes the system compound.
|
|
|
4296
4518
|
|
|
4297
4519
|
---
|
|
4298
4520
|
|
|
4299
|
-
##
|
|
4521
|
+
## LFG orchestrator
|
|
4522
|
+
|
|
4523
|
+
\`/compound:lfg\` chains all 5 phases with enforcement gates.
|
|
4524
|
+
|
|
4525
|
+
### Invocation
|
|
4526
|
+
|
|
4527
|
+
\`\`\`
|
|
4528
|
+
/compound:lfg <epic-id>
|
|
4529
|
+
/compound:lfg <epic-id> from plan
|
|
4530
|
+
\`\`\`
|
|
4531
|
+
|
|
4532
|
+
### Phase execution protocol
|
|
4533
|
+
|
|
4534
|
+
For each phase, LFG:
|
|
4535
|
+
|
|
4536
|
+
1. Announces progress: \`[Phase N/5] PHASE_NAME\`
|
|
4537
|
+
2. Initializes state: \`npx ca phase-check start <phase>\`
|
|
4538
|
+
3. Reads the phase skill file (non-negotiable -- never from memory)
|
|
4539
|
+
4. Runs \`npx ca search\` with the current goal
|
|
4540
|
+
5. Executes the phase following skill instructions
|
|
4541
|
+
6. Updates epic notes: \`bd update <epic-id> --notes="Phase: NAME COMPLETE | Next: NEXT"\`
|
|
4542
|
+
7. Verifies the phase gate before proceeding
|
|
4543
|
+
|
|
4544
|
+
### Phase gates
|
|
4545
|
+
|
|
4546
|
+
| Gate | When | Verification |
|
|
4547
|
+
|------|------|-------------|
|
|
4548
|
+
| Post-plan | After Plan | \`bd list --status=open\` shows Review + Compound tasks |
|
|
4549
|
+
| Gate 3 | After Work | \`bd list --status=in_progress\` returns empty |
|
|
4550
|
+
| Gate 4 | After Review | \`/implementation-reviewer\` returned APPROVED |
|
|
4551
|
+
| Final | After Compound | \`npx ca verify-gates <epic-id>\` passes, \`pnpm test\` and \`pnpm lint\` pass |
|
|
4552
|
+
|
|
4553
|
+
If any gate fails, LFG stops. You must fix the issue before proceeding.
|
|
4554
|
+
|
|
4555
|
+
### Resumption
|
|
4556
|
+
|
|
4557
|
+
If interrupted, LFG can resume:
|
|
4558
|
+
|
|
4559
|
+
1. Run \`bd show <epic-id>\` and read the notes for phase state
|
|
4560
|
+
2. Re-invoke with \`from <phase>\` to skip completed phases
|
|
4561
|
+
|
|
4562
|
+
### Phase state tracking
|
|
4563
|
+
|
|
4564
|
+
LFG persists state in \`.claude/.ca-phase-state.json\`. Useful commands:
|
|
4565
|
+
|
|
4566
|
+
\`\`\`bash
|
|
4567
|
+
npx ca phase-check status # See current phase state
|
|
4568
|
+
npx ca phase-check clean # Reset phase state (escape hatch)
|
|
4569
|
+
\`\`\`
|
|
4570
|
+
|
|
4571
|
+
### Session close
|
|
4572
|
+
|
|
4573
|
+
Before saying "done", LFG runs this inviolable checklist:
|
|
4574
|
+
|
|
4575
|
+
\`\`\`bash
|
|
4576
|
+
git status
|
|
4577
|
+
git add <files>
|
|
4578
|
+
bd sync
|
|
4579
|
+
git commit -m "..."
|
|
4580
|
+
bd sync
|
|
4581
|
+
git push
|
|
4582
|
+
\`\`\`
|
|
4583
|
+
`,
|
|
4584
|
+
"CLI_REFERENCE.md": `---
|
|
4585
|
+
version: "{{VERSION}}"
|
|
4586
|
+
last-updated: "{{DATE}}"
|
|
4587
|
+
summary: "Complete CLI command reference for compound-agent"
|
|
4588
|
+
---
|
|
4589
|
+
|
|
4590
|
+
# CLI Reference
|
|
4300
4591
|
|
|
4301
4592
|
All commands use \`npx ca\` (or \`npx compound-agent\`). Global flags: \`-v, --verbose\` and \`-q, --quiet\`.
|
|
4302
4593
|
|
|
4303
|
-
|
|
4594
|
+
---
|
|
4595
|
+
|
|
4596
|
+
## Capture commands
|
|
4304
4597
|
|
|
4305
4598
|
\`\`\`bash
|
|
4306
|
-
# Capture a lesson (primary command
|
|
4599
|
+
# Capture a lesson (primary command)
|
|
4307
4600
|
npx ca learn "Always validate epic IDs before shell execution" \\
|
|
4308
4601
|
--trigger "Shell injection via bd show" \\
|
|
4309
4602
|
--tags "security,validation" \\
|
|
@@ -4311,7 +4604,7 @@ npx ca learn "Always validate epic IDs before shell execution" \\
|
|
|
4311
4604
|
--type lesson
|
|
4312
4605
|
|
|
4313
4606
|
# Capture a pattern (requires --pattern-bad and --pattern-good)
|
|
4314
|
-
npx ca learn "Use execFileSync instead of execSync
|
|
4607
|
+
npx ca learn "Use execFileSync instead of execSync" \\
|
|
4315
4608
|
--type pattern \\
|
|
4316
4609
|
--pattern-bad "execSync(\\\`bd show \\\${id}\\\`)" \\
|
|
4317
4610
|
--pattern-good "execFileSync('bd', ['show', id])"
|
|
@@ -4327,68 +4620,44 @@ npx ca detect --input corrections.json --save --yes
|
|
|
4327
4620
|
**Types**: \`lesson\` (default), \`solution\`, \`pattern\`, \`preference\`
|
|
4328
4621
|
**Severity**: \`high\`, \`medium\`, \`low\`
|
|
4329
4622
|
|
|
4330
|
-
|
|
4623
|
+
## Retrieval commands
|
|
4331
4624
|
|
|
4332
4625
|
\`\`\`bash
|
|
4333
|
-
# Keyword search
|
|
4334
|
-
npx ca search "sqlite validation"
|
|
4626
|
+
npx ca search "sqlite validation" # Keyword search
|
|
4335
4627
|
npx ca search "security" --limit 5
|
|
4336
|
-
|
|
4337
|
-
# List all memory items
|
|
4338
|
-
npx ca list
|
|
4628
|
+
npx ca list # List all memory items
|
|
4339
4629
|
npx ca list --limit 20
|
|
4340
|
-
npx ca list --invalidated
|
|
4341
|
-
|
|
4342
|
-
# Semantic search against a plan
|
|
4630
|
+
npx ca list --invalidated # Show only invalidated items
|
|
4343
4631
|
npx ca check-plan --plan "Implement git worktree integration"
|
|
4344
|
-
echo "Add caching layer" | npx ca check-plan
|
|
4345
|
-
|
|
4346
|
-
# Load high-severity lessons for session context
|
|
4347
|
-
npx ca load-session
|
|
4632
|
+
echo "Add caching layer" | npx ca check-plan # Semantic search against a plan
|
|
4633
|
+
npx ca load-session # Load high-severity lessons
|
|
4348
4634
|
npx ca load-session --json
|
|
4349
4635
|
\`\`\`
|
|
4350
4636
|
|
|
4351
|
-
|
|
4637
|
+
## Management commands
|
|
4352
4638
|
|
|
4353
4639
|
\`\`\`bash
|
|
4354
|
-
# View a specific item
|
|
4355
|
-
npx ca show <id>
|
|
4640
|
+
npx ca show <id> # View a specific item
|
|
4356
4641
|
npx ca show <id> --json
|
|
4357
|
-
|
|
4358
|
-
# Update item fields
|
|
4359
|
-
npx ca update <id> --insight "Updated insight text"
|
|
4642
|
+
npx ca update <id> --insight "Updated text" # Update item fields
|
|
4360
4643
|
npx ca update <id> --severity high --tags "security,input-validation"
|
|
4361
|
-
|
|
4362
|
-
# Soft delete (creates tombstone)
|
|
4363
|
-
npx ca delete <id>
|
|
4644
|
+
npx ca delete <id> # Soft delete (creates tombstone)
|
|
4364
4645
|
npx ca delete <id1> <id2> <id3>
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
npx ca
|
|
4368
|
-
|
|
4369
|
-
# Re-enable an invalidated item
|
|
4370
|
-
npx ca validate <id>
|
|
4371
|
-
|
|
4372
|
-
# Export as JSON
|
|
4373
|
-
npx ca export
|
|
4646
|
+
npx ca wrong <id> --reason "Incorrect" # Mark as invalid
|
|
4647
|
+
npx ca validate <id> # Re-enable an invalidated item
|
|
4648
|
+
npx ca export # Export as JSON
|
|
4374
4649
|
npx ca export --since 2026-01-01 --tags "security"
|
|
4375
|
-
|
|
4376
|
-
#
|
|
4377
|
-
npx ca
|
|
4378
|
-
|
|
4379
|
-
#
|
|
4380
|
-
npx ca
|
|
4381
|
-
npx ca
|
|
4382
|
-
npx ca
|
|
4383
|
-
npx ca rebuild # Rebuild SQLite index from JSONL
|
|
4384
|
-
npx ca rebuild --force # Force rebuild even if unchanged
|
|
4385
|
-
npx ca stats # Show database health and statistics
|
|
4386
|
-
|
|
4387
|
-
# Context recovery
|
|
4388
|
-
npx ca prime # Reload workflow context after compaction
|
|
4650
|
+
npx ca import lessons-backup.jsonl # Import from JSONL file
|
|
4651
|
+
npx ca compact # Remove tombstones and archive old items
|
|
4652
|
+
npx ca compact --dry-run
|
|
4653
|
+
npx ca compact --force
|
|
4654
|
+
npx ca rebuild # Rebuild SQLite index from JSONL
|
|
4655
|
+
npx ca rebuild --force
|
|
4656
|
+
npx ca stats # Show database health and statistics
|
|
4657
|
+
npx ca prime # Reload workflow context after compaction
|
|
4389
4658
|
\`\`\`
|
|
4390
4659
|
|
|
4391
|
-
|
|
4660
|
+
## Setup commands
|
|
4392
4661
|
|
|
4393
4662
|
\`\`\`bash
|
|
4394
4663
|
npx ca init # Initialize in current repo
|
|
@@ -4396,21 +4665,18 @@ npx ca init --skip-agents # Skip AGENTS.md and template installation
|
|
|
4396
4665
|
npx ca init --skip-hooks # Skip git hook installation
|
|
4397
4666
|
npx ca init --skip-claude # Skip Claude Code hooks
|
|
4398
4667
|
npx ca init --json # Output result as JSON
|
|
4399
|
-
|
|
4400
4668
|
npx ca setup # Full setup (init + model download)
|
|
4401
4669
|
npx ca setup --update # Regenerate templates (preserves user files)
|
|
4402
4670
|
npx ca setup --uninstall # Remove compound-agent integration
|
|
4403
4671
|
npx ca setup --status # Show installation status
|
|
4404
4672
|
npx ca setup --skip-model # Skip embedding model download
|
|
4405
|
-
|
|
4406
4673
|
npx ca setup claude # Install Claude Code hooks only
|
|
4407
4674
|
npx ca setup claude --status # Check hook status
|
|
4408
|
-
|
|
4409
4675
|
npx ca hooks # Install git hooks
|
|
4410
4676
|
npx ca download-model # Download embedding model (~278MB)
|
|
4411
4677
|
\`\`\`
|
|
4412
4678
|
|
|
4413
|
-
|
|
4679
|
+
## Reviewer commands
|
|
4414
4680
|
|
|
4415
4681
|
\`\`\`bash
|
|
4416
4682
|
npx ca reviewer enable gemini # Enable Gemini as external reviewer
|
|
@@ -4419,11 +4685,10 @@ npx ca reviewer disable gemini # Disable a reviewer
|
|
|
4419
4685
|
npx ca reviewer list # List enabled reviewers
|
|
4420
4686
|
\`\`\`
|
|
4421
4687
|
|
|
4422
|
-
|
|
4688
|
+
## Loop command
|
|
4423
4689
|
|
|
4424
4690
|
\`\`\`bash
|
|
4425
|
-
# Generate
|
|
4426
|
-
npx ca loop
|
|
4691
|
+
npx ca loop # Generate infinity loop script for autonomous processing
|
|
4427
4692
|
npx ca loop --epics epic-1 epic-2
|
|
4428
4693
|
npx ca loop --output my-loop.sh
|
|
4429
4694
|
npx ca loop --max-retries 5
|
|
@@ -4431,22 +4696,15 @@ npx ca loop --model claude-opus-4-6
|
|
|
4431
4696
|
npx ca loop --force # Overwrite existing script
|
|
4432
4697
|
\`\`\`
|
|
4433
4698
|
|
|
4434
|
-
|
|
4699
|
+
## Health, audit, and verification commands
|
|
4435
4700
|
|
|
4436
4701
|
\`\`\`bash
|
|
4702
|
+
npx ca about # Show version, animation, and recent changelog
|
|
4437
4703
|
npx ca doctor # Check external dependencies and project health
|
|
4438
4704
|
npx ca audit # Run pattern, rule, and lesson quality checks
|
|
4439
4705
|
npx ca rules check # Check codebase against .claude/rules.json
|
|
4440
4706
|
npx ca test-summary # Run tests and output compact pass/fail summary
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
### Verification commands
|
|
4444
|
-
|
|
4445
|
-
\`\`\`bash
|
|
4446
|
-
# Verify workflow gates before epic closure
|
|
4447
|
-
npx ca verify-gates <epic-id>
|
|
4448
|
-
|
|
4449
|
-
# Phase state management (used by LFG workflow)
|
|
4707
|
+
npx ca verify-gates <epic-id> # Verify workflow gates before epic closure
|
|
4450
4708
|
npx ca phase-check init <epic-id>
|
|
4451
4709
|
npx ca phase-check status
|
|
4452
4710
|
npx ca phase-check start <phase>
|
|
@@ -4454,39 +4712,37 @@ npx ca phase-check gate <gate-name> # post-plan, gate-3, gate-4, final
|
|
|
4454
4712
|
npx ca phase-check clean
|
|
4455
4713
|
\`\`\`
|
|
4456
4714
|
|
|
4457
|
-
|
|
4715
|
+
## Worktree commands
|
|
4458
4716
|
|
|
4459
4717
|
\`\`\`bash
|
|
4460
|
-
# Create
|
|
4461
|
-
npx ca worktree
|
|
4462
|
-
|
|
4463
|
-
#
|
|
4464
|
-
npx ca worktree
|
|
4465
|
-
|
|
4466
|
-
# Merge worktree back to main (two-phase: resolve in worktree, land on main)
|
|
4467
|
-
npx ca worktree merge <epic-id>
|
|
4468
|
-
|
|
4469
|
-
# List active worktrees
|
|
4470
|
-
npx ca worktree list
|
|
4471
|
-
|
|
4472
|
-
# Remove worktree and clean up
|
|
4473
|
-
npx ca worktree cleanup <epic-id>
|
|
4474
|
-
npx ca worktree cleanup <epic-id> --force # Force cleanup of dirty worktrees
|
|
4718
|
+
npx ca worktree create <epic-id> # Create isolated worktree
|
|
4719
|
+
npx ca worktree wire-deps <epic-id> # Connect merge dependencies
|
|
4720
|
+
npx ca worktree merge <epic-id> # Merge worktree back to main
|
|
4721
|
+
npx ca worktree list # List active worktrees
|
|
4722
|
+
npx ca worktree cleanup <epic-id> # Remove worktree and clean up
|
|
4723
|
+
npx ca worktree cleanup <epic-id> --force # Force cleanup of dirty worktrees
|
|
4475
4724
|
\`\`\`
|
|
4476
4725
|
|
|
4477
|
-
|
|
4726
|
+
## Compound command
|
|
4478
4727
|
|
|
4479
4728
|
\`\`\`bash
|
|
4480
|
-
# Synthesize cross-cutting patterns from accumulated lessons
|
|
4481
|
-
npx ca compound
|
|
4729
|
+
npx ca compound # Synthesize cross-cutting patterns from accumulated lessons
|
|
4482
4730
|
\`\`\`
|
|
4483
|
-
|
|
4731
|
+
`,
|
|
4732
|
+
"SKILLS.md": `---
|
|
4733
|
+
version: "{{VERSION}}"
|
|
4734
|
+
last-updated: "{{DATE}}"
|
|
4735
|
+
summary: "Phase skills and agent role skills reference"
|
|
4484
4736
|
---
|
|
4485
4737
|
|
|
4486
|
-
|
|
4738
|
+
# Skills Reference
|
|
4487
4739
|
|
|
4488
4740
|
Skills are instructions that Claude reads before executing each phase. They live in \`.claude/skills/compound/\` and are auto-installed by \`npx ca setup\`.
|
|
4489
4741
|
|
|
4742
|
+
---
|
|
4743
|
+
|
|
4744
|
+
## Phase skills
|
|
4745
|
+
|
|
4490
4746
|
### \`/compound:brainstorm\`
|
|
4491
4747
|
|
|
4492
4748
|
**Purpose**: Divergent-then-convergent thinking to explore the solution space.
|
|
@@ -4533,7 +4789,7 @@ Skills are instructions that Claude reads before executing each phase. They live
|
|
|
4533
4789
|
|
|
4534
4790
|
**When invoked**: When you want to run an entire epic end-to-end.
|
|
4535
4791
|
|
|
4536
|
-
**What it does**: Sequences all 5 phases with mandatory gates between them, tracks progress in beads notes, handles resumption after interruption.
|
|
4792
|
+
**What it does**: Sequences all 5 phases with mandatory gates between them, tracks progress in beads notes, handles resumption after interruption. See [WORKFLOW.md](WORKFLOW.md) for full details.
|
|
4537
4793
|
|
|
4538
4794
|
### \`/compound:set-worktree\`
|
|
4539
4795
|
|
|
@@ -4545,150 +4801,42 @@ Skills are instructions that Claude reads before executing each phase. They live
|
|
|
4545
4801
|
|
|
4546
4802
|
---
|
|
4547
4803
|
|
|
4548
|
-
##
|
|
4549
|
-
|
|
4550
|
-
\`/compound:lfg\` chains all 5 phases with enforcement gates. Here is how it works:
|
|
4551
|
-
|
|
4552
|
-
### Invocation
|
|
4553
|
-
|
|
4554
|
-
\`\`\`
|
|
4555
|
-
/compound:lfg <epic-id>
|
|
4556
|
-
\`\`\`
|
|
4557
|
-
|
|
4558
|
-
Or with a phase skip:
|
|
4559
|
-
|
|
4560
|
-
\`\`\`
|
|
4561
|
-
/compound:lfg <epic-id> from plan
|
|
4562
|
-
\`\`\`
|
|
4563
|
-
|
|
4564
|
-
### Phase execution protocol
|
|
4565
|
-
|
|
4566
|
-
For each phase, LFG:
|
|
4567
|
-
|
|
4568
|
-
1. Announces progress: \`[Phase N/5] PHASE_NAME\`
|
|
4569
|
-
2. Initializes state: \`npx ca phase-check start <phase>\`
|
|
4570
|
-
3. Reads the phase skill file (non-negotiable -- never from memory)
|
|
4571
|
-
4. Runs \`npx ca search\` with the current goal
|
|
4572
|
-
5. Executes the phase following skill instructions
|
|
4573
|
-
6. Updates epic notes: \`bd update <epic-id> --notes="Phase: NAME COMPLETE | Next: NEXT"\`
|
|
4574
|
-
7. Verifies the phase gate before proceeding
|
|
4575
|
-
|
|
4576
|
-
### Phase gates
|
|
4577
|
-
|
|
4578
|
-
| Gate | When | Verification |
|
|
4579
|
-
|------|------|-------------|
|
|
4580
|
-
| Post-plan | After Plan | \`bd list --status=open\` shows Review + Compound tasks |
|
|
4581
|
-
| Gate 3 | After Work | \`bd list --status=in_progress\` returns empty |
|
|
4582
|
-
| Gate 4 | After Review | \`/implementation-reviewer\` returned APPROVED |
|
|
4583
|
-
| Final | After Compound | \`npx ca verify-gates <epic-id>\` passes, \`pnpm test\` and \`pnpm lint\` pass |
|
|
4584
|
-
|
|
4585
|
-
If any gate fails, LFG stops. You must fix the issue before proceeding.
|
|
4586
|
-
|
|
4587
|
-
### Resumption
|
|
4588
|
-
|
|
4589
|
-
If interrupted, LFG can resume:
|
|
4804
|
+
## Skill invocation
|
|
4590
4805
|
|
|
4591
|
-
|
|
4592
|
-
2. Re-invoke with \`from <phase>\` to skip completed phases
|
|
4806
|
+
Skills are invoked as Claude Code slash commands:
|
|
4593
4807
|
|
|
4594
|
-
### Phase state tracking
|
|
4595
|
-
|
|
4596
|
-
LFG persists state in \`.claude/.ca-phase-state.json\`. Useful commands:
|
|
4597
|
-
|
|
4598
|
-
\`\`\`bash
|
|
4599
|
-
npx ca phase-check status # See current phase state
|
|
4600
|
-
npx ca phase-check clean # Reset phase state (escape hatch)
|
|
4601
4808
|
\`\`\`
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
git add <files>
|
|
4610
|
-
bd sync
|
|
4611
|
-
git commit -m "..."
|
|
4612
|
-
bd sync
|
|
4613
|
-
git push
|
|
4809
|
+
/compound:brainstorm # Start brainstorm phase
|
|
4810
|
+
/compound:plan # Start plan phase
|
|
4811
|
+
/compound:work # Start work phase
|
|
4812
|
+
/compound:review # Start review phase
|
|
4813
|
+
/compound:compound # Start compound phase
|
|
4814
|
+
/compound:lfg <epic-id> # Run all phases end-to-end
|
|
4815
|
+
/compound:set-worktree <epic-id> # Set up worktree before LFG
|
|
4614
4816
|
\`\`\`
|
|
4615
4817
|
|
|
4818
|
+
Each skill reads its SKILL.md file from \`.claude/skills/compound/<phase>/SKILL.md\` at invocation time. Skills are never executed from memory.
|
|
4819
|
+
`,
|
|
4820
|
+
"INTEGRATION.md": `---
|
|
4821
|
+
version: "{{VERSION}}"
|
|
4822
|
+
last-updated: "{{DATE}}"
|
|
4823
|
+
summary: "Memory system, hooks, beads integration, and agent guidance"
|
|
4616
4824
|
---
|
|
4617
4825
|
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
Worktrees let you run epics in isolation, enabling parallel execution across multiple Claude Code sessions.
|
|
4621
|
-
|
|
4622
|
-
### Creating a worktree
|
|
4623
|
-
|
|
4624
|
-
\`\`\`bash
|
|
4625
|
-
npx ca worktree create <epic-id>
|
|
4626
|
-
\`\`\`
|
|
4627
|
-
|
|
4628
|
-
This:
|
|
4629
|
-
|
|
4630
|
-
1. Creates a git worktree at \`../<repo>-wt-<epic-id>\` on branch \`epic/<epic-id>\`
|
|
4631
|
-
2. Installs dependencies via \`pnpm install --frozen-lockfile\`
|
|
4632
|
-
3. Copies \`.claude/lessons/index.jsonl\` to the worktree
|
|
4633
|
-
4. Runs \`npx ca setup --skip-model\` in the worktree
|
|
4634
|
-
5. Creates a Merge beads task linked to the epic
|
|
4635
|
-
|
|
4636
|
-
### Using with LFG
|
|
4637
|
-
|
|
4638
|
-
\`\`\`bash
|
|
4639
|
-
# From main repo:
|
|
4640
|
-
npx ca worktree create my-epic-id
|
|
4641
|
-
|
|
4642
|
-
# Then in the worktree directory:
|
|
4643
|
-
# Run /compound:lfg or /compound:set-worktree followed by /compound:lfg
|
|
4644
|
-
\`\`\`
|
|
4645
|
-
|
|
4646
|
-
Or use the skill:
|
|
4647
|
-
|
|
4648
|
-
\`\`\`
|
|
4649
|
-
/compound:set-worktree <epic-id>
|
|
4650
|
-
\`\`\`
|
|
4651
|
-
|
|
4652
|
-
### Merging back
|
|
4653
|
-
|
|
4654
|
-
When all work tasks complete, the Merge task surfaces via \`bd ready\`:
|
|
4655
|
-
|
|
4656
|
-
\`\`\`bash
|
|
4657
|
-
npx ca worktree merge <epic-id>
|
|
4658
|
-
\`\`\`
|
|
4659
|
-
|
|
4660
|
-
This runs a two-phase merge:
|
|
4661
|
-
|
|
4662
|
-
1. Merges \`main\` into the worktree branch (resolve conflicts there)
|
|
4663
|
-
2. Fast-forwards \`main\` to the worktree branch (clean landing)
|
|
4826
|
+
# Integration
|
|
4664
4827
|
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
\`\`\`bash
|
|
4668
|
-
npx ca worktree cleanup <epic-id>
|
|
4669
|
-
npx ca worktree cleanup <epic-id> --force # For dirty worktrees
|
|
4670
|
-
\`\`\`
|
|
4671
|
-
|
|
4672
|
-
This removes the worktree directory, deletes the branch, and closes the Merge task.
|
|
4673
|
-
|
|
4674
|
-
### Listing worktrees
|
|
4675
|
-
|
|
4676
|
-
\`\`\`bash
|
|
4677
|
-
npx ca worktree list
|
|
4678
|
-
\`\`\`
|
|
4679
|
-
|
|
4680
|
-
Shows active worktrees with their epic and merge task status.
|
|
4828
|
+
Deep integration topics for compound-agent: memory system internals, Claude Code hooks, beads workflow, worktree integration, and agent guidance.
|
|
4681
4829
|
|
|
4682
4830
|
---
|
|
4683
4831
|
|
|
4684
|
-
##
|
|
4832
|
+
## Memory system
|
|
4685
4833
|
|
|
4686
4834
|
### Storage format
|
|
4687
4835
|
|
|
4688
4836
|
Memory items are stored as newline-delimited JSON in \`.claude/lessons/index.jsonl\`. Each line is a complete JSON object:
|
|
4689
4837
|
|
|
4690
4838
|
\`\`\`json
|
|
4691
|
-
{"id":"L-abc123","type":"lesson","trigger":"Shell injection via execSync","insight":"Use execFileSync with array args
|
|
4839
|
+
{"id":"L-abc123","type":"lesson","trigger":"Shell injection via execSync","insight":"Use execFileSync with array args","tags":["security"],"source":"manual","context":{"tool":"cli","intent":"manual learning"},"created":"2026-02-15T10:00:00Z","confirmed":true,"severity":"high","supersedes":[],"related":[]}
|
|
4692
4840
|
\`\`\`
|
|
4693
4841
|
|
|
4694
4842
|
### Indexing
|
|
@@ -4709,14 +4857,6 @@ The index is rebuilt automatically when the JSONL changes. Force rebuild with \`
|
|
|
4709
4857
|
|
|
4710
4858
|
**Session loading** (\`npx ca load-session\`): Returns high-severity confirmed lessons for injection at session start.
|
|
4711
4859
|
|
|
4712
|
-
### Compounding (pattern synthesis)
|
|
4713
|
-
|
|
4714
|
-
\`\`\`bash
|
|
4715
|
-
npx ca compound
|
|
4716
|
-
\`\`\`
|
|
4717
|
-
|
|
4718
|
-
This reads all memory items, computes embeddings, clusters them by similarity, and synthesizes cross-cutting patterns into \`.claude/lessons/cct-patterns.jsonl\`. Clusters with 2+ items become patterns; single-item clusters are filtered as noise.
|
|
4719
|
-
|
|
4720
4860
|
### Data lifecycle
|
|
4721
4861
|
|
|
4722
4862
|
| Operation | Effect |
|
|
@@ -4729,21 +4869,7 @@ This reads all memory items, computes embeddings, clusters them by similarity, a
|
|
|
4729
4869
|
|
|
4730
4870
|
---
|
|
4731
4871
|
|
|
4732
|
-
##
|
|
4733
|
-
|
|
4734
|
-
### Integrating into CLAUDE.md
|
|
4735
|
-
|
|
4736
|
-
Add a reference to compound-agent in your project's \`.claude/CLAUDE.md\`:
|
|
4737
|
-
|
|
4738
|
-
\`\`\`markdown
|
|
4739
|
-
## References
|
|
4740
|
-
|
|
4741
|
-
- docs/compound/HOW_TO_COMPOUND.md -- Usage guide for humans and AI agents
|
|
4742
|
-
\`\`\`
|
|
4743
|
-
|
|
4744
|
-
The \`npx ca init\` command does this automatically.
|
|
4745
|
-
|
|
4746
|
-
### Claude Code hooks
|
|
4872
|
+
## Claude Code hooks
|
|
4747
4873
|
|
|
4748
4874
|
Compound-agent installs five hooks into \`.claude/settings.json\`:
|
|
4749
4875
|
|
|
@@ -4751,7 +4877,7 @@ Compound-agent installs five hooks into \`.claude/settings.json\`:
|
|
|
4751
4877
|
|------|---------|--------|
|
|
4752
4878
|
| **SessionStart** | New session or resume | Runs \`npx ca prime\` to load workflow context and high-severity lessons |
|
|
4753
4879
|
| **PreCompact** | Before context compaction | Runs \`npx ca prime\` to preserve context across compaction |
|
|
4754
|
-
| **UserPromptSubmit** | Every user message | Detects correction
|
|
4880
|
+
| **UserPromptSubmit** | Every user message | Detects correction/planning language, injects memory reminders |
|
|
4755
4881
|
| **PostToolUseFailure** | Bash/Edit/Write failures | After 2 failures on same file or 3 total, suggests \`npx ca search\` |
|
|
4756
4882
|
| **PostToolUse** | After successful tool use | Resets failure tracking; tracks skill file reads for phase guard |
|
|
4757
4883
|
|
|
@@ -4778,7 +4904,9 @@ npx ca learn "The insight" --trigger "What happened" --severity medium
|
|
|
4778
4904
|
npx ca compound
|
|
4779
4905
|
\`\`\`
|
|
4780
4906
|
|
|
4781
|
-
|
|
4907
|
+
---
|
|
4908
|
+
|
|
4909
|
+
## Beads integration
|
|
4782
4910
|
|
|
4783
4911
|
Compound-agent works with beads (\`bd\`) for issue tracking:
|
|
4784
4912
|
|
|
@@ -4801,11 +4929,38 @@ Before closing an epic, verify all gates pass:
|
|
|
4801
4929
|
npx ca verify-gates <epic-id>
|
|
4802
4930
|
\`\`\`
|
|
4803
4931
|
|
|
4804
|
-
This checks that
|
|
4932
|
+
This checks that a Review task, Compound task, and (if applicable) Merge task all exist and are closed.
|
|
4933
|
+
|
|
4934
|
+
---
|
|
4935
|
+
|
|
4936
|
+
## Worktree integration
|
|
4937
|
+
|
|
4938
|
+
Worktrees let you run epics in isolation, enabling parallel execution across multiple Claude Code sessions.
|
|
4939
|
+
|
|
4940
|
+
\`\`\`bash
|
|
4941
|
+
npx ca worktree create <epic-id> # Creates worktree + installs deps + copies lessons
|
|
4942
|
+
npx ca worktree merge <epic-id> # Two-phase merge back to main
|
|
4943
|
+
npx ca worktree cleanup <epic-id> # Remove worktree, delete branch, close Merge task
|
|
4944
|
+
npx ca worktree list # Show active worktrees
|
|
4945
|
+
\`\`\`
|
|
4946
|
+
|
|
4947
|
+
See [CLI_REFERENCE.md](CLI_REFERENCE.md) for full worktree command details.
|
|
4948
|
+
|
|
4949
|
+
---
|
|
4950
|
+
|
|
4951
|
+
## For AI agents
|
|
4952
|
+
|
|
4953
|
+
### Integrating into CLAUDE.md
|
|
4805
4954
|
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4955
|
+
Add a reference to compound-agent in your project's \`.claude/CLAUDE.md\`:
|
|
4956
|
+
|
|
4957
|
+
\`\`\`markdown
|
|
4958
|
+
## References
|
|
4959
|
+
|
|
4960
|
+
- docs/compound/README.md -- Compound-agent overview and getting started
|
|
4961
|
+
\`\`\`
|
|
4962
|
+
|
|
4963
|
+
The \`npx ca init\` command does this automatically.
|
|
4809
4964
|
|
|
4810
4965
|
### Session completion checklist
|
|
4811
4966
|
|
|
@@ -5386,12 +5541,18 @@ Synthesize analysis results into a refined optimization plan:
|
|
|
5386
5541
|
- Estimate impact on test suite speed and coverage
|
|
5387
5542
|
- Iterate with subagents until the plan is comprehensive
|
|
5388
5543
|
|
|
5389
|
-
### Phase 3: Adversarial Review
|
|
5544
|
+
### Phase 3: Adversarial Review (CRITICAL QUALITY GATE)
|
|
5545
|
+
**This is THE KEY PHASE -- the most important phase in the entire workflow. NEVER skip, NEVER rush, NEVER settle for "good enough."**
|
|
5546
|
+
|
|
5390
5547
|
Expose the plan to two neutral reviewer subagents:
|
|
5391
5548
|
- **Reviewer A** (Opus): Independent critique of the optimization plan
|
|
5392
5549
|
- **Reviewer B** (Sonnet): Independent critique from a different perspective
|
|
5550
|
+
|
|
5393
5551
|
Both reviewers challenge assumptions, identify risks, and suggest improvements.
|
|
5394
|
-
|
|
5552
|
+
|
|
5553
|
+
**Mandatory iteration loop**: After each reviewer pass, if ANY issues, concerns, or suggestions remain from EITHER reviewer, revise the plan and re-submit to BOTH reviewers. Repeat until BOTH reviewers explicitly approve with ZERO reservations. Do not proceed to Phase 4 until unanimous, unconditional approval is reached.
|
|
5554
|
+
|
|
5555
|
+
This is the critical quality gate. Loop as many times as needed. The test suite must be bulletproof before execution begins.
|
|
5395
5556
|
|
|
5396
5557
|
### Phase 4: Execution
|
|
5397
5558
|
Apply the agreed changes:
|
|
@@ -5417,13 +5578,13 @@ Apply the agreed changes:
|
|
|
5417
5578
|
## Common Pitfalls
|
|
5418
5579
|
- Deleting tests without verifying coverage is maintained elsewhere
|
|
5419
5580
|
- Optimizing for speed at the cost of correctness
|
|
5420
|
-
-
|
|
5581
|
+
- Settling for partial approval or cutting the Phase 3 review loop short before BOTH reviewers approve with zero reservations
|
|
5421
5582
|
- Making changes without machine-readable output
|
|
5422
5583
|
- Not feeding results back into compound-agent memory
|
|
5423
5584
|
|
|
5424
5585
|
## Quality Criteria
|
|
5425
5586
|
- All 5 phases completed (analysis, planning, review, execution, verification)
|
|
5426
|
-
-
|
|
5587
|
+
- Both adversarial reviewers approved with zero reservations after iterative refinement
|
|
5427
5588
|
- Machine-readable output format used throughout
|
|
5428
5589
|
- Full test suite passes after changes
|
|
5429
5590
|
- Coverage not degraded
|
|
@@ -5726,7 +5887,7 @@ async function stripHeadersRecursive(dir, dryRun = false) {
|
|
|
5726
5887
|
return count;
|
|
5727
5888
|
}
|
|
5728
5889
|
async function upgradeDocVersion(repoRoot, newVersion, dryRun = false) {
|
|
5729
|
-
const docPath = join(repoRoot, "docs", "compound", "
|
|
5890
|
+
const docPath = join(repoRoot, "docs", "compound", "README.md");
|
|
5730
5891
|
if (!existsSync(docPath)) return false;
|
|
5731
5892
|
const content = await readFile(docPath, "utf-8");
|
|
5732
5893
|
const updated = content.replace(/^(version: ")([^"]+)(")/m, `$1${newVersion}$3`);
|
|
@@ -5872,6 +6033,10 @@ async function runUpdate(repoRoot, dryRun) {
|
|
|
5872
6033
|
for (const [name, content] of Object.entries(AGENT_ROLE_SKILLS)) {
|
|
5873
6034
|
await processFile(join(repoRoot, ".claude", "skills", "compound", "agents", name, "SKILL.md"), content);
|
|
5874
6035
|
}
|
|
6036
|
+
for (const [filename, template] of Object.entries(DOC_TEMPLATES)) {
|
|
6037
|
+
const content = template.replace("{{VERSION}}", VERSION).replace("{{DATE}}", (/* @__PURE__ */ new Date()).toISOString().slice(0, 10));
|
|
6038
|
+
await processFile(join(repoRoot, "docs", "compound", filename), content);
|
|
6039
|
+
}
|
|
5875
6040
|
for (const filename of LEGACY_ROOT_SLASH_COMMANDS) {
|
|
5876
6041
|
const filePath = join(repoRoot, ".claude", "commands", filename);
|
|
5877
6042
|
if (existsSync(filePath)) {
|
|
@@ -5881,6 +6046,14 @@ async function runUpdate(repoRoot, dryRun) {
|
|
|
5881
6046
|
}
|
|
5882
6047
|
}
|
|
5883
6048
|
}
|
|
6049
|
+
const oldDocPath = join(repoRoot, "docs", "compound", "HOW_TO_COMPOUND.md");
|
|
6050
|
+
if (existsSync(oldDocPath)) {
|
|
6051
|
+
const oldContent = await readFile(oldDocPath, "utf-8");
|
|
6052
|
+
if (oldContent.startsWith("---\nversion:")) {
|
|
6053
|
+
if (!dryRun) await rm(oldDocPath);
|
|
6054
|
+
updated++;
|
|
6055
|
+
}
|
|
6056
|
+
}
|
|
5884
6057
|
let configUpdated = false;
|
|
5885
6058
|
if (!dryRun) {
|
|
5886
6059
|
const { hooks } = await configureClaudeSettings();
|
|
@@ -5895,11 +6068,12 @@ var MODEL_STATUS_MSG = {
|
|
|
5895
6068
|
already_exists: "Already exists",
|
|
5896
6069
|
failed: "Download failed (run `ca download-model` manually)"
|
|
5897
6070
|
};
|
|
5898
|
-
async function printSetupResult(result, quiet) {
|
|
6071
|
+
async function printSetupResult(result, quiet, repoRoot) {
|
|
5899
6072
|
if (!quiet) {
|
|
5900
|
-
if (result.
|
|
5901
|
-
|
|
5902
|
-
|
|
6073
|
+
if (result.upgrade?.isUpgrade) {
|
|
6074
|
+
console.log(` ${result.upgrade.message}`);
|
|
6075
|
+
console.log(" Tip: Run with --update to regenerate managed files with latest templates.");
|
|
6076
|
+
}
|
|
5903
6077
|
if (process.stdout.isTTY) await playInstallBanner();
|
|
5904
6078
|
}
|
|
5905
6079
|
out.success("Compound agent setup complete");
|
|
@@ -5910,6 +6084,9 @@ async function printSetupResult(result, quiet) {
|
|
|
5910
6084
|
printPnpmConfigStatus(result.pnpmConfig);
|
|
5911
6085
|
printGitignoreStatus(result.gitignore);
|
|
5912
6086
|
console.log(` Model: ${MODEL_STATUS_MSG[result.model]}`);
|
|
6087
|
+
const fullBeads = runFullBeadsCheck(repoRoot);
|
|
6088
|
+
printBeadsFullStatus(fullBeads);
|
|
6089
|
+
printScopeStatus(result.scope);
|
|
5913
6090
|
console.log("\nNext steps:\n 1. Restart Claude Code to load hooks\n 2. Use `npx ca search` and `npx ca learn` commands");
|
|
5914
6091
|
}
|
|
5915
6092
|
function registerSetupAllCommand(setupCommand) {
|
|
@@ -5931,6 +6108,7 @@ function registerSetupAllCommand(setupCommand) {
|
|
|
5931
6108
|
return;
|
|
5932
6109
|
}
|
|
5933
6110
|
if (options.update) {
|
|
6111
|
+
if (!dryRun && process.stdout.isTTY) await playInstallBanner();
|
|
5934
6112
|
const result2 = await runUpdate(repoRoot, dryRun);
|
|
5935
6113
|
const prefix = dryRun ? "[dry-run] " : "";
|
|
5936
6114
|
if (result2.upgrade.isUpgrade) {
|
|
@@ -5946,6 +6124,10 @@ function registerSetupAllCommand(setupCommand) {
|
|
|
5946
6124
|
console.log(` ${prefix}.gitignore: Added [${result2.gitignore.added.join(", ")}]`);
|
|
5947
6125
|
}
|
|
5948
6126
|
if (result2.configUpdated) console.log(` ${prefix}Config: hooks updated`);
|
|
6127
|
+
const fullBeads = runFullBeadsCheck(repoRoot);
|
|
6128
|
+
printBeadsFullStatus(fullBeads);
|
|
6129
|
+
const scope = checkUserScope(repoRoot);
|
|
6130
|
+
printScopeStatus(scope);
|
|
5949
6131
|
return;
|
|
5950
6132
|
}
|
|
5951
6133
|
if (options.status) {
|
|
@@ -5954,7 +6136,7 @@ function registerSetupAllCommand(setupCommand) {
|
|
|
5954
6136
|
}
|
|
5955
6137
|
const result = await runSetup({ skipModel: options.skipModel, skipHooks: options.skipHooks });
|
|
5956
6138
|
const { quiet } = getGlobalOpts(this);
|
|
5957
|
-
await printSetupResult(result, quiet);
|
|
6139
|
+
await printSetupResult(result, quiet, repoRoot);
|
|
5958
6140
|
});
|
|
5959
6141
|
}
|
|
5960
6142
|
async function handleStatus(alreadyInstalled, displayPath, settingsPath, options) {
|
|
@@ -6175,18 +6357,14 @@ async function initAction(cmd, options) {
|
|
|
6175
6357
|
const repoRoot = getRepoRoot();
|
|
6176
6358
|
const { quiet } = getGlobalOpts(cmd);
|
|
6177
6359
|
const scopeResult = checkUserScope(repoRoot);
|
|
6178
|
-
if (scopeResult.isUserScope && !quiet && !options.json) {
|
|
6179
|
-
console.log(` ${scopeResult.message}`);
|
|
6180
|
-
}
|
|
6181
|
-
const beadsResult = checkBeadsAvailable();
|
|
6182
|
-
if (!beadsResult.available && !quiet && !options.json) {
|
|
6183
|
-
console.log(` ${beadsResult.message}`);
|
|
6184
|
-
}
|
|
6185
6360
|
let upgradeResult = null;
|
|
6186
6361
|
if (options.update || detectExistingInstall(repoRoot)) {
|
|
6187
6362
|
upgradeResult = await runUpgrade(repoRoot);
|
|
6188
6363
|
if (!quiet && !options.json && upgradeResult.isUpgrade) {
|
|
6189
6364
|
console.log(` ${upgradeResult.message}`);
|
|
6365
|
+
if (!options.update) {
|
|
6366
|
+
console.log(" Tip: Run with --update to regenerate managed files with latest templates.");
|
|
6367
|
+
}
|
|
6190
6368
|
}
|
|
6191
6369
|
}
|
|
6192
6370
|
if (!quiet && !options.json && process.stdout.isTTY) {
|
|
@@ -6220,8 +6398,9 @@ async function initAction(cmd, options) {
|
|
|
6220
6398
|
claudeHooksResult = await installClaudeHooksForInit(repoRoot);
|
|
6221
6399
|
}
|
|
6222
6400
|
const gitignoreResult = await ensureGitignore(repoRoot);
|
|
6401
|
+
const fullBeads = runFullBeadsCheck(repoRoot);
|
|
6223
6402
|
if (options.json) {
|
|
6224
|
-
printInitJson({ lessonsDir, agentsMdUpdated, hookResult, claudeHooksResult, pnpmConfig,
|
|
6403
|
+
printInitJson({ lessonsDir, agentsMdUpdated, hookResult, claudeHooksResult, pnpmConfig, fullBeads, scopeResult, upgradeResult, gitignoreResult });
|
|
6225
6404
|
return;
|
|
6226
6405
|
}
|
|
6227
6406
|
if (quiet) return;
|
|
@@ -6232,6 +6411,8 @@ async function initAction(cmd, options) {
|
|
|
6232
6411
|
printClaudeHooksStatus(claudeHooksResult, options.skipClaude);
|
|
6233
6412
|
printPnpmConfigStatus2(pnpmConfig);
|
|
6234
6413
|
printGitignoreStatus(gitignoreResult);
|
|
6414
|
+
printBeadsFullStatus(fullBeads);
|
|
6415
|
+
printScopeStatus(scopeResult);
|
|
6235
6416
|
}
|
|
6236
6417
|
function printInitJson(ctx) {
|
|
6237
6418
|
const claudeHooksInstalled = ctx.claudeHooksResult.action === "installed";
|
|
@@ -6244,7 +6425,9 @@ function printInitJson(ctx) {
|
|
|
6244
6425
|
hookStatus: ctx.hookResult?.status ?? "skipped",
|
|
6245
6426
|
claudeHooks: claudeHooksInstalled,
|
|
6246
6427
|
pnpmConfig: ctx.pnpmConfig.isPnpm ? { added: ctx.pnpmConfig.added, alreadyConfigured: ctx.pnpmConfig.alreadyConfigured } : null,
|
|
6247
|
-
beadsAvailable: ctx.
|
|
6428
|
+
beadsAvailable: ctx.fullBeads.cliAvailable,
|
|
6429
|
+
beadsInitialized: ctx.fullBeads.initialized,
|
|
6430
|
+
beadsHealthy: ctx.fullBeads.healthy,
|
|
6248
6431
|
userScope: ctx.scopeResult.isUserScope,
|
|
6249
6432
|
upgrade: ctx.upgradeResult ? { isUpgrade: ctx.upgradeResult.isUpgrade, removedCommands: ctx.upgradeResult.removedCommands, strippedHeaders: ctx.upgradeResult.strippedHeaders } : null,
|
|
6250
6433
|
gitignore: ctx.gitignoreResult.added
|
|
@@ -6514,6 +6697,17 @@ function registerCrudCommands(program2) {
|
|
|
6514
6697
|
await deleteAction(ids, options);
|
|
6515
6698
|
});
|
|
6516
6699
|
}
|
|
6700
|
+
function checkGitignoreHealth(repoRoot) {
|
|
6701
|
+
const gitignorePath = join(repoRoot, ".gitignore");
|
|
6702
|
+
if (!existsSync(gitignorePath)) return false;
|
|
6703
|
+
try {
|
|
6704
|
+
const content = readFileSync(gitignorePath, "utf-8");
|
|
6705
|
+
const lines = new Set(content.split("\n").map((l) => l.trim()));
|
|
6706
|
+
return ["node_modules/", ".claude/.cache/"].every((p) => lines.has(p));
|
|
6707
|
+
} catch {
|
|
6708
|
+
return false;
|
|
6709
|
+
}
|
|
6710
|
+
}
|
|
6517
6711
|
async function runDoctor(repoRoot) {
|
|
6518
6712
|
const checks = [];
|
|
6519
6713
|
const claudeDir = join(repoRoot, ".claude");
|
|
@@ -6540,20 +6734,21 @@ async function runDoctor(repoRoot) {
|
|
|
6540
6734
|
checks.push(modelOk ? { name: "Embedding model", status: "pass" } : { name: "Embedding model", status: "warn", fix: "Run: npx ca download-model" });
|
|
6541
6735
|
const beadsResult = checkBeadsAvailable();
|
|
6542
6736
|
checks.push(beadsResult.available ? { name: "Beads CLI", status: "pass" } : { name: "Beads CLI", status: "warn", fix: "Install beads: https://github.com/Nathandela/beads" });
|
|
6543
|
-
|
|
6544
|
-
const
|
|
6545
|
-
|
|
6546
|
-
|
|
6737
|
+
checks.push(checkGitignoreHealth(repoRoot) ? { name: ".gitignore health", status: "pass" } : { name: ".gitignore health", status: "warn", fix: "Run: npx ca setup --update" });
|
|
6738
|
+
const docPath = join(repoRoot, "docs", "compound", "README.md");
|
|
6739
|
+
checks.push(existsSync(docPath) ? { name: "Usage documentation", status: "pass" } : { name: "Usage documentation", status: "warn", fix: "Run: npx ca setup" });
|
|
6740
|
+
const beadsDir = join(repoRoot, ".beads");
|
|
6741
|
+
checks.push(existsSync(beadsDir) ? { name: "Beads initialized", status: "pass" } : { name: "Beads initialized", status: "warn", fix: "Run: bd init" });
|
|
6742
|
+
if (beadsResult.available && existsSync(beadsDir)) {
|
|
6547
6743
|
try {
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
gitignoreOk = requiredPatterns.every((p) => lines.has(p));
|
|
6744
|
+
execSync("bd doctor", { cwd: repoRoot, shell: "/bin/sh", stdio: "pipe" });
|
|
6745
|
+
checks.push({ name: "Beads healthy", status: "pass" });
|
|
6551
6746
|
} catch {
|
|
6747
|
+
checks.push({ name: "Beads healthy", status: "warn", fix: "Run: bd doctor" });
|
|
6552
6748
|
}
|
|
6553
6749
|
}
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
checks.push(existsSync(docPath) ? { name: "Usage documentation", status: "pass" } : { name: "Usage documentation", status: "warn", fix: "Run: npx ca setup" });
|
|
6750
|
+
const scope = checkUserScope(repoRoot);
|
|
6751
|
+
checks.push(!scope.isUserScope ? { name: "Codebase scope", status: "pass" } : { name: "Codebase scope", status: "warn", fix: "Install in a specific repository, not home directory" });
|
|
6557
6752
|
return checks;
|
|
6558
6753
|
}
|
|
6559
6754
|
var STATUS_ICONS = {
|
|
@@ -7335,6 +7530,96 @@ function registerVerifyGatesCommand(program2) {
|
|
|
7335
7530
|
}
|
|
7336
7531
|
});
|
|
7337
7532
|
}
|
|
7533
|
+
|
|
7534
|
+
// src/changelog-data.ts
|
|
7535
|
+
var CHANGELOG_RECENT = `## [1.3.2] - 2026-02-21
|
|
7536
|
+
|
|
7537
|
+
### Added
|
|
7538
|
+
|
|
7539
|
+
- **Banner audio**: Pure TypeScript WAV synthesis plays a rising pentatonic melody during the tendril animation. Cross-platform: \`afplay\` (macOS), \`aplay\` (Linux), PowerShell (Windows). Silently skips if player unavailable. Zero dependencies.
|
|
7540
|
+
- **Test coverage**: 19 new tests for \`ca about\` command, changelog extraction/escaping, and \`--update\` doc migration path
|
|
7541
|
+
|
|
7542
|
+
### Fixed
|
|
7543
|
+
|
|
7544
|
+
- **\`setup --update\` doc migration**: \`--update\` now installs the 5 split docs before removing legacy \`HOW_TO_COMPOUND.md\`, preventing empty \`docs/compound/\`
|
|
7545
|
+
- **Fresh checkout type-check**: \`src/changelog-data.ts\` tracked in git so \`tsc --noEmit\` passes without a prior build
|
|
7546
|
+
- **Trailing status text**: Banner animation no longer leaves "al tendrils..." remnant from previous phase
|
|
7547
|
+
|
|
7548
|
+
### Changed
|
|
7549
|
+
|
|
7550
|
+
- **\`ca about\` command**: Renamed from \`ca version-show\` for brevity
|
|
7551
|
+
- **Changelog extraction**: Core parsing/escaping logic extracted to \`scripts/changelog-utils.ts\` (shared between prebuild script and tests)
|
|
7552
|
+
- **Narrowed \`.gitignore\`**: Setup-generated patterns scoped to \`compound/\` subdirectories to avoid hiding tracked TDD agent definitions
|
|
7553
|
+
|
|
7554
|
+
## [1.3.1] - 2026-02-21
|
|
7555
|
+
|
|
7556
|
+
### Added
|
|
7557
|
+
|
|
7558
|
+
- **\`ca about\` command**: Displays version with terminal animation (tendril growth) and recent changelog entries. Non-TTY environments get plain text output. Changelog is embedded at build time from CHANGELOG.md.
|
|
7559
|
+
- **3 new doctor checks**: Beads initialized (\`.beads/\` dir), beads healthy (\`bd doctor\`), codebase scope (user-scope detection)
|
|
7560
|
+
- **Beads + scope status in init/setup output**: Full beads health display (CLI available, initialized, healthy) and scope status shown after \`ca init\`, \`ca setup\`, and \`ca setup --update\`
|
|
7561
|
+
- **Banner on \`--update\`**: Terminal art animation now plays during \`ca setup --update\` and \`ca init --update\` (same TTY/quiet guards as fresh install)
|
|
7562
|
+
|
|
7563
|
+
### Changed
|
|
7564
|
+
|
|
7565
|
+
- **Split documentation**: \`HOW_TO_COMPOUND.md\` replaced by 5 focused documents in \`docs/compound/\`: \`README.md\`, \`WORKFLOW.md\`, \`CLI_REFERENCE.md\`, \`SKILLS.md\`, \`INTEGRATION.md\`
|
|
7566
|
+
- **Test-cleaner Phase 3 strengthened**: Adversarial review phase now mandates iteration loop until both reviewers give unconditional approval. Heading, emphasis, and quality criteria updated.
|
|
7567
|
+
- **Update hint on upgrade**: When \`ca init\` or \`ca setup\` detects an existing install, displays tip to run with \`--update\` to regenerate managed files
|
|
7568
|
+
- **HOW_TO_COMPOUND.md migration**: \`ca setup --update\` automatically removes old monolithic \`HOW_TO_COMPOUND.md\` if it has version frontmatter (generated by compound-agent)
|
|
7569
|
+
- **Doctor doc check**: Now checks for \`docs/compound/README.md\` instead of \`HOW_TO_COMPOUND.md\`
|
|
7570
|
+
|
|
7571
|
+
## [1.3.0] - 2026-02-21
|
|
7572
|
+
|
|
7573
|
+
### Added
|
|
7574
|
+
|
|
7575
|
+
- **Setup hardening**: Four new pre-flight checks during \`ca init\` and \`ca setup\`:
|
|
7576
|
+
- **Beads CLI check** (\`beads-check.ts\`): Detects if \`bd\` is available, shows install URL if missing (informational, non-blocking)
|
|
7577
|
+
- **User-scope detection** (\`scope-check.ts\`): Warns when installing at home directory level where lessons are shared across projects
|
|
7578
|
+
- **.gitignore injection** (\`gitignore.ts\`): Ensures \`node_modules/\` and \`.claude/.cache/\` patterns exist in \`.gitignore\`
|
|
7579
|
+
- **Upgrade detection** (\`upgrade.ts\`): Detects existing installs and runs migration pipeline (deprecated command removal, header stripping, doc version update)
|
|
7580
|
+
- **Upgrade engine**: Automated migration from v1.2.x to v1.3.0:
|
|
7581
|
+
- Removes 5 deprecated CLI wrapper commands (\`search.md\`, \`list.md\`, \`show.md\`, \`stats.md\`, \`wrong.md\`)
|
|
7582
|
+
- Strips legacy \`<!-- generated by compound-agent -->\` headers from installed files
|
|
7583
|
+
- Updates \`HOW_TO_COMPOUND.md\` version during upgrade
|
|
7584
|
+
- **\`/compound:research\` skill**: PhD-depth research producing structured survey documents following \`TEMPLATE_FOR_RESEARCH.md\` format
|
|
7585
|
+
- **\`/compound:test-clean\` skill**: 5-phase test suite optimization with adversarial review (audit, design, implement, verify, report)
|
|
7586
|
+
- **Documentation template**: \`HOW_TO_COMPOUND.md\` deployed to \`docs/compound/\` during setup with version and date placeholders
|
|
7587
|
+
- **Test scripts**: \`test:segment\` (run tests for specific module), \`test:random\` (seeded random subset), \`test:critical\` (*.critical.test.ts convention)
|
|
7588
|
+
- **3 new doctor checks**: Beads CLI availability, \`.gitignore\` health, usage documentation presence
|
|
7589
|
+
|
|
7590
|
+
### Fixed
|
|
7591
|
+
|
|
7592
|
+
- **\`setup --update --dry-run\` no longer mutates files**: \`runUpgrade()\` now accepts a \`dryRun\` parameter propagated to all sub-functions (removeDeprecatedCommands, stripGeneratedHeaders, upgradeDocVersion)
|
|
7593
|
+
- **\`setup --uninstall\` respects plugin.json ownership**: Checks \`name === "compound-agent"\` before deleting; user-owned plugin manifests are preserved
|
|
7594
|
+
- **Upgrade ownership guard**: \`removeDeprecatedCommands\` checks file content for compound-agent markers before deleting, preventing silent removal of user-authored files with the same name
|
|
7595
|
+
- **Malformed settings.json no longer silently clobbered**: On parse error, \`configureClaudeSettings\` warns and skips instead of overwriting with empty config
|
|
7596
|
+
|
|
7597
|
+
### Changed
|
|
7598
|
+
|
|
7599
|
+
- **\`setup --update\` overhaul**: Now uses path-based file detection (compound/ = managed) instead of marker-based. Runs upgrade pipeline and \`.gitignore\` remediation during update
|
|
7600
|
+
- **JSON-first \`bd\` parsing in loop**: \`jq\` primary with \`python3\` fallback via \`parse_json()\` helper
|
|
7601
|
+
- **CLI test helpers hardened**: Replaced shell string interpolation with \`execFileSync\` for safety and reliability
|
|
7602
|
+
- **Beads check portable**: Uses POSIX \`command -v\` instead of non-portable \`which\`
|
|
7603
|
+
- **Template expansion**: Brainstorm and plan skills now cross-reference researcher skill; 9 total skills, 11 total commands
|
|
7604
|
+
- **Code organization**: Extracted display utilities to \`display-utils.ts\`, uninstall logic to \`uninstall.ts\`
|
|
7605
|
+
|
|
7606
|
+
### Removed
|
|
7607
|
+
|
|
7608
|
+
- **5 deprecated CLI wrapper commands**: \`search.md\`, \`list.md\`, \`show.md\`, \`stats.md\`, \`wrong.md\` (redundant wrappers around \`npx ca <cmd>\`)
|
|
7609
|
+
- **\`GENERATED_MARKER\` on new installs**: New installs use path-based detection; marker retained only for backward-compatible \`--update\` detection`;
|
|
7610
|
+
|
|
7611
|
+
// src/commands/about.ts
|
|
7612
|
+
function registerAboutCommand(program2) {
|
|
7613
|
+
program2.command("about").description("Show version, animation, and recent changelog").action(async () => {
|
|
7614
|
+
if (process.stdout.isTTY) {
|
|
7615
|
+
await playInstallBanner();
|
|
7616
|
+
} else {
|
|
7617
|
+
console.log(`compound-agent v${VERSION}`);
|
|
7618
|
+
}
|
|
7619
|
+
console.log("");
|
|
7620
|
+
console.log(CHANGELOG_RECENT);
|
|
7621
|
+
});
|
|
7622
|
+
}
|
|
7338
7623
|
function parseWorktreeList(raw) {
|
|
7339
7624
|
const entries = [];
|
|
7340
7625
|
let currentPath = "";
|
|
@@ -8443,6 +8728,7 @@ function registerManagementCommands(program2) {
|
|
|
8443
8728
|
registerRulesCommands(program2);
|
|
8444
8729
|
registerTestSummaryCommand(program2);
|
|
8445
8730
|
registerVerifyGatesCommand(program2);
|
|
8731
|
+
registerAboutCommand(program2);
|
|
8446
8732
|
registerWorktreeCommands(program2);
|
|
8447
8733
|
}
|
|
8448
8734
|
|