fix(interactive): hand tmux a script path, never the system prompt (#96) - #97
Merged
Merged
Conversation
A tmux `new-session` command travels over its imsg socket, capped at ~16 KB (measured on tmux 3.7c: 16 300 B starts, 16 340 B "failed to send command", 20 000 B "command too long"). The subscription engine put the whole system prompt inside that command, so a project with a 25 KB AGENTS.md — legal, agents-md.MAX_BYTES is 64 KB — could never start an interactive session, and the real tmux error was discarded with stderr. - tmuxLaunchCommand() writes the invocation to a content-addressed script in a per-process 0700 mkdtemp dir and hands tmux `sh <path>` (~60 bytes). A script rather than `"$(cat file)"`: tmux runs the command through the user's login shell, where `$( )` is a csh/tcsh syntax error. The script execs, so the pane process is still `claude`. Falls back to the inline command if the temp dir is unwritable. - tmux stderr is piped and appended to the `error` frame. - buildInteractiveCommand() extracted so the argv shape is unit-testable. - test/engine-spawn-cmd.test.js starts a REAL tmux session with a 40 KB prompt and asserts the child's argv byte-identical; the pre-fix inline form is run as an informational control (prints `command too long`). - agents-md.js: MAX_BYTES comment corrected (it is an argv budget; macOS ARG_MAX is 1 MB, not 256 KB). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #96.
Root cause
A tmux
new-sessioncommand travels over tmux's imsg socket, which caps the whole message at ~16 KB. Reproduced on tmux 3.7c (macOS): 16 300 B starts, 16 340 B →failed to send command, 20 000 B →command too long.runInteractiveSingle()put the entire--append-system-prompt(studio prompt + skills + AGENTS.md, up to 64 KB) inside that command, and spawned tmux withstdio:'ignore', so the only thing on screen was the generic "failed to start tmux session".Fix (
claude-interactive.js)tmuxLaunchCommand()writes the full invocation into a content-addressed script inside a per-processmkdtemp(0700) directory and hands tmuxsh <path>— ~60 bytes regardless of prompt size. The scriptexecs, so the pane process is stillclaude."$(cat file)"(the suggestion in the issue): tmux runs the command throughdefault-shell, the user's login shell —$( )is a syntax error under csh/tcsh and strips trailing newlines elsewhere.sh <path>is plain words in every shell./tmpname: this file is executed, so a pre-created file by another local user would be run instead of ours.errorframe, socommand too longreaches the user.buildInteractiveCommand()extracted (pure) so the argv shape is unit-testable.agents-md.js:MAX_BYTEScomment corrected — it is an argv budget (macOSARG_MAXis 1 MB, not 256 KB); the tmux ceiling no longer applies.Test
test/engine-spawn-cmd.test.js(wired intonpm test): 15 pure checks + an end-to-end run through a real tmux on a private socket with a fakeclaudethat dumps its argv — asserts the 40 KB prompt (with non-ASCII) arrives byte-identical. The pre-fix inline form runs as an informational control and printscommand too long.Cost / risk
ccs-mcp-*.json). Content-addressed, so a respawn with the same config reuses it.sh /tmp/ccs-spawn-…/spawn-<hash>.shinstead of the readableclaude …line;psstill shows the exec'dclaudeargv.🤖 Generated with Claude Code