Tmux Workflow

cortex tmux gives agents a small, scriptable control surface for named tmux windows. It is meant for orchestration: start work in a window, inspect output, wait for completion, and interrupt safely when needed.

Session Model

cortex tmux operates inside one tmux session:

  • if TMUX_SESSION is set, Cortex uses that
  • otherwise it derives the session name from the current directory name

If the session does not exist, Cortex returns a helpful error instead of guessing.

Creating, killing, and attaching to sessions

The convention is one session per project, named after the project directory. Three commands cover the lifecycle:

# Idempotently create — safe to call repeatedly, returns
# "already exists" if the session is up
cortex tmux session-new
cortex tmux session-new my-project --cwd /path/to/project

# Kill the session and every window in it (errors loudly if missing)
cortex tmux session-kill my-project

# Land in the session. switch-client when $TMUX is set,
# attach-session otherwise. --window selects a starting window first.
cortex tmux attach
cortex tmux attach my-project --window shell

Two asymmetries worth knowing:

  • session-new is idempotent. Re-runs return success with an “already exists” message, so it’s safe as a setup-recipe dependency.
  • session-kill is loud. It errors on a missing session because kill is destructive — append 2>/dev/null || true if you want fire-and-forget semantics.

What It Is For

Use cortex tmux when you want to:

  • create dedicated windows for build, test, review, or watch tasks
  • send commands without manually attaching to tmux
  • talk to a TUI agent (Claude Code, Codex) running in another window
  • inspect recent output from another window
  • survey every session and window on the box at once
  • wait for a command to finish
  • watch for a success or failure pattern in output

This is especially useful when an agent needs multiple long-running terminals without mixing their output together.

Core Window Management

List windows:

cortex tmux list

Create a new window. By default the window starts in your current working directory; pass --cwd to override it:

cortex tmux new review
cortex tmux new api-server --cwd /path/to/api

Without --cwd, tmux falls back to whatever directory the server was started in — usually $HOME, almost never what you want.

Rename a window after an agent claims it, so sessions and snapshot stay readable:

cortex tmux rename review Claude-Review

Kill a window when the task is done:

cortex tmux kill review

Sending Commands vs Typing Text

Run a command and press Enter:

cortex tmux send review "pytest -m unit"

Type text without submitting it:

cortex tmux type review "pytest -m unit -k export"

Send a key sequence directly:

cortex tmux keys review C-c
cortex tmux keys review Up Enter

Or use the explicit interrupt helper:

cortex tmux interrupt review

One important behavior: cortex tmux send sends Ctrl-C first to clear any partial input before it submits the new command. That makes it safer for agent automation than blindly typing into a possibly half-edited shell line.

Talking to TUI Agents

send is for shells. When the target window is running a TUI — Claude Code, Codex, vim, fzf — use say:

cortex tmux say claude-frontend "what's your progress on the login form?"

say differs from send in two important ways:

  • No Ctrl-C clear. That would interrupt whatever the agent in the target window is doing. say is safe to use against a thinking agent.
  • The text and the submit key are sent as two separate send-keys calls with a 0.5-second pause between them. TUIs render their input on a debounced loop; if text and Enter arrive in the same call, the submit can race the render and you end up sending an empty or truncated message.

If a TUI is twitchy on a slow box, raise the settle:

cortex tmux say claude-frontend "..." --settle 1.0

Quick mental model:

Target is… Use Ctrl-C clear? Text + Enter combined?
Shell send yes yes
TUI say no no (two calls + settle)

Targeting Split Panes

All targeting subcommands accept window.pane syntax for split panes:

cortex tmux say claude-frontend.0 "..."   # left pane
cortex tmux send build.1 "cargo test"      # right pane
cortex tmux read claude-frontend.2 50      # third pane

Only the window-name half is validated; the pane number is forwarded to tmux unchanged. A window literally named my.config is left alone because the parser only treats purely numeric suffixes as pane indices.

Reading Output

Read the last lines from a window:

cortex tmux read review
cortex tmux read review 100

Dump the entire scrollback buffer:

cortex tmux dump review

Get a compact status view:

cortex tmux status review

status is useful when you want a lightweight “does this window exist and what did it print most recently?” check.

Surveying All Sessions

list only shows windows in the current session. To see every session on the box:

cortex tmux sessions
main (attached): 4 windows
side (detached): 1 windows

For a deeper view — every session, every window, with the last N lines of output per window — use snapshot:

cortex tmux snapshot
cortex tmux snapshot --lines 30
cortex tmux snapshot --session main
=== main (attached) ===
  [0] Claude-Frontend *
    | Working on the login form…
    | Added /api/v1/auth integration
  [1] dev-server
    | Listening on :3000

The active window in each session is marked with a trailing *. The output is plain text designed to be piped into an LLM context, so an orchestrator agent can answer “what is every other agent doing right now?” in one read.

Waiting and Watching

Check whether the window looks busy:

cortex tmux running review

This exits with status 0 when a command appears to be running and 1 when the pane looks idle at a shell prompt.

Wait for the command to finish:

cortex tmux wait review
cortex tmux wait review 180

Watch for a specific pattern:

cortex tmux watch review "FAILED"
cortex tmux watch review "Build succeeded" --timeout 300

If you call watch without a pattern, it waits for the prompt to return.

A reliable workflow looks like this:

# create a dedicated window
cortex tmux new review

# start the job
cortex tmux send review "pytest -m unit"

# follow along without attaching
cortex tmux read review 80

# wait for completion
cortex tmux wait review 180

# inspect the tail again
cortex tmux status review

For watch-mode or dev servers, use pattern-based watching instead:

cortex tmux new docs
cortex tmux send docs "bundle exec jekyll serve --livereload"
cortex tmux watch docs "Server address:"

For a multi-agent orchestration loop, combine snapshot and say:

# 1. See who's on the box
cortex tmux snapshot --lines 5

# 2. Pick a window and check it's still active
cortex tmux running claude-frontend && \
  cortex tmux say claude-frontend "status update please?"

# 3. Wait a beat, then read the response
sleep 8
cortex tmux read claude-frontend 30

When To Prefer Raw Tmux

Use raw tmux when you need full layout management — splitting new panes, resizing, or attaching interactively. cortex tmux can drive existing split panes via window.pane syntax but won’t create them for you. For day-to-day automation against named windows it remains the more stable control plane.

  • Git Workflow – pair isolated worktrees with isolated tmux windows
  • Agent Activation – load the right agents before kicking off background work
  • Export Context – hand the right context to another session or model