Merge pull request #1144 from ChaptersOfFloatingLife/fix/codex-agent-toml-metadata

fix(codex): include required agent metadata in TOML
This commit is contained in:
Tom Boucher
2026-03-19 12:12:08 -04:00
committed by GitHub
2 changed files with 26 additions and 2 deletions

View File

@@ -964,14 +964,22 @@ purpose: ${toSingleLine(description)}
/**
* Generate a per-agent .toml config file for Codex.
* Sets sandbox_mode and developer_instructions from the agent markdown body.
* Sets required agent metadata, sandbox_mode, and developer_instructions
* from the agent markdown content.
*/
function generateCodexAgentToml(agentName, agentContent) {
const sandboxMode = CODEX_AGENT_SANDBOX[agentName] || 'read-only';
const { body } = extractFrontmatterAndBody(agentContent);
const { frontmatter, body } = extractFrontmatterAndBody(agentContent);
const frontmatterText = frontmatter || '';
const resolvedName = extractFrontmatterField(frontmatterText, 'name') || agentName;
const resolvedDescription = toSingleLine(
extractFrontmatterField(frontmatterText, 'description') || `GSD agent ${resolvedName}`
);
const instructions = body.trim();
const lines = [
`name = ${JSON.stringify(resolvedName)}`,
`description = ${JSON.stringify(resolvedDescription)}`,
`sandbox_mode = "${sandboxMode}"`,
// Agent prompts contain raw backslashes in regexes and shell snippets.
// TOML literal multiline strings preserve them without escape parsing.

View File

@@ -160,6 +160,19 @@ tools: Read, Grep, Glob
assert.ok(result.includes("'''"), 'has closing literal triple quotes');
});
test('includes required name and description fields', () => {
const result = generateCodexAgentToml('gsd-executor', sampleAgent);
assert.ok(result.includes('name = "gsd-executor"'), 'has name');
assert.ok(result.includes('description = "Executes plans"'), 'has description');
});
test('falls back to generated description when frontmatter is missing fields', () => {
const minimalAgent = `<role>You are an unknown agent.</role>`;
const result = generateCodexAgentToml('gsd-unknown', minimalAgent);
assert.ok(result.includes('name = "gsd-unknown"'), 'falls back to agent name');
assert.ok(result.includes('description = "GSD agent gsd-unknown"'), 'falls back to synthetic description');
});
test('defaults unknown agents to read-only', () => {
const result = generateCodexAgentToml('gsd-unknown', sampleAgent);
assert.ok(result.includes('sandbox_mode = "read-only"'), 'defaults to read-only');
@@ -515,10 +528,13 @@ describe('installCodexConfig (integration)', () => {
assert.ok(fs.existsSync(path.join(agentsDir, 'gsd-plan-checker.toml')), 'plan-checker .toml exists');
const executorToml = fs.readFileSync(path.join(agentsDir, 'gsd-executor.toml'), 'utf8');
assert.ok(executorToml.includes('name = "gsd-executor"'), 'executor has name');
assert.ok(executorToml.includes('description = "Executes GSD plans with atomic commits, deviation handling, checkpoint protocols, and state management. Spawned by execute-phase orchestrator or execute-plan command."'), 'executor has description');
assert.ok(executorToml.includes('sandbox_mode = "workspace-write"'), 'executor is workspace-write');
assert.ok(executorToml.includes('developer_instructions'), 'has developer_instructions');
const checkerToml = fs.readFileSync(path.join(agentsDir, 'gsd-plan-checker.toml'), 'utf8');
assert.ok(checkerToml.includes('name = "gsd-plan-checker"'), 'plan-checker has name');
assert.ok(checkerToml.includes('sandbox_mode = "read-only"'), 'plan-checker is read-only');
});
});