Files
small-scripts/specs/claude-tmux.spec.md
Paul O'Reilly 448091ecf4 feat(claude-tmux): spawn detached tmux Claude Code session with Remote Control
New script that launches Claude Code (via claude-profile) inside a detached
tmux session with --remote-control enabled, in a project's directory, named
after the project (Title-cased, auto-incrementing #N on collision). Lets a
session be started for later attach over VPN or control from the Claude app.

Spec-first per repo conventions: specs/claude-tmux.spec.md, script, and
tests/test-claude-tmux.sh (18 dryrun assertions, all passing).

Claude-Session: https://claude.ai/code/session_014oa7T7z1h5n34vu8vX9zGT
2026-07-25 16:29:46 +12:00

4.6 KiB

claude-tmux

Purpose

Spawn a detached tmux session running Claude Code (via claude-profile) with Remote Control enabled, in a project's directory, with the session named after the project so it is easy to tmux attach to and easy to identify in the Claude app.

Usage

claude-tmux [PROJECT] [OPTIONS]

Arguments

Argument Default Description
PROJECT (prompt if TTY) Project name (folder under ~/dev/claude or ~/dev/claude/projects), or an explicit path to a directory

Flags

Flag Default Description
--mode <name> profile's last-mode, else quick Engagement mode passed to claude-profile
--profile <name> oreillyit-anthropic Claude Code profile (resolves to ~/.claude-<name>, or ~/.claude for default)
--name <display> Title-cased project name Override the session / Remote-Control name
--attach off Attach (or switch-client if already inside tmux) after spawning
--dryrun, -n off Preview all actions without creating anything
--help, -h Show usage information

Behaviour

  1. Resolve the profile directory (~/.claude-<profile>, or ~/.claude for default). Error if it does not exist.
  2. Resolve the project. If PROJECT is empty and stdin is a TTY, prompt for it; if empty and not a TTY, error. Resolve the folder by trying, in order: an existing path, ~/dev/claude/<PROJECT>, ~/dev/claude/projects/<PROJECT>. Error if none exist.
  3. Resolve the engagement mode. If --mode is not given, read the profile's last-mode file, falling back to quick. The mode is always resolved explicitly and passed to claude-profile — the launcher must never leave claude-profile to show its interactive mode picker, because Remote Control only registers in the app once claude is actually running.
  4. Derive the base session name: Title-Case the project folder basename (agent-runtimesAgent Runtimes), unless --name overrides it.
  5. Auto-increment: if a tmux session with the base name already exists, append #2, #3, … until a free name is found. The first session gets no suffix.
  6. Create a detached tmux session named after the resolved name, with its working directory set to the project folder.
  7. Send the launch command into the session's pane (sent literally, followed by Enter): claude-profile <profile> --mode <mode> --project <basename> -- --remote-control "<name>"
  8. Print the attach hint and the Remote-Control name. If --attach is set, attach (or switch-client when already inside tmux).

claude-profile is located via PATH, falling back to a sibling of this script.

Dryrun Behaviour

When --dryrun / -n is passed, no tmux session is created and nothing is sent. Output (values substituted):

[dryrun] Project:      agent-runtimes (/home/paul/dev/claude/projects/agent-runtimes)
[dryrun] Profile:      oreillyit-anthropic (/home/paul/.claude-oreillyit-anthropic)
[dryrun] Mode:         deep
[dryrun] Session name: Agent Runtimes
[dryrun] Would run:    tmux new-session -d -s "Agent Runtimes" -c "/home/paul/dev/claude/projects/agent-runtimes"
[dryrun] Would send:   claude-profile oreillyit-anthropic --mode deep --project agent-runtimes -- --remote-control Agent\ Runtimes
[dryrun] Attach with:  tmux attach -t "Agent Runtimes"

Edge Cases

Case Handling
No PROJECT and stdin is a TTY Prompt Project name:
No PROJECT and not a TTY (e.g. run by an agent) Error: "No project given…", exit 1
Project folder not found Error naming the searched locations, exit 1
Profile directory not found Error, exit 1
Session name already taken Auto-increment with #N suffix
Project name has underscores Treated like hyphens for Title-Casing
claude-profile not found Error, exit 1
Two concurrent sessions on the same profile Both work: claude-profile rewrites the shared active-mode.env, but each session's cwd takes precedence for project auto-selection, so the correct project is still picked

Examples

# Spawn a Remote-Control session for agent-runtimes (Title-cased, mode from last-mode)
$ claude-tmux agent-runtimes
Spawned tmux session: Agent Runtimes
  attach:  tmux attach -t "Agent Runtimes"

# A second one auto-increments
$ claude-tmux agent-runtimes
Spawned tmux session: Agent Runtimes #2

# Override the mode, and attach immediately
$ claude-tmux cluster-bootstrap --mode deep --attach

# Preview only
$ claude-tmux dns-manager --dryrun