# Tmux Agent Tools

> Mechanics library for running AI coding CLIs as managed tmux workers via agent-tmux <cli> <command> (plus tmux-agent-sessions and the other bundled tools). Entry point is the using-tmux-agent-tools router skill — route through it first; read this skill for wrapper mechanics it defers to. Covers start/send-wait/status/result/stop, structured result.json completion, multi-worker watch, profiles for custom CLIs, and bounded dialogue/fanout. Not for general tmux config, theming, non-tmux headless CLI use, or human team debate.

- Skill: `ohyeh/tmux-agent-tools` (Agent Skill, multi-file: 36 files)
- Install (CLI): `npx skillmds@latest add ohyeh/tmux-agent-tools`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ohyeh/tmux-agent-tools/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: ohyeh (https://skillmd.com/u/ohyeh)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/ohyeh/tmux-agent-tools

---


# Tmux Agent Tools

## Fast paths (read this first)

Non-negotiable rules:

1. **Engine-only — never type raw `tmux` at a worker.** Drive every worker through `agent-tmux <cli>` subcommands (`send-wait`, `status`, `result`, `capture`, `stop`); read-only inventory is `tmux-agent-sessions list`, not raw `tmux ls`. Raw `tmux` bypasses naming, redaction, result contracts, and cleanup. Before concluding the engine lacks a command, check the capability table below; plain shell is a last resort for genuine gaps — say why.
2. **A `send` is not done until submission is verified.** Bare `send` can leave text unsent in the input box. Default to `send-wait`: it appends a fresh nonce and waits for it, confirming the prompt landed.
3. **Every blocking wait takes a timeout — never hand-roll `sleep`/polling loops.** Multiple workers: one bounded `watch --any|--all|--count <n> --timeout <s> --json …`. Mixed-engine fleets: trust `reason:result_updated` or resolve with `tmux-agent-sessions`.
4. **Reusing a worker for a follow-up task?** `result init` first, then `send-wait`, then `result wait-required` — never reuse without `result init`, or the wait returns the stale prior result. Details: `references/multi-agent.md#persistent-teammates-worker-reuse`.

Fast answers:

- **Bounded task with no follow-ups?** Default to interactive `start` (headed): the tmux pane is the debug surface — `capture`, `status`, or attaching shows exactly what the CLI is doing, mid-run and post-mortem. `start --headless` (`claude -p` / `codex exec`) is OPT-IN only: user explicitly asks for it, or the output is trivially verifiable and nobody will need to inspect the run. A headless failure leaves only an exit code and a stdout file — repeatedly observed to cost long blind-debugging sessions (user ruling 2026-08-03: headed by default).
- **Wrapper not on PATH?** Run it from this bundle: `<skill-dir>/scripts/agent-tmux codex …`.
- **Worker "failed" but the pane says PASS?** Exit code is not the verdict — see `references/core-workflow.md#5-read-the-agents-structured-result` ("Exit code is not the verdict") before re-dispatching or reporting failure.
- **Auto-delegate substantial work?** Use the inline-vs-worker gate in the `using-tmux-agent-tools` skill (absorbed there, no longer a separate subagent); details live in `references/core-workflow.md`.
- **Long-running external CLI worker (Codex or Claude Code)?** Dispatch it with ONE `agent-tmux <cli> assign <name> <dir> <prompt-file>` call — the stepwise sequence (start → result init → send → confirm-processing → blocking supervise) IS the supervision, so the proxy hosts it and nothing else (the OLD per-worker *polling* proxy stays retired, 2026-08-08). The host is ONE supervision proxy — a `general-purpose` subagent on `sonnet` low whose brief runs that single `assign` call and reports its exit code (see `model-dispatch.md` §4, 2026-08-17/18 rulings). Parent foreground `assign` is banned in ALL forms, `--detach` included, and is denied at the tool call by the `tmux-assign-host-gate` hook; parent `run_in_background` is REQUIRED, not a last-resort fallback, whenever the proxy reports anything non-terminal — measured 2026-08-30, the harness reaps a proxy's foreground call at ~600s and a subagent has no `TaskOutput`, so a reaped proxy can only report in-flight and the parent must own the wait itself (a task orphaned by a terminated subagent notifies nobody; incident c48c0d3a lost 2h40m that way). Log the reason in the run dir, and never pipe the listener — a trailing `| tail` reports `tail`'s status, so the wrapper's `exit 2` reads as success. The parent MUST NOT additionally poll `status`/`capture`/`probe` unless `assign` reports a failed step or the user asks; harvest with bounded `result wait-required --wait <s>` calls. A `pending` result is a TERMINATING PROCEDURE, not a verdict: keep waiting within the bound → bound expires still pending, re-prompt the worker ONCE with the literal path from `result --path <name>` and wait one more bounded round → only then may a pane capture stand in, labelled UNCONFIRMED and never shipped as a verified answer. Heed `assign`'s `result-path delivery UNCONFIRMED` warning — a worker that never learned its path can never write result.json, so that `pending` is permanent. Teardown order: stand the proxy DOWN BEFORE stopping the worker it supervises, or the proxy is stranded on a signal that can no longer arrive. Never brief a proxy to return the worker's output verbatim — it is forbidden to read that output, so the brief is unsatisfiable; have the WORKER write to a declared artifact path and read that file yourself.
- **Writing the worker prompt?** Shape it with the `delegation-templates` skill: GOAL / ACCEPTANCE / REPORT + common footer, plus its tmux addendum (no-cascade ban + literal result path).
- **New or renamed CLI?** Add a profile with `bin=…`, then prove it with `doctor --json` and `start --dry-run`; see `references/profiles.md`.

## Overview

`agent-tmux <cli> <command>` runs any AI coding CLI as a managed tmux worker; claude/codex/agy are built-in presets, other CLIs use an optional profile. The old `claude-tmux`/`codex-tmux`/`agy-tmux` shims are DEPRECATED (removal: v0.39) — always spell `agent-tmux <cli> <command>`.

## Required preflight and safe invocation

Before the first worker command:

1. Resolve the wrapper bundle instead of assuming PATH. Probe, in order,
   `<repo-dir>/skills/tmux-agent-tools/scripts`,
   `~/.agents/skills/tmux-agent-tools/scripts`,
   `~/.claude/skills/tmux-agent-tools/scripts`, and
   `~/.codex/skills/tmux-agent-tools/scripts`; use bare wrapper names only when
   no bundle exists and PATH lookup succeeds.
2. Run the resolved `agent-tmux <cli> setup` and stop if preflight fails.
3. Pass the raw task as a separately quoted argument or prompt-file content.
   Never interpolate task text into `eval`, `sh -c`, or a constructed shell
   command.
4. Pass task-specific credentials only through `--secret KEY=URI`. Never embed
   credential values in task text or a constructed shell command.

## When to use

- Long-running Claude/Codex/agy/custom CLI work that needs later supervision.
- A worker must write structured `result.json` for a parent agent or wrapper.
- You need verified follow-up sends, liveness/status checks, bounded waits, or cleanup.
- Multiple workers need first/all/N completion via one wrapper `watch` call.

## Command choice

| Need | Use |
| --- | --- |
| Run Claude Code / Codex / agy as a worker | `agent-tmux claude` / `agent-tmux codex` / `agent-tmux agy` |
| Any other CLI (gemini, cursor, grok, custom) | `agent-tmux <cli>` (+ optional profile) |
| **Any worker, including bounded one-shots** | interactive `start` (headed) — pane = debug surface; DEFAULT |
| Trivially verifiable fire-and-collect, user opted in | `start --headless` — completion = process exit; failures leave only exit code + stdout file |
| Local working directory | `start` |
| Repo on another host, tmux stays local | `start-ssh` |
| Pin a model for one run | `start --model <m> <name> <dir> '<prompt>'` |
| Continue an existing CLI session UUID | `resume` (opt-in, off by default) |
| Don't know which wrapper owns a session | `tmux-agent-sessions resolve --name <n> --json` first |
| Two-party exchange / one-to-many work | `tmux-agent-dialogue` / `tmux-agent-fanout` |
| Read-only inventory or evidence polling | `tmux-agent-sessions` / `tmux-agent-monitor` |

Start flags precede positionals: `start --exact --model <m> <name> <dir>`; a misplaced flag exits 2.

Full capability table (every subcommand + when to use it): `references/cheatsheets.md`.

## When not to use

- A one-off shell command or a simple file read, search, test, or build — run it directly instead of spawning a worker.
- Externally visible, destructive, or privacy-sensitive work unless the user has already authorized it.

## The 6 commands you need most

```bash
# Dispatch a prompt-file task: ONE command runs the whole verified sequence
# (start -> result init -> send --from-file -> confirm the pane is processing
# -> blocking supervise). Prefer this over hand-chaining the steps; it cannot
# be misordered and it catches "task never reached the CLI" before waiting.
agent-tmux codex assign job ~/repo /abs/path/prompt.txt

# Bounded one-shot (headed by default; add --headless only when the user opted in):
agent-tmux codex start --exact job ~/repo 'Task. Write final JSON to the wrapper-provided result path when done.'
agent-tmux codex result wait-required job --fields status,summary --wait 600 --json   # returns at process exit
agent-tmux codex supervise --result-required --silent-while-unchanged --json job       # one silent call until terminal event
agent-tmux codex stop job

# Interactive one-worker flow (only when follow-ups are needed): start -> send-wait -> supervise -> stop.
agent-tmux codex start --exact worker ~/repo 'Task. Write final JSON to the wrapper-provided result path when done.'
agent-tmux codex send-wait worker 'Follow-up instruction.' 180
agent-tmux codex status --json worker
agent-tmux codex result --json --wait 30 worker
agent-tmux codex stop worker

# Multiple workers: block on first/all/N completion with one bounded call.
agent-tmux codex watch --any --timeout 600 --json w1 w2 w3
```

Full walkthrough: `references/core-workflow.md`.

## result.json completion contract

Agents write `$TMUX_AGENT_DIR/<name>/result.json` with `schema_version: 1`, canonical `status` (`success|failed|blocked|needs-input`), `summary`, `artifacts`, and `errors` (optional `verdict`/`decision`). Codex/generic prompt sends inject the literal result path once per session; the worker cannot rely on `$TMUX_AGENT_RESULT` inside tool sandboxes. Branch in this order — never scrape the pane when a valid result exists: `.present -> .valid -> .body`.

`--fields` names keys in THAT contract, never a prompt placeholder: harvesting with `artifact_path` (which no worker writes) left two finished workers unharvested for ~24 minutes on 2026-09-08. Ask for `status,summary`, read `.body`, and request a produced file as `.body.artifacts`. A terminal result missing a requested field now exits `3` (`event:"contract-mismatch"`, worker `body` attached) instead of waiting — fix the field list, do not re-dispatch. A CLI that cannot launch exits `4` at `assign` step 0 with `blocked_reason` (`keychain_locked`, `login_required`, `quota_exhausted`, `cli_not_found`) and starts nothing: report the blocker, do not wait. For a TUI that submits on every newline, dispatch with `assign --prompt-delivery file-ref` (profile `prompt_delivery`; `agy` ships it) — agy received one pasted prompt as 12 separate inputs, `GOAL` and `CONTEXT` never arriving, and still reported `assigned:true`.

```bash
agent-tmux codex result --json --wait 30 worker
agent-tmux codex supervise --result-required --silent-while-unchanged --json worker
```

If `.present:false`, the agent never wrote the file — re-prompt with the literal path from `result --path <name>`. Full schema, worked example, `status --json` fields, approval-gate exit codes, concurrency model: `references/contracts.md`.

## Safety

- Wrappers use permissive CLI flags by default (`--dangerously-skip-permissions` for Claude, `--yolo` for Codex). Never use for destructive, privacy-sensitive, externally visible, payment, or irreversible work without explicit user authorization.
- `status --json` reports `confirmation_detected:true` plus `blocked_reason` when a pane appears to wait for confirmation. It does **not** auto-accept; answer only after you trust it.
- Before spawning more than one worker: ask the user for tool+model+effort per worker, set a worker upper bound, and forbid cascade spawning in every prompt. Details: `references/multi-agent.md`.
- Secret injection (`--secret KEY=URI`, fail-closed) and audit log (`TMUX_AGENT_TOOLS_AUDIT_LOG`): `references/security.md`.

## References

Load these only when you hit the relevant scenario — they are not needed for routine use:

- `references/core-workflow.md` — full single-worker workflow, session naming, remote sessions, peer-review, approval gates, the inline-vs-worker gate.
- `references/profiles.md` — custom CLI profile keys, precedence, examples, detection overrides.
- `references/cheatsheets.md` — full capability table, scenario commands, marker pitfalls, failure triage.
- `references/multi-agent.md` — dialogue/fanout rules, bridge pattern, SSH participants, github-comment behavior.
- `references/contracts.md` — `status --json`/`result.json` schemas, approval exit codes, concurrency, inventory/cleanup.
- `references/security.md` — secret injection, audit log, environment overrides, pre-flight checks.
- `references/troubleshooting.md` — failure modes and fixes for stuck/unsent/stale-marker scenarios.
- `references/recipes.md` — copy-pasteable workflows (approval gate, fanout, DAG).

## Bundled schemas

`schemas/` ships `result-status-summary.schema.json` and `fanout-summary.schema.json` — the offline fallback the scripts already resolve for `result.json` validation when no other copy is found on disk.

The `agents/` subagent bundle (`tmux-delegate.md`, `claude-oneshot.md`, `codex-oneshot.md`) is retired — see CHANGELOG. The inline-vs-worker gate and the one-shot forwarding pattern they carried now live in the `using-tmux-agent-tools` skill's decision tree; there is nothing to install into `~/.claude/agents/` anymore.

