Skip to content

feat(bin): one-command cmux launchers for Claude Code sessions - #49

Closed
elitecoder wants to merge 8 commits into
mainfrom
feat/cmux-claude-launcher
Closed

elitecoder wants to merge 8 commits into
mainfrom
feat/cmux-claude-launcher

Conversation

@elitecoder

Copy link
Copy Markdown
Owner

Summary

In auto mode, the classifier kept blocking the orchestrator when it started or messaged Claude Code sessions through cmux, mostly as [Create Unsafe Agents]. The skill told launches to add --dangerously-skip-permissions, so the classifier treated every child as unchecked. The claude alias actually runs --permission-mode auto.

This PR adds two one-command launchers that a narrow permissions.allow rule can approve, and points the spawn-claude-workspace skill at them.

  • bin/cmux-claude-spawn.sh [--env FFP_CHANNEL=<v>|FFP_EXP_<ID>=<v>]... <cwd> <title> <prompt-file> starts the claude alias in a new unfocused cmux workspace and has it read one prompt file. It prints <workspace-ref> <surface-uuid> <transcript>.
  • bin/cmux-claude-send.sh <surface-uuid> <transcript> <prompt-file> has a running session read one prompt file and prints delivered once the transcript shows it.

Guards:

  • Prompt files only, plain-named, under ~/.assistant/spawn-prompts/. The message is always Read <file> and follow it.
  • --env takes only FFP_CHANNEL and FFP_EXP_* with [a-z0-9]+ values, passed through cmux new-workspace --env.
  • Spawn refuses (exit 3) a claude alias without --permission-mode auto or with --dangerously-skip-permissions.
  • Nothing is typed until the screen shows auto mode and doesn't show bypass mode. The wake Enter is sent only on a blank screen.
  • Text goes through cmux paste --submit, which refuses over a draft or an open dialog.
  • Send takes surface UUIDs only, refuses its caller's own surface, and refuses a target that isn't in auto mode.
  • Delivery counts "type":"user" and "operation":"enqueue" lines (a message queued to a busy session), never last-prompt records.

Rules to add by hand in ~/.claude/settings.json

Add the deny rules before or with the allow rules, so the scripts can't be rewritten without review and then run under the allow rule.

"allow": [
  "Bash(/Users/mukuls/.claude/bin/cmux-claude-spawn.sh *)",
  "Bash(/Users/mukuls/.claude/bin/cmux-claude-send.sh *)"
],
"deny": [
  "Edit(~/dev/assistant/bin/cmux-claude-*.sh)",
  "Edit(~/.claude/bin/cmux-claude-*.sh)"
]

Testing

  • tests/test_cmux_claude_launcher.py: 24 tests against a fake cmux that writes transcripts the way Claude Code does, including queued messages and last-prompt records. All pass.
  • Mutation probes are red for every guard: the env check, both halves of the alias check, the prompt-folder boundary, the ready gate, the blank-screen-only wake, the bypass-screen check in both scripts, the user and enqueue counts, the self-target check, and --submit.
  • Full suite, as CI runs it: 3033 passed, 1 skipped.
  • Live: spawned a throwaway session that read a prompt file and answered; send delivered a second file and got its answer; sending to the caller's own surface was refused; the workspace was closed.
  • Two independent reviews: CLEAR after fixes.

🤖 Generated with Claude Code

elitecoder and others added 8 commits October 18, 2026 21:07
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Prompt files only, FFP env switches only, auto-mode alias required, guarded cmux paste, no blind Enter, UUID surfaces, self-target refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… fixes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… a missing transcript

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@elitecoder

Copy link
Copy Markdown
Owner Author

Closing in favor of the skill-only fix: plain single cmux commands work without new scripts or allow rules.

@elitecoder elitecoder closed this Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant