also looking at this
Brief agents on the environment a fresh checkout cannot infer
#319
4 files
+126
-0
| @@ -0,0 +1,45 @@ | ||
| 1 | /** | |
| 2 | * Keeps `AGENTS.md` a real briefing rather than a copy of `CLAUDE.md`. | |
| 3 | * | |
| 4 | * `AGENTS.md` is the only thing a coding agent working from a fresh checkout | |
| 5 | * reads before it runs a command. It was byte-identical to `CLAUDE.md` below | |
| 6 | * its title, so it carried the house rules and none of the environment facts | |
| 7 | * that a machine without this repository's history cannot discover. | |
| 8 | * | |
| 9 | * Every topic below cost a real, separately diagnosed build failure here, in | |
| 10 | * this order: an unpinned `zig` on PATH, the absent sibling checkouts, and a | |
| 11 | * `bun test` that ran the wrong suite. None of them are code defects and none | |
| 12 | * are visible from the tree, which is exactly why they belong in writing. | |
| 13 | */ | |
| 14 | ||
| 15 | /** Facts an agent cannot derive from the tree, each with the words that prove it was written down. */ | |
| 16 | const briefings: { topic: string, needles: string[] }[] = [ | |
| 17 | { topic: 'the pinned Zig toolchain', needles: ['CRAFT_ZIG', 'pantry.lock'] }, | |
| 18 | { topic: 'the sibling first-party checkouts', needles: ['Libraries/zig-js', 'pins.env'] }, | |
| 19 | { topic: 'which suite each test script runs', needles: ['bun run test:sdk'] }, | |
| 20 | ] | |
| 21 | ||
| 22 | /** House rules that must survive any rewrite, since the copy is where they came from. */ | |
| 23 | const houseRules = ['pickier', 'buddy-bot', 'conventional commit'] | |
| 24 | ||
| 25 | /** The text below the first heading, which is the only line the two files are meant to differ on. */ | |
| 26 | function body(text: string): string { | |
| 27 | return text.split('\n').slice(1).join('\n').trim() | |
| 28 | } | |
| 29 | ||
| 30 | export function checkAgentsGuidelines(agents: string, claude: string): void { | |
| 31 | if (body(agents) === body(claude)) | |
| 32 | throw new Error('AGENTS.md repeats CLAUDE.md below its title, so it briefs none of the environment a fresh checkout needs') | |
| 33 | ||
| 34 | for (const { topic, needles } of briefings) { | |
| 35 | const missing = needles.filter(needle => !agents.includes(needle)) | |
| 36 | if (missing.length) | |
| 37 | throw new Error(`AGENTS.md does not brief ${topic}; expected to find ${missing.join(' and ')}`) | |
| 38 | } | |
| 39 | ||
| 40 | const lowered = agents.toLowerCase() | |
| 41 | for (const rule of houseRules) { | |
| 42 | if (!lowered.includes(rule)) | |
| 43 | throw new Error(`AGENTS.md dropped the shared house rule: ${rule}`) | |
| 44 | } | |
| 45 | } | |