UserPromptSubmit hooks drop image attachments from the hook payload

Open 💬 1 comment Opened Aug 27, 2026 by zzh-newlearner

Current behavior

A UserPromptSubmit command hook only receives the string prompt. In codex-rs/core/src/hook_runtime.rs, the request is built with UserMessageItem::new(content).message(). That helper concatenates UserInput::Text items and returns an empty string for Image, LocalImage, Audio, LocalAudio, Skill, and Mention items.

The hook request and generated user-prompt-submit.command.input schema therefore expose no attachment or structured-content field, even though the turn later serializes the complete UserInput list to the model request.

A hook cannot tell whether a submitted prompt included an image, cannot distinguish image-only input from an empty text prompt, and cannot apply attachment-aware audit or policy logic.

Expected behavior

UserPromptSubmit should expose the submitted content in a structured, ordered form, while retaining the existing prompt string for backward compatibility. At minimum, image/local-image entries should include their type, position, media type when known, detail, and local path when applicable. This should also cover audio and other UserInput variants so the hook contract represents the user submission faithfully.

Raw data URLs need an explicit design decision: exposing them lets trusted hooks inspect or scan image bytes but can substantially increase stdin size and widens sensitive-data exposure. A metadata-only default or an explicit opt-in would avoid silently changing that property.

Suggested implementation

  1. Add a backward-compatible content field to UserPromptSubmitRequest and UserPromptSubmitCommandInput rather than deriving hook input from UserMessageItem::message().
  1. Define a bounded, hook-specific wire representation for each UserInput variant; preserve ordering and avoid unbounded inline payloads by default.
  1. Regenerate the hook schema with just write-hooks-schema.
  1. Add a core integration test that submits text plus Image and verifies the captured hook stdin contains both entries, plus tests for image-only and local-image cases.

Reproduction

Configure a UserPromptSubmit command hook that records stdin, then submit text with a pasted image. The model receives the image, but the hook payload contains only the text prompt and no indication that an image was attached.

Related issues checked

#20204 tracks missing PreToolUse coverage for several tool handlers. It does not cover UserPromptSubmit payload content or user-image attachments.

View original on GitHub ↗

1 Comment

zzh-newlearner · 22 hours ago

A compatibility point for the proposed structured payload:

Adding a content property to the current JSON shape can break handlers that deserialize stdin with unknown-field rejection. Please make the richer contract an explicit opt-in format, for example inputFormat = structured_v2, while existing handlers continue to receive the exact v1 payload.

The v2 representation should preserve input order and cover the complete UserInput union, including text, image, local image, audio, local audio, skill, and mention. That avoids fixing images while leaving the same observability gap for later input types.

Suggested acceptance coverage:

  1. Existing v1 handler receives its current payload unchanged.
  2. V2 handler receives ordered mixed text/image input.
  3. Image-only, local-image, audio, skill, and mention inputs have distinct representations.
  4. Generated hook schemas are updated by just write-hooks-schema.