Feature request: let PostToolUse hooks replace tool output (updatedToolOutput)
Motivation
We build toonify-mcp, a context-compression tool: it converts large JSON/YAML tool output to a compact tabular format and collapses repetitive logs (60%+ token reduction on realistic payloads), while passing through anything it can't reproduce losslessly.
On Claude Code this works as a PostToolUse hook that returns hookSpecificOutput.updatedToolOutput, which replaces what the model sees — that replacement is what actually shrinks context.
Current Codex behavior
PostToolUseOutcome supports block / additionalContext / feedback, but no output replacement. The output parser already recognizes a Claude-style updatedMCPToolOutput field — and explicitly rejects it as unsupported (codex-rs/hooks/src/events/post_tool_use.rs, unsupported_updated_mcp_tool_output_fails_open), so the concept appears to be on your radar already.
additionalContext can't serve this use case: appending a compressed copy on top of the original output makes context larger, the exact opposite of the goal.
Request
Support an updatedToolOutput (and/or the already-parsed updatedMCPToolOutput) in PostToolUse hook output that replaces the tool result before it enters model context — schema-checked against the tool's output type, with fail-open on mismatch, like the current unsupported-field handling.
This would let context-optimization tools (compression, redaction, truncation policies) work across both ecosystems with the same hook contract.
2 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
Verified against
main(1f41cc5d92), and the symmetric precedent makes this a well-bounded ask: PreToolUse already does replacement. The registry's dispatch loop handlesPreToolUseHookResult::Continue { updated_input: Some(_) }by rebuilding the invocation viawith_updated_hook_inputbefore the tool runs (https://github.com/openai/codex/blob/1f41cc5d92/codex-rs/core/src/tools/registry.rs#L590-L608). So the architecture already accepts "hook rewrites the payload, fail closed on malformed rewrite" — the request is the mirror image on the result side, applied betweenhandle_any_toolreturning and the output entering history.And as noted, the parser half-exists:
updatedMCPToolOutputis recognized and deliberately failed-open with "returned unsupported updatedMCPToolOutput" (hooks/src/events/post_tool_use.rs#L410-L431), so the wire contract is already parsed — only the application step is missing.Design details from the input-side precedent worth copying: schema-check the replacement against the tool's output shape and treat mismatch like the current unsupported-field fail-open (never lose the original output); and record both original and replaced output in the rollout so
/feedbackand debugging keep ground truth while only the replacement reaches model context.