docs(agents): standardize required_reading patterns across agent specs (#2176)

Closes #2168

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Tibsfox
2026-04-12 14:56:19 -07:00
committed by GitHub
parent b2febdec2f
commit 67f5c6fd1d
30 changed files with 130 additions and 50 deletions

View File

@@ -0,0 +1,78 @@
/**
* GSD Agent Required Reading Consistency Tests
*
* Validates that all agent .md files use the standardized <required_reading>
* pattern and that no legacy <files_to_read> blocks remain.
*
* See: https://github.com/gsd-build/get-shit-done/issues/2168
*/
const { test, describe } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');
const AGENTS_DIR = path.join(__dirname, '..', 'agents');
const ALL_AGENTS = fs.readdirSync(AGENTS_DIR)
.filter(f => f.startsWith('gsd-') && f.endsWith('.md'))
.map(f => f.replace('.md', ''));
// ─── No Legacy files_to_read Blocks ────────────────────────────────────────
describe('READING: no legacy <files_to_read> blocks remain', () => {
for (const agent of ALL_AGENTS) {
test(`${agent} does not contain <files_to_read>`, () => {
const content = fs.readFileSync(path.join(AGENTS_DIR, agent + '.md'), 'utf-8');
assert.ok(
!content.includes('<files_to_read>'),
`${agent} still has <files_to_read> opening tag — migrate to <required_reading>`
);
assert.ok(
!content.includes('</files_to_read>'),
`${agent} still has </files_to_read> closing tag — migrate to </required_reading>`
);
});
}
test('no backtick references to files_to_read in any agent', () => {
for (const agent of ALL_AGENTS) {
const content = fs.readFileSync(path.join(AGENTS_DIR, agent + '.md'), 'utf-8');
assert.ok(
!content.includes('`<files_to_read>`'),
`${agent} still references \`<files_to_read>\` in prose — update to \`<required_reading>\``
);
}
});
});
// ─── Standardized required_reading Pattern ─────────────────────────────────
describe('READING: agents with reading blocks use <required_reading>', () => {
// Agents that have any kind of reading instruction should use required_reading
const AGENTS_WITH_READING = ALL_AGENTS.filter(name => {
const content = fs.readFileSync(path.join(AGENTS_DIR, name + '.md'), 'utf-8');
return content.includes('required_reading') || content.includes('files_to_read');
});
test('at least 20 agents have reading instructions', () => {
assert.ok(
AGENTS_WITH_READING.length >= 20,
`Expected at least 20 agents with reading instructions, found ${AGENTS_WITH_READING.length}`
);
});
for (const agent of AGENTS_WITH_READING) {
test(`${agent} uses required_reading (not files_to_read)`, () => {
const content = fs.readFileSync(path.join(AGENTS_DIR, agent + '.md'), 'utf-8');
assert.ok(
content.includes('required_reading'),
`${agent} has reading instructions but does not use required_reading`
);
assert.ok(
!content.includes('files_to_read'),
`${agent} still uses files_to_read — must be migrated to required_reading`
);
});
}
});

View File

@@ -89,13 +89,13 @@ describe('gates taxonomy (#1715)', () => {
test('gsd-plan-checker.md references gates.md in required_reading block', () => {
const planChecker = path.join(ROOT, 'agents', 'gsd-plan-checker.md');
const content = fs.readFileSync(planChecker, 'utf-8');
const match = content.match(/<required_reading>\n([\s\S]*?)\n<\/required_reading>/);
assert.ok(
content.includes('<required_reading>'),
match,
'gsd-plan-checker.md must have a <required_reading> block'
);
const reqBlock = content.split('<required_reading>')[1].split('</required_reading>')[0];
assert.ok(
reqBlock.includes('references/gates.md'),
match[1].includes('references/gates.md'),
'gsd-plan-checker.md must reference gates.md inside <required_reading>'
);
});
@@ -103,13 +103,13 @@ describe('gates taxonomy (#1715)', () => {
test('gsd-verifier.md references gates.md in required_reading block', () => {
const verifier = path.join(ROOT, 'agents', 'gsd-verifier.md');
const content = fs.readFileSync(verifier, 'utf-8');
const match = content.match(/<required_reading>\n([\s\S]*?)\n<\/required_reading>/);
assert.ok(
content.includes('<required_reading>'),
match,
'gsd-verifier.md must have a <required_reading> block'
);
const reqBlock = content.split('<required_reading>')[1].split('</required_reading>')[0];
assert.ok(
reqBlock.includes('references/gates.md'),
match[1].includes('references/gates.md'),
'gsd-verifier.md must reference gates.md inside <required_reading>'
);
});

View File

@@ -217,7 +217,9 @@ describe('verification overrides reference (#1747)', () => {
verifierContent = verifierContent || fs.readFileSync(verifierPath, 'utf-8');
const roleEnd = verifierContent.indexOf('</role>');
const projectCtx = verifierContent.indexOf('<project_context>');
const reqReading = verifierContent.indexOf('<required_reading>');
// Use regex to find the actual XML tag (on its own line), not backtick-escaped prose mentions
const reqMatch = verifierContent.match(/^<required_reading>/m);
const reqReading = reqMatch ? reqMatch.index : -1;
assert.ok(roleEnd > -1, '</role> tag should exist');
assert.ok(projectCtx > -1, '<project_context> tag should exist');
assert.ok(reqReading > -1, '<required_reading> tag should exist');