From arthur0824hao-skills
Tmux execution support for long-running and persistent commands. Load this skill when you need to: (1) run commands expected to exceed tool timeout (over 60s), (2) start persistent servers or dev processes, (3) run TUI/interactive applications, (4) execute parallel isolated tasks in separate sessions, (5) run remote commands over SSH that must survive disconnection, (6) handle tmux errors like 'capture-pane blocked in interactive_bash'. Trigger phrases: 'run in background', 'start server', 'long-running', 'tmux session', 'keep running', 'persistent process', 'dev server', 'training script', 'git clone large repo', 'docker build', 'capture-pane blocked'.
npx claudepluginhub arthur0824hao/skills --plugin document-skillsThis skill uses the workspace's default tool permissions.
Route shell commands through tmux when they risk timeout, require persistence, or need interactive terminal access. This skill provides decision heuristics and session management conventions — not tmux tutorials.
Creates isolated Git worktrees for feature branches with prioritized directory selection, gitignore safety checks, auto project setup for Node/Python/Rust/Go, and baseline verification.
Executes implementation plans in current session by dispatching fresh subagents per independent task, with two-stage reviews: spec compliance then code quality.
Dispatches parallel agents to independently tackle 2+ tasks like separate test failures or subsystems without shared state or dependencies.
Route shell commands through tmux when they risk timeout, require persistence, or need interactive terminal access. This skill provides decision heuristics and session management conventions — not tmux tutorials.
Use this matrix to decide: direct bash vs tmux.
| Condition | Route | Examples |
|---|---|---|
| Estimated time > 60s | tmux | git clone <large>, npm install, docker build, training scripts |
| Command does not self-terminate | tmux | npm run dev, python app.py, jupyter notebook |
| Requires TUI or interactive input | tmux | vim, htop, pudb, claude |
| Parallel isolated execution needed | tmux | Multiple agents, concurrent test suites |
| Remote execution over SSH | tmux | Commands that must survive connection drops |
| Atomic, non-interactive, fast (<30s) | direct bash | ls, grep, git status, cat, mkdir |
| Single-shot with expected output | direct bash | python script.py (fast), git diff, npm test (short) |
Default: direct bash. Only route to tmux when a condition above is met.
Commands likely to exceed timeout:
clone (large repos), push (large payloads), checkout (>1GB working tree)npm install, pip install (many deps), cargo builddocker build, make (large projects), webpack (production builds)Use project-context naming for human readability:
Format: {project}-{purpose}
Agent-created sessions (MANDATORY prefix):
oc-{purpose} # e.g., oc-audit, oc-verify, oc-render
oc-{project}-{task} # e.g., oc-skills-build, oc-subproject-test
User/infra sessions (no prefix required):
postgres-dev
frontend-watch
ml-training
Rules:
oc- prefix — enables bulk identification and cleanupoc- session names when they exist (e.g., oc-exp-runner)oc-* before reuse531)For long-running commands where you don't need real-time output:
# Kill any existing session with same name, then start fresh
tmux kill-session -t {session} 2>/dev/null || true
tmux new-session -d -s {session} bash -c '{command}'
Using interactive_bash tool:
tmux_command: new-session -d -s {session}
tmux_command: send-keys -t {session} "{command}" Enter
For dev servers or processes that must keep running:
tmux_command: new-session -d -s {session}
tmux_command: send-keys -t {session} "{command}" Enter
Check if running later:
tmux_command: has-session -t {session}
Read what a tmux session has produced:
tmux_command: capture-pane -p -t {session}
For longer history (last 1000 lines):
tmux_command: capture-pane -p -t {session} -S -1000
After sending a command, poll to detect completion:
/(\\$|>|#)\s*$/m)Always clean up sessions when done:
tmux_command: kill-session -t {session}
Kill-before-new pattern prevents zombie sessions:
tmux_command: kill-session -t {session}
# (ignore error if doesn't exist)
tmux_command: new-session -d -s {session}
Reclaim all agent-created sessions and detect stale resources. Run this when:
Step 1: Identify agent sessions
tmux list-sessions -F '#{session_name} #{session_activity}' | grep '^oc-'
Step 2: Kill all agent sessions
tmux list-sessions -F '#{session_name}' | grep '^oc-' | xargs -I{} tmux kill-session -t {}
Step 3: Detect stale non-agent sessions
A session is likely stale if:
$ or ╰─)# List sessions with last activity timestamp
tmux list-sessions -F '#{session_name} #{session_activity}'
# Compare #{session_activity} (epoch) against current time
# Capture pane of suspects to verify idle state
Step 4: Reclaim orphaned processes
# Find opencode processes whose parent tmux pane was killed
ps aux | grep opencode | grep -v grep
# Check if port is held by a zombie
lsof -i :{port} 2>/dev/null
# Force kill if needed (SIGTERM first, SIGKILL if unresponsive after 5s)
kill {pid} && sleep 5 && kill -0 {pid} 2>/dev/null && kill -9 {pid}
Important: Never kill known non-agent infra sessions without explicit user confirmation. Legacy names from sibling projects should be normalized to oc-* before they are treated as agent-managed sessions.
interactive_bash ToolThe primary interface. Pass tmux subcommands directly (without tmux prefix):
# Create session
tmux_command: new-session -d -s oc-my-session
# Send command
tmux_command: send-keys -t oc-my-session "npm run dev" Enter
# Read output
tmux_command: capture-pane -p -t oc-my-session
# Kill session
tmux_command: kill-session -t oc-my-session
bash Tool with TimeoutFor commands near the timeout boundary, prefer increasing timeout parameter over tmux:
bash(command="npm install", timeout=300000) # 5 min timeout
Use tmux only when:
capture-pane blocked in interactive_bashError: 'capture-pane' is blocked in interactive_bash
This is the most common tmux error. The interactive_bash tool blocks certain tmux subcommands (including capture-pane, pipe-pane, save-buffer). Always use the Bash tool instead for these operations.
# WRONG — will be blocked:
# interactive_bash: tmux_command: capture-pane -p -t oc-dev-server
# CORRECT — use Bash tool:
tmux capture-pane -p -t oc-dev-server
# Capture with history (last 1000 lines):
tmux capture-pane -p -t oc-dev-server -S -1000
# Capture and grep for specific output:
tmux capture-pane -p -t oc-dev-server | grep -i "error\|ready\|listening"
Rule: For any tmux read-only operation (capture-pane, list-sessions, display-message, show-options), prefer the Bash tool. Reserve interactive_bash for mutations (send-keys, new-session, kill-session).
session not found after kill/recreateError: can't find session: oc-xxx
Common when kill-before-new pattern races. Add a small guard:
tmux kill-session -t oc-build 2>/dev/null || true
tmux new-session -d -s oc-build bash -c 'make all'
duplicate session on new-sessionError: duplicate session: oc-xxx
The session already exists. Either reuse it or kill-before-new:
# Reuse (send new command to existing session):
tmux send-keys -t oc-build "make clean && make all" Enter
# Or kill and recreate:
tmux kill-session -t oc-build 2>/dev/null || true
tmux new-session -d -s oc-build bash -c 'make all'
no server running / tmux not startedError: no server running on /tmp/tmux-*/default
No tmux server is running. Any new-session command will start one automatically:
tmux new-session -d -s oc-init echo "tmux ready"
| tmux subcommand | Use interactive_bash? | Use Bash tool? |
|---|---|---|
new-session | Yes | Yes |
send-keys | Yes (preferred) | Yes |
kill-session | Yes | Yes |
capture-pane | NO — blocked | Yes (required) |
list-sessions | Avoid | Yes (preferred) |
has-session | Yes | Yes |
pipe-pane | NO — blocked | Yes (required) |
display-message | Avoid | Yes (preferred) |
| Don't | Do Instead |
|---|---|
| Route every command through tmux | Use direct bash for fast, atomic commands |
| Forget to kill sessions after use | Always clean up with kill-session |
Use generic session names like s1 | Use descriptive names: oc-project-purpose |
Create agent sessions without oc- prefix | Always prefix: oc-audit, oc-verify, oc-build |
| Poll capture-pane in tight loops | Use 1-2s intervals between polls |
| Start a new session without killing old one | Always kill-before-new for same session name |
| Send commands without clearing the line first | Send C-u before commands if line might have residual input |
| Leave sessions running after task completes | Run bulk reclaim (Pattern 6) at session end |
Use interactive_bash for capture-pane | Always use Bash tool for capture-pane |
Retry blocked commands in interactive_bash | Switch to Bash tool immediately |
This skill system's sibling projects may contain older tmux naming patterns, but agent-owned sessions in this repo must be normalized to oc-*.
oc-exp-runner: Preferred agent-owned name for experiment executiontmux send-keysmachines.json config: tmux_session field defines per-machine session namesWhen working in a project with existing tmux conventions, preserve true user/infra sessions, but rename inherited agent sessions to the oc-* form before continuing.
{
"schema_version": "2.0",
"id": "skill-system-tmux",
"version": "1.0.0",
"capabilities": ["tmux-session-start", "tmux-capture", "tmux-wait", "tmux-session-list", "tmux-session-kill"],
"effects": ["proc.exec"],
"operations": {
"start-session": {
"description": "Start a long-running command in a managed tmux session.",
"input": {
"name": { "type": "string", "required": true, "description": "Logical session name" },
"command": { "type": "string", "required": true, "description": "Command to execute inside tmux" }
},
"output": {
"description": "Started session metadata",
"fields": { "status": "string", "session_name": "string" }
},
"entrypoints": {
"unix": ["python3", "{skill_dir}/scripts/tmux_tool.py", "start-session", "{name}", "{command}"]
}
},
"capture-pane": {
"description": "Capture output from a managed tmux session.",
"input": {
"session_name": { "type": "string", "required": true, "description": "Target session name" },
"lines": { "type": "integer", "required": false, "description": "Number of lines to capture" }
},
"output": {
"description": "Captured output",
"fields": { "status": "string", "output": "string" }
},
"entrypoints": {
"unix": ["python3", "{skill_dir}/scripts/tmux_tool.py", "capture-pane", "{session_name}"]
}
},
"wait-completion": {
"description": "Poll a managed tmux session until completion.",
"input": {
"session_name": { "type": "string", "required": true, "description": "Target session name" },
"timeout_seconds": { "type": "integer", "required": false, "description": "Maximum wait time" }
},
"output": {
"description": "Completion result and final output",
"fields": { "status": "string", "completed": "boolean", "output": "string" }
},
"entrypoints": {
"unix": ["python3", "{skill_dir}/scripts/tmux_tool.py", "wait-completion", "{session_name}"]
}
},
"list-sessions": {
"description": "List managed tmux sessions.",
"input": {},
"output": {
"description": "Managed session rows",
"fields": { "status": "string", "sessions": "array" }
},
"entrypoints": {
"unix": ["python3", "{skill_dir}/scripts/tmux_tool.py", "list-sessions"]
}
},
"kill-session": {
"description": "Kill a managed tmux session.",
"input": {
"session_name": { "type": "string", "required": true, "description": "Target session name" }
},
"output": {
"description": "Kill result",
"fields": { "status": "string", "session_name": "string" }
},
"entrypoints": {
"unix": ["python3", "{skill_dir}/scripts/tmux_tool.py", "kill-session", "{session_name}"]
}
}
},
"stdout_contract": {
"last_line_json": false,
"note": "Agent-executed; uses interactive_bash tool for tmux operations."
}
}