[FEATURE] Serialize interactive prompts as structured output in `-p` (non-interactive) mode
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet
- [x] This is a single feature request (not multiple features)
Problem Statement
When running Claude Code in non-interactive mode (-p), if the model decides it needs clarification from the user, it triggers an interactive multi-select prompt (the Ink-based TUI widget with numbered options and arrow-key navigation). Since there is no TTY in -p mode, this prompt cannot render, and the CLI either hangs indefinitely or silently returns no output.
This is a silent failure. The caller has no way to:
- Know that a clarification question was triggered
- Read the question and its options
- Provide an answer programmatically
This makes -p mode unreliable for automation, CI/CD pipelines, and scripting, because you cannot predict when the model will decide to ask a follow-up question. Adding prompt instructions like "don't ask questions" is a workaround, but it's fragile — there's no guarantee the model will comply.
Reproduction
- Create a complex prompt that involves ambiguous design decisions (e.g., a multi-phase code analysis task)
- Run it with
claude -p "your complex prompt" - If the model decides it needs clarification → no output, process hangs or exits
Use cases affected
- CI/CD pipelines: A build step using
claude -pthat needs to handle ambiguous tasks - Wrapper scripts: Tools that orchestrate multiple
claude -pcalls and need to handle clarification loops - Batch processing: Running the same prompt against multiple codebases where some trigger questions and others don't
Related issues:
- #17603 — Model doesn't know it's in
-pmode - #581 — Non-interactive mode doesn't respect configured tool permissions
- #6009 — Feature request for piping input to interactive sessions
Proposed Solution
When running in -p mode and the model triggers an interactive prompt (multi-select, single-select, confirmation, or free-text input), serialize it as structured output to stdout instead of attempting to render a TUI widget.
Proposed output format (JSON, when using --output-format json)
{
"type": "input_required",
"input_type": "single_select",
"question": "How should the existing project be matched for deletion before loading?",
"options": [
{
"index": 1,
"label": "Name + user_id",
"description": "Match on project name and user. Works when IDs differ between machines."
},
{
"index": 2,
"label": "Same project ID",
"description": "Assume the project ID in the dump matches the local ID."
},
{
"index": 3,
"label": "User chooses",
"description": "User manually selects which local project to replace."
}
],
"session_id": "abc123"
}
Re-invocation with answer
The caller can then re-invoke Claude with the answer using --resume:
claude -p "2" --resume "abc123" --output-format json
Plain text fallback (without --output-format json)
[INPUT REQUIRED] How should the existing project be matched for deletion before loading?
1. Name + user_id — Match on project name and user. Works when IDs differ between machines.
2. Same project ID — Assume the project ID in the dump matches the local ID.
3. User chooses — User manually selects which local project to replace.
Session ID: abc123
Resume with: claude -p "<your choice>" --resume "abc123"
Alternatives considered
- Adding "don't ask questions" to the prompt — Fragile. The model may still decide to ask. And sometimes the questions are genuinely important and shouldn't be auto-resolved.
--dangerously-skip-permissions— Only covers tool permission prompts, not model-initiated clarification questions.- Piping
yesorecho "1"to stdin — Doesn't work because the Ink TUI doesn't read from stdin in the same way. - A
--no-interactiveflag that auto-resolves — Less useful than serializing, because the caller loses visibility into what was decided.
Alternative Solutions
- Adding "don't ask questions" to the prompt — Works sometimes but is fragile. The model may still decide to ask, and sometimes the clarification questions are genuinely important.
--dangerously-skip-permissions— Only covers tool permission prompts, not model-initiated clarification questions.- Piping
yesorecho "1"to stdin — Doesn't work because the Ink TUI doesn't read from stdin in-pmode. - A
--no-interactiveflag that auto-resolves — Less useful than serializing, because the caller loses visibility into what the model decided and why.
Priority
High - Significant impact on productivity
Feature Category
CLI commands and flags
Use Case Example
Example scenario:
- I have a complex multi-phase prompt that runs a domain analysis followed by a technical architecture phase for a Yii2/PHP codebase
- I run
claude -p "$(cat my-prompt.md)" --output-format jsonin a wrapper script - The model encounters an ambiguous design decision and triggers a multi-select prompt asking me to choose between 3 matching strategies
- In interactive mode, this renders a nice TUI with arrow-key selection — works great
- In
-pmode: silent failure — no output, no error, process hangs or exits with empty result - My wrapper script has no way to detect this happened, capture the question, or provide an answer
With this feature, step 5 would instead return a JSON object with "type": "input_required", and my wrapper script could:
- Parse the question and options
- Present them to the user via its own UI
- Re-invoke with
claude -p "2" --resume "session_id" - Or auto-select based on predefined rules
Additional Context
This is a significant gap in the -p mode contract. Currently, -p mode promises non-interactive execution, but the model can unilaterally break that contract by deciding to ask a clarification question. The caller has no way to handle this gracefully — it's a silent failure with no error code, no stderr output, and no way to detect or recover.
The --output-format stream-json mode would be a natural fit for emitting these input-required events as part of the JSON stream.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗