From ee8efcac3dfcebb3a87fa589273530d11099dcbc Mon Sep 17 00:00:00 2001 From: Shivakumar Date: Tue, 7 Jul 2026 23:31:44 +0530 Subject: [PATCH 1/2] =?UTF-8?q?fix(ponytail):=20Codex=20hook=20output=20?= =?UTF-8?q?=E2=80=94=20additionalContext=20at=20top=20level,=20not=20neste?= =?UTF-8?q?d?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Codex CLI expects additionalContext at JSON root, not under hookSpecificOutput - Matches upstream ponytail#508 fix - Other platforms (Claude, Copilot, Fallback) unchanged - Closes ponytail PR audit ticket #64 --- crates/ponytail/src/platform.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/crates/ponytail/src/platform.rs b/crates/ponytail/src/platform.rs index 289a6c5e..858f2328 100644 --- a/crates/ponytail/src/platform.rs +++ b/crates/ponytail/src/platform.rs @@ -34,12 +34,7 @@ pub fn format_hook_output(event: &str, ctx: &str, platform: &AgentPlatform) -> S .to_string() } AgentPlatform::Codex => { - let mut output = json!({ - "hookSpecificOutput": { - "hookEventName": event, - "additionalContext": ctx, - } - }); + let mut output = json!({ "additionalContext": ctx }); if event == "SessionStart" { output["systemMessage"] = json!("PONYTAIL:FULL"); } From 253dcb8f7d58ee5a691cf608f1a29acbcba91258 Mon Sep 17 00:00:00 2001 From: Shivakumar Date: Wed, 8 Jul 2026 00:04:44 +0530 Subject: [PATCH 2/2] test(ponytail): add regression tests for Codex flat hook output shape - Test non-SessionStart: flat JSON, no hookSpecificOutput or hookEventName - Test SessionStart: includes systemMessage with additionalContext at top level - Lock in the flattened Codex contract against regression --- crates/ponytail/src/platform.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/crates/ponytail/src/platform.rs b/crates/ponytail/src/platform.rs index 858f2328..5a9693cc 100644 --- a/crates/ponytail/src/platform.rs +++ b/crates/ponytail/src/platform.rs @@ -50,3 +50,26 @@ pub fn format_hook_output(event: &str, ctx: &str, platform: &AgentPlatform) -> S AgentPlatform::Fallback => ctx.to_string(), } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn codex_non_session_start_is_flat_json() { + let output = format_hook_output("SubagentStart", "test context", &AgentPlatform::Codex); + let parsed: serde_json::Value = serde_json::from_str(&output).unwrap(); + assert_eq!(parsed["additionalContext"], "test context"); + assert!(parsed.get("hookSpecificOutput").is_none()); + assert!(parsed.get("hookEventName").is_none()); + } + + #[test] + fn codex_session_start_includes_system_message() { + let output = format_hook_output("SessionStart", "test context", &AgentPlatform::Codex); + let parsed: serde_json::Value = serde_json::from_str(&output).unwrap(); + assert_eq!(parsed["systemMessage"], "PONYTAIL:FULL"); + assert_eq!(parsed["additionalContext"], "test context"); + assert!(parsed.get("hookSpecificOutput").is_none()); + } +}