opencode discovers AGENTS.md and nothing else — its only target is
H.up({targets:["AGENTS.md"]}), verified in the binary. claude code discovers
CLAUDE.md. no overlap.
every brief the platform wrote was CLAUDE.md, so under opencode a commander got
none of its standing brief, a bot none of its arming instructions, and a plugin
chat none of its plugin's guidance. nothing failed and nothing was logged: the
agent simply knew nothing, which is indistinguishable from the feature not
existing, and is why it lasted this long. commanders can already run under
opencode, so this was live.
writeAgentBrief puts the content in AGENTS.md and a POINTER in CLAUDE.md. a
pointer rather than two copies because these are rewritten every turn, two
copies of that will eventually disagree, and the stale one is the one somebody
reads.
three writers, and the third needed a flag the others must not have:
bots rewritten every turn ON PURPOSE, so a template change reaches them
plugin chats same
commanders onlyIfAbsent — a commander EXTENDS this file over its life, and
rewriting it when the template changed would delete the job it
had agreed with the owner
two things that would have quietly defeated it. the file listing handed to a
commander said "CLAUDE.md — this file", which would have had it editing the
pointer. and backfill-commander-credentials appended to CLAUDE.md, which on a
new commander means burying a credential section inside six lines nobody reads —
it targets AGENTS.md where one exists, CLAUDE.md where it does not, so old
commanders still work.
plugins ship these too: email and proxy-manager's chat/CLAUDE.md are now
chat/AGENTS.md. the platform accepts BOTH source names, because a plugin is its
own repository on its own release cadence and dropping the old name would
un-brief any installed copy that had not updated — silently, again.
tested: both files written, pointer is not a second copy, idempotent, rewrites
on change, and onlyIfAbsent leaves an extended brief alone. verified on disk
after a restart.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Officer-Session: 656f5c85-e49a-4f1f-b9f3-042a04b4d043
69 lines
2.9 KiB
TypeScript
69 lines
2.9 KiB
TypeScript
import { describe, expect, test, afterAll } from 'bun:test';
|
|
import { mkdtempSync, rmSync, readFileSync, existsSync, writeFileSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
import { writeAgentBrief } from './agent-brief';
|
|
|
|
/**
|
|
* Both harnesses have to find the brief.
|
|
*
|
|
* Claude Code discovers `CLAUDE.md`, opencode discovers `AGENTS.md` and nothing else. Every brief the
|
|
* platform wrote was `CLAUDE.md`, so under opencode a commander, a bot and a plugin chat were each
|
|
* briefed with nothing — silently, which is why it lasted.
|
|
*/
|
|
|
|
const root = mkdtempSync(join(tmpdir(), 'agent-brief-'));
|
|
afterAll(() => rmSync(root, { recursive: true, force: true }));
|
|
|
|
const dir = (name: string) => {
|
|
const d = join(root, name);
|
|
rmSync(d, { recursive: true, force: true });
|
|
Bun.spawnSync(['mkdir', '-p', d]);
|
|
return d;
|
|
};
|
|
|
|
describe('writeAgentBrief', () => {
|
|
test('writes the content as AGENTS.md and a POINTER as CLAUDE.md', async () => {
|
|
const d = dir('both');
|
|
await writeAgentBrief(d, '# Brief\n\nthe real instructions\n');
|
|
|
|
expect(readFileSync(join(d, 'AGENTS.md'), 'utf8')).toContain('the real instructions');
|
|
const pointer = readFileSync(join(d, 'CLAUDE.md'), 'utf8');
|
|
expect(pointer).toContain('AGENTS.md');
|
|
// The pointer must NOT be a second copy — two copies of a file rewritten every turn will disagree,
|
|
// and the stale one is the one somebody reads.
|
|
expect(pointer).not.toContain('the real instructions');
|
|
});
|
|
|
|
test('is idempotent — an unchanged brief writes nothing', async () => {
|
|
const d = dir('idempotent');
|
|
expect(await writeAgentBrief(d, 'same\n')).toBe(true);
|
|
expect(await writeAgentBrief(d, 'same\n')).toBe(false);
|
|
});
|
|
|
|
test('rewrites when the content changes, because that is how a template reaches a bot', async () => {
|
|
const d = dir('rewrite');
|
|
await writeAgentBrief(d, 'v1\n');
|
|
expect(await writeAgentBrief(d, 'v2\n')).toBe(true);
|
|
expect(readFileSync(join(d, 'AGENTS.md'), 'utf8')).toBe('v2\n');
|
|
});
|
|
|
|
test('onlyIfAbsent never touches a brief the agent has extended', async () => {
|
|
// A commander writes its own job into this file over days. Rewriting it because the template
|
|
// changed would delete what it agreed with the owner.
|
|
const d = dir('extended');
|
|
await writeAgentBrief(d, 'generated\n');
|
|
writeFileSync(join(d, 'AGENTS.md'), 'generated\n\n## JOB\n\nwatch the thing\n');
|
|
|
|
expect(await writeAgentBrief(d, 'a new template\n', { onlyIfAbsent: true })).toBe(false);
|
|
expect(readFileSync(join(d, 'AGENTS.md'), 'utf8')).toContain('watch the thing');
|
|
});
|
|
|
|
test('onlyIfAbsent still creates both files the first time', async () => {
|
|
const d = dir('first');
|
|
expect(await writeAgentBrief(d, 'generated\n', { onlyIfAbsent: true })).toBe(true);
|
|
expect(existsSync(join(d, 'AGENTS.md'))).toBe(true);
|
|
expect(existsSync(join(d, 'CLAUDE.md'))).toBe(true);
|
|
});
|
|
});
|