altimate-code run wedges silently on inherited stdin when invoked as subprocess
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 84/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Quiet
- Tech stack
- bun, typescript
Research direction
Start in packages/opencode/src/cli/cmd/run.ts around line 422 and trace how the positional message is assembled before stdin is read. Add coverage for both non-TTY cases described in the test plan, then run the relevant CLI tests and verify that altimate-code run "say hi" --yolo with closed stdin returns instead of hanging.
Written by the indexing model from the issue text.
Description
Problem
When altimate-code run "<task>" --yolo is invoked as a subprocess (Claude Code's Bash tool, Python subprocess.run, a CI runner, a plugin spawn with stdio: "inherit" on stdin), the process hangs at 0% CPU forever. No session is created, no log activity past json migration complete, no error — looks identical to a deadlock.
Root cause
packages/opencode/src/cli/cmd/run.ts:422 unconditionally reads stdin whenever the process is not attached to a TTY:
if (!process.stdin.isTTY) message += "\n" + (await Bun.stdin.text())
When the parent process inherits stdin from a higher-level non-pipe source and never closes its end, Bun.stdin.text() waits forever for an EOF that never arrives. The intent of the code was "if someone pipes input in, append it to the message" — but the guard !process.stdin.isTTY is too broad: it also matches "stdin was inherited from a parent that isn't a TTY but also isn't closing".
Reproducer
From a shell with a positional message arg:
# Simulate inherited-but-not-closed stdin (Bun.stdin.text() blocks forever)
exec 3< /dev/null # any open FD that isn't being written to
altimate-code run "say hi" --yolo <&3
# hangs at 0% CPU, no session created
Or, more realistically, from Python subprocess.run([...], stdin=None) inside another process — anywhere the child inherits a stdin file descriptor the parent doesn't explicitly close.
Current mitigation (downstream)
The altimate-opencode-plugin works around this by spawning altimate-code with stdio: ["ignore", "pipe", "pipe"], which closes the child's stdin from outside. See altimate-opencode-plugin plugins/altimate-code/index.ts:28 and its comment at lines 177-182. Any caller that doesn't take that precaution still hits the wedge.
Proposed fix
Only read stdin when no positional message has been provided:
if (!process.stdin.isTTY && message.trim().length === 0) {
message += "\n" + (await Bun.stdin.text())
}
This matches conventional CLI semantics (echo "foo" | tool reads stdin; tool "explicit arg" doesn't), and unblocks every subprocess caller that passes a positional message — which is the most common pattern in agent/skill/plugin invocations.
Pipe-only invocations without a positional arg (echo "task" | altimate-code run --yolo) continue to work unchanged.
Test plan
- Unit test: with a positional message provided and
isTTYfalse,Bun.stdin.text()is NOT invoked. - Unit test: with no positional message and
isTTYfalse, stdin IS read (existing pipe-only path). - Smoke:
altimate-code run "say hi" --yolo <&-returns in ~1s instead of hanging.
Context
Surfaced during a multi-week experiment series running altimate-code as a Skill from Claude Code's --print subprocess flow. Originally diagnosed and patched in a local altimate-code-preview build (worktree at altimate-code/.claude/worktrees/fix-run-stdin/) — that patch has been belt-and-suspenders for the last several months. Re-verified 2026-06-12 against main (release v0.8.7, commit 146acea8e): run.ts:422 is unchanged; the line is still the original unconditional read.
Full writeup: plugin-skill-experiments/03-issues-and-fixes.md Issue #2.
PR incoming.
- Dominant language
- TypeScript
- Stars
- 813
- Forks
- 134
- Avg merge
- 2d 5h
- Merged PRs (30d)
- 62
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from AltimateAI/altimate-code
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
AltimateAI/altimate-code#1323 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
AltimateAI/altimate-code#1288 ·
-
Difficulty 1/5 Under an hour Newbie friendliness 92/100
AltimateAI/altimate-code#1285 ·
-
privacy: Altimate Base consent dialog no longer discloses persistent per-installation identifier Open
Difficulty 1/5 Under an hour Newbie friendliness 88/100
AltimateAI/altimate-code#1284 ·
-
Difficulty 2/5 Under an hour Newbie friendliness 72/100
AltimateAI/altimate-code#1283 ·
All issues in AltimateAI/altimate-code
Similar issues
-
Browser Waiting for: Product Owner
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
getsentry/sentry-javascript#24577 · 1 comment ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
agilepathway/label-checker#640 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
copse-dev/agent-pane#2953 ·
-
agentic-workflows
Difficulty 1/5 Under an hour Newbie friendliness 85/100
githubnext/rig#534 ·
-
automation missing-model model-sync provider:pioneer
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
anomalyco/models.dev#7701 ·