[FEATURE] `claude -p` 3-second stdin timeout breaks `vipe`-style edit-in-pipeline workflows
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
claude -p aborts after a 3-second stdin inactivity timeout, which breaks the common "edit the stream in $EDITOR mid-pipeline" idiom built on vipe (moreutils). The timeout fires while the editor is still open, so the prompt is never sent. The error message even says input is required — but the process exits instead of waiting for it.
Reproduction:
$ : | vipe | claude -p
# vim opens; type a prompt; :wq
Warning: no stdin data received in 3s, proceeding without it...
Error: Input must be provided either through stdin or as a prompt argument when using --print
Root cause (best guess): pipeline stages run concurrently. vipe blocks on the editor while holding the write end of the pipe open. claude -p starts immediately, sees no bytes on stdin, and trips a 3-second inactivity guard. EOF never arrives because the upstream is still alive — but claude exits anyway.
Proposed Solution
In order of preference:
- When
--printis given without a prompt argument, block on stdin until EOF (no inactivity timeout). The current error message already says input is required, so waiting for it is the obviously-correct behavior. The 3s guard makes sense as a defense against a forgotten prompt — but only when stdin is closed, not when it's still open with no bytes yet. - Add
--stdin-timeout=N(seconds;0= wait forever) for explicit user control. The same flag was suggested in #34455 for the opposite problem (tail -f | claude -phung forever). One flag solves both ends of the spectrum. - Detect upstream-still-open (e.g.
fstaton stdin or apollforPOLLHUP) and only apply the timeout once the pipe has been closed without bytes. More complex, but it would Just Work for users with no extra flags.
Alternative Solutions
Workarounds exist but lose pipeline composition (the very thing that makes the idiom useful):
# 1. Command substitution — works, but can't be chained into a longer pipeline
claude -p "$(vipe < /dev/null)"
# 2. Temp file — works, but verbose and not composable
tmp=$(mktemp); $EDITOR "$tmp"; claude -p < "$tmp"; rm "$tmp"
Priority
Medium - Would be very helpful
Feature Category
CLI commands and flags
Use Case Example
Scenario: I want to take a generated draft prompt, refine it in vim, and send it to Claude, all in one pipeline.
# Today (broken — claude times out while vim is still open):
some-command-that-generates-a-draft | vipe | claude -p
# Real-world precedent — this idiom is established across the ecosystem:
vipe | kubectl apply -f -
kubectl get pod foo -o yaml | vipe | kubectl apply -f -
helm template ./chart | vipe | kubectl apply -f -
vipe | jq '.something' | curl -X POST ...
Walkthrough of the desired flow:
- Upstream command emits a draft prompt to stdout.
vipepauses the pipeline, opens the draft in$EDITORfor refinement.- User edits and saves;
vipecloses its write end of the pipe. claude -preceives EOF and processes the refined prompt.
This is a standard human-in-the-loop pattern in pipelines. The fix unlocks it for Claude Code with no new concepts users need to learn.
Additional Context
Related issues — different symptoms, same 3s timeout:
- #34455 —
tail -f | claude -phangs forever (closed). Almost certainly the issue whose fix introduced the 3s timeout that now breaks vipe. The fix over-corrected: instead of no timeout, we now have one too short for any human-in-the-loop workflow. - #40726 —
--channelsin headless/background mode crashes with the exact sameInput must be provided…error after ~3s (closed). - #56268 —
claude -pfrom long-running orchestrators (open). Different scenario, same underlying input-handling logic.
Environment:
claude --version: 2.1.145 (Claude Code)- OS: Linux 6.17.0-23-generic x86_64 (Ubuntu)
- Shell: zsh
- moreutils
vipe(Debian/Ubuntu packagemoreutils)
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗