Render `UserPromptSubmit.additionalContext` as multiline hook context in the TUI
What version of Codex CLI is running?
0.118.0
What subscription do you have?
Plus
Which model were you using?
_No response_
What platform is your computer?
_No response_
What terminal emulator and version are you using (if applicable)?
_No response_
What issue are you seeing?
UserPromptSubmit.hookSpecificOutput.additionalContext is already treated as the model-visible hook context surface, and the core pipeline preserves it as a raw string, including newlines.
Relevant code paths:
codex-rs/hooks/src/schema.rs
``rust``
pub(crate) struct UserPromptSubmitHookSpecificOutputWire {
pub hook_event_name: HookEventNameWire,
#[serde(default)]
pub additional_context: Option<String>,
}
codex-rs/hooks/src/engine/output_parser.rs
``rust``
let additional_context = wire
.hook_specific_output
.and_then(|output| output.additional_context);
codex-rs/core/src/hook_runtime.rs
``rust``
fn additional_context_messages(additional_contexts: Vec<String>) -> Vec<ResponseItem> {
additional_contexts
.into_iter()
.map(|additional_context| DeveloperInstructions::new(additional_context).into())
.collect()
}
So the injected content path already supports structured multiline text.
The TUI side does not present that structure cleanly. It currently prefixes the whole entry with hook context: and renders it as one formatted line:
codex-rs/tui/src/chatwidget.rs
``rust``
let prefix = match entry.kind {
codex_protocol::protocol::HookOutputEntryKind::Context => "hook context: ",
// ...
};
lines.push(format!(" {prefix}{}", entry.text).into());
This makes structured hook context hard to read in the TUI. In practice, hook authors are pushed to flatten rich context into synthetic one-line encodings such as:
[Action now]: ...; [Authority]: ...; [Wait rule]: ...
instead of emitting the more natural multiline content they actually want the model to see, for example:
Action now
- Keep replying with plan preview only.
- Do not emit the wrapped full plan.
Authority
- Managed planning is active.
Wait rule
- If managed evidence is needed, spawn a managed sub-agent first.
What steps can reproduce the bug?
- Register a
UserPromptSubmithook that returns multilineadditionalContext. - Example hook output:
{
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "Action now\n- Keep replying with plan preview only.\n- Do not emit the wrapped full plan.\n\nAuthority\n- Managed planning is active."
}
}
- Trigger the hook in the Codex TUI.
- Observe the rendered hook notification in the transcript/history area.
Minimal behavior to inspect:
- model-side injection path preserves the raw string
- TUI-side hook notification path does not render the structure as a readable multiline block
What is the expected behavior?
The TUI should render HookOutputEntryKind::Context using the exact text structure carried in additionalContext, including line breaks.
For example:
UserPromptSubmit hook (completed)
hook context:
Action now
- Keep replying with plan preview only.
- Do not emit the wrapped full plan.
Authority
- Managed planning is active.
At minimum:
- multiline
additionalContextshould not force hook authors to collapse content into a single line - the TUI-visible content should preserve the same structure that gets injected as developer instructions
- only the host prefix should differ; the body should stay semantically identical
Additional information
Why this matters:
- Hook authors often need to send structured policy or coordination context to the model.
- The cleanest machine/human shape for that content is often multiline Markdown-like text.
- The current TUI rendering strongly encourages ugly one-line serialization purely for display.
- That makes hook debugging harder, because the operator sees a degraded version of the intended context shape.
- It also pushes hook implementations to optimize for host rendering instead of clear model guidance.
Suggested implementation direction:
- In
codex-rs/tui/src/chatwidget.rs, special-caseHookOutputEntryKind::Contextwhenentry.textcontains\n. - Render a standalone
hook context:label line, then append the body as indented lines rather thanformat!(" {prefix}{}", entry.text). - Keep the underlying injected
additionalContextstring unchanged in core/hooks.
Duplicate-issue search:
- I searched open issues in
openai/codexfor combinations ofUserPromptSubmit,additionalContext,hook context,multiline, andTUI. - I did not find a clear duplicate for this exact topic.
- Closest but different issues:
#5253about missing interrupted tool-call context, not hook context rendering: https://github.com/openai/codex/issues/5253#4790about prior tool calls disappearing from the TUI transcript, not multiline hook rendering: https://github.com/openai/codex/issues/4790
Generated with Codex CLI.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗