From 33c00d3d7a9d72c75a76d344cddf9fec24bc169a Mon Sep 17 00:00:00 2001 From: Aly Dhedhi <91044156+dhedhialy@users.noreply.github.com> Date: Thu, 9 Jul 2026 12:03:43 -0400 Subject: [PATCH] fix: Codex CLI SessionStart additionalContext at top level (#505) (#508) * fix: Codex CLI SessionStart additionalContext at top level (#505) Codex CLI expects additionalContext at the top level of the hook output, not nested under hookSpecificOutput. Flattened the Codex branch of writeHookOutput so the injected instructions actually reach the agent. Fixes #505 * Merge main; move #99 Codex @ponytail report assertion to top-level additionalContext (#505) --------- Co-authored-by: Emeriko --- hooks/ponytail-runtime.js | 8 ++++---- tests/hooks.test.js | 9 +++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/hooks/ponytail-runtime.js b/hooks/ponytail-runtime.js index 37d682f..7b5a662 100644 --- a/hooks/ponytail-runtime.js +++ b/hooks/ponytail-runtime.js @@ -43,10 +43,10 @@ function writeHookOutput(event, mode, context = '') { if (isCodex) { const output = { systemMessage: `PONYTAIL:${mode.toUpperCase()}` }; if (context) { - output.hookSpecificOutput = { - hookEventName: event, - additionalContext: context, - }; + // ponytail: Codex CLI expects additionalContext at top level, not nested + // under hookSpecificOutput. The hookSpecificOutput wrapper is for Claude + // Code's SubagentStart. See issue #505. + output.additionalContext = context; } process.stdout.write(JSON.stringify(output)); return; diff --git a/tests/hooks.test.js b/tests/hooks.test.js index 5389850..bc2ab20 100644 --- a/tests/hooks.test.js +++ b/tests/hooks.test.js @@ -61,9 +61,10 @@ assert.equal(fs.readFileSync(codexState, 'utf8'), 'ultra'); let output = JSON.parse(result.stdout); assert.equal(output.systemMessage, 'PONYTAIL:ULTRA'); assert.match( - output.hookSpecificOutput.additionalContext, + output.additionalContext, /PONYTAIL MODE ACTIVE — level: ultra/, ); +assert.equal(output.hookSpecificOutput, undefined, 'Codex should not use hookSpecificOutput (#505)'); result = run( 'ponytail-mode-tracker.js', @@ -85,7 +86,7 @@ assert.equal(result.status, 0, result.stderr); assert.equal(fs.readFileSync(codexState, 'utf8'), 'lite'); output = JSON.parse(result.stdout); assert.match( - output.hookSpecificOutput.additionalContext, + output.additionalContext, /PONYTAIL MODE ACTIVE — level: lite/, ); @@ -229,8 +230,8 @@ result = run('ponytail-subagent.js', { HOME: subHome, USERPROFILE: subHome, PLUG assert.equal(result.status, 0, result.stderr); output = JSON.parse(result.stdout); assert.equal(output.systemMessage, 'PONYTAIL:FULL'); -assert.equal(output.hookSpecificOutput.hookEventName, 'SubagentStart'); -assert.match(output.hookSpecificOutput.additionalContext, /PONYTAIL MODE ACTIVE — level: full/); +assert.ok(output.additionalContext, 'Codex SubagentStart should have additionalContext at top level (#505)'); +assert.match(output.additionalContext, /PONYTAIL MODE ACTIVE — level: full/); // SubagentStart scoping (issue #506): PONYTAIL_SUBAGENT_MATCHER limits the // injection to agent types whose name matches the regex. Unset keeps the