Repository navigation
Coding sessions no longer use tmux, but the names, diagnostics, kill-tmux control and docs all still say they do #247
Description
The Coder engine stopped using tmux — packages/browser-runner/src/coding/headless.ts:29:
The coding engine — Claude Code driven through its structured stream-json interface, NOT a
scraped tmux TUI … Survives a runner restart without tmux … routes and console keep working
unchanged — only the guts move from tmux to structured JSON.
It spawns a child process (spawn(this.cmdBin, …), :241/:321) and tracks it via
proc.exitCode/signalCode. Nothing in that path calls createSession from coding/tmux.ts.
tmux is still genuinely used — but only by the terminal-operator family (coding/terminal.ts,
server.ts:351-363), i.e. the tmux / Terminal / kitty / iTerm2 Operator agents. Those create real
sessions. Repo Coders do not.
The surface around the coding path was never cleaned up, and it now actively misleads.
What's stale
1. A session name that names nothing. headless.ts:115 still computes
this.sessionName = pags-${clientType}-${id}, which is persisted to coding_sessions.tmux_session
and surfaced through the API and console. On a live instance today: 13 sessions each recording
pags-claude-csess_…, and zero such tmux sessions have ever existed. A user who tries
tmux attach -t pags-claude-csess_… — the obvious thing to do with a name like that — gets
"session not found" and reasonably concludes their engine is broken.
2. Diagnostics measure something structurally always zero. coding_diagnostics returns
tmux: { trackedSessions, orphanedSessions, tmuxTotal, pagsTmuxTotal }. Real output from an
instance whose runner is healthy:
tmux: { trackedSessions: 0, orphanedSessions: [], tmuxTotal: 4, pagsTmuxTotal: 0 }
pagsTmuxTotal: 0 is not a symptom — it can never be anything else for a coding agent. tmuxTotal: 4
counts the user's own unrelated tmux sessions. This is the panel someone opens because something
is wrong, and it points them at a false cause.
3. A "Kill tmux" control that cannot help. POST /:instanceId/coding/kill-tmux (routes/coding.ts:1413)
proxies to the runner's /coding/kill-tmux. For a coding session there is no tmux to kill, so the
diagnostics panel offers a cleanup action that structurally no-ops for the sessions it is shown
beside.
4. The docs describe the old architecture. pags/CLAUDE.md still says "Engine = the actual CLI
running in a tmux pane on the user's machine", "tmux addressed by session name (not :0.0)",
and "The runner reattaches to existing tmux coding sessions on reconnect". The last one is
wrong in a load-bearing way: reattach works by re-spawning with --resume <claudeSessionId> from
~/.claude, which is why it survives a restart without tmux.
5. Stale comments in live code. lib/coding-store.ts:444 explains the driver-claim expiry in
terms of "the RUNNER reports no tmux". The reconciler is fine — trackedIds comes from the runner's
in-memory tracked[] registry (routes/coding.ts:1495-1497), not from tmux — but the comment sends
the next reader down the wrong path. (Verified: not a functional bug.)
Suggested shape
- Drop
tmuxSessionfrom the coding-session model, or rename it to what it is (an engine/session
label). If the column stays for migration reasons, stop surfacing it in the API and console. - Remove the tmux block from
coding_diagnosticsfor coding agents, or scope it to the
terminal-operator agents where it means something. - Retire or re-scope
kill-tmuxon the coding path. - Update
CLAUDE.mdand the published docs to describe the stream-json engine and--resume
reattach. Docs [docs] Reconcile runtime docs with relay-onlypags up#208/[docs] Update Coder docs for runner-node picker, engines, and package paths #211 already cover runtime/Coder doc drift — this belongs with them.
Why bother
This is what made a maintainer (and the product owner) ask "are Coder agents connected to tmux?"
and start debugging in the wrong place. The names, the diagnostics panel and the docs all assert an
architecture the code deliberately replaced.
Verified, and the three forks resolved
Every claim above checks out against the code, plus the live-data assertion: this machine has 4 tmux sessions and zero named pags-* — one is tmux-operator-runner, i.e. the operator family, exactly as described.
Two findings that decide the open questions:
Nothing consumes the stale surfaces. No console or coder-web code reads tmuxSession, pagsTmuxTotal, or calls kill-tmux. The only consumer of /coding/diagnostics at all is MCP coding_diagnostics (workers/mcp/src/instance-tools/coding.ts:27), which passes the JSON through. So all three forks lean the same way — remove — and none is a breaking change for a real caller.
kill-tmux is NOT a no-op, contrary to point 3. Its no-args branch calls runner.coding.closeAll() (server.ts:237), which really does close the tracked engine processes. Only the tmux targeting is dead. Retiring the route wholesale would delete the one working "close everything" escape hatch — it needs re-scoping, not removal.
Decisions
sessionName→engineLabel, and drop thepags-prefix. The prefix is what makes a user typetmux attach -t pags-claude-…. In the coding path this value addresses nothing —runtime.ts:193/211only reports it. The persisted columncoding_sessions.tmux_sessionstays (a D1 column rename is a table rewrite for a cosmetic gain); it gets a comment saying it holds an engine label under a legacy name, and stops being surfaced astmuxSessionin API responses.- Remove the tmux block from the coding diagnostics rather than scoping it.
trackedSessions/orphanedSessions/pagsTmuxTotalare structurally zero for coding agents, andtmuxTotalcounts the user's unrelated sessions. The operator agents have their own endpoints and are untouched. - Re-scope
kill-tmuxto what works. Runner keeps the path (an older runner must still answer a newer API — version skew), with the tmux targeting stripped so it just closes tracked coding sessions. The API gains the honest namePOST /:instanceId/coding/close-sessions;kill-tmuxstays as a deprecated alias since removing a route nothing calls buys nothing.
Also needed, not in the original scope
coding/tmux.ts also hosts ensureRepo (:166, does the git clone) and sanitizeSessionName (:153), both imported by runtime.ts:6 and neither anything to do with tmux. The file cannot simply shrink to nothing; those two move out first.
The docs pointer at the end should not say #208/#211 — those are the two docs tickets whose numbers unrelated commits have been misusing, so it sends the reader to the wrong place.
Acceptance criteria
- No coding session records or reports a
pags-*value that looks like a tmux target. -
/coding/diagnosticsreturns nothing tmux-shaped for a coding agent; the operator agents' tmux endpoints are unchanged and still work. - "Close all coding sessions" still works, under a name that says so.
-
ensureRepo/sanitizeSessionNameno longer live in a file named tmux. -
coding-store.ts:444no longer explains the claim expiry in terms of tmux. -
pags/CLAUDE.mddescribes the stream-json engine and--resumereattach, not tmux panes. - Tests cover the label shape and the diagnostics payload.
Activity
docs: Coder agents do not run in tmux (refs #247)
fix(coder): stop asserting a tmux architecture the engine replaced (#247
serge-ivo commentedon Aug 6, 2026
Confirmed there is no tmux option on the coding path —
CodingRuntime.start()(coding/runtime.ts:126) unconditionally constructsnew HeadlessSession({…}). No branch, no flag, no env var selects a tmux-backed engine, so this is not a configurable backend that happens to default away from tmux; the alternative implementation is gone.Two more stale comments to fold into the cleanup, both in
coding/runtime.tsand both describing the removed design::9-10— "The coding runtime: the local 'hands' that hold live tmux coding sessions, the tmux counterpart of the browser runtime's Playwright page management.":60— "…the tmux analogue of…"Worth stating positively in whatever replaces these, since it is the question a reader actually has: on a Coder you choose the engine (
config.codingEngines→ the session'slaunch_command), not a terminal backend. tmux belongs to the terminal-connector agents.serge-ivo commentedon Aug 6, 2026
Delivered in ca534f3 — API deployed, CLI 0.4.31 published.
All four decisions from the resolution above shipped:
sessionName→engineLabel, formatted<engine>:<id>. Thepags-prefix is gone — it was the thing that madetmux attach -t pags-claude-…look like the obvious move.coding_sessions.tmux_sessionkeeps its name (a D1 column rename is a table rewrite for a cosmetic gain) with a comment saying what it actually holds, and is surfaced asengineLabel./coding/diagnostics, replaced byengine: { trackedSessions }. The operator agents'/tmux/*endpoints are untouched.kill-tmuxre-scoped, not retired — see the correction above: it was never a no-op. It now closes tracked coding sessions and nothing else, exposed asclose-sessions, with the old runner path and API route kept as aliases for version skew.ensureRepo+sanitizeSessionNamemoved tocoding/repo.ts, so the tmux module is only tmux and only the terminal-operator agents import it.coding-store.ts:444and the surrounding tmux-framed comments are corrected.Docs were already done — another session had updated
pags/CLAUDE.mdto describe the stream-json engine and--resumereattach, citing this issue. I fixed the two lines that my change made stale (the label shape, andkill-tmuxin the route list). So the point about #208/#211 is moot; nothing here depends on them.Verified on a live machine throughout: 4 tmux sessions, zero named
pags-*, one beingtmux-operator-runner.2842 tests green.
serge-ivo commentedon Aug 6, 2026
Two follow-ups filed off this:
feat(coder): report which credential a session actually used, not whi…
feat(agents): a prompt may not tell an agent something its capabiliti…
fix(runner): a one-shot engine's turn ends when its process exits, no…
docs(coding): "can I use tmux for coding?" gets an answer, and it nam…