[[
wikihub
]]
Search
⌘K
Explore
People
For Agents
Sign in
Explore
People
For Agents
Sign in
@jacobcole / picortex — planning / docs/adrs/0003-tmux-for-session-persistence.md
Suggest edit
Cancel
Submit suggestion
Title
Name
Note
--- visibility: public --- # ADR-0003: tmux for per-chat session persistence **Status:** Accepted **Date:** 2026-04-23 **Deciders:** Jacob ## Context Each chat needs a persistent shell/REPL that holds Claude Code context across turns. Options: | Option | Persistence | Attach from browser? | Claude Code fit | |---|---|---|---| | Short-lived `claude --print` per turn | none | N/A | simplest but loses agentic state | | Raw PTY + `node-pty` keep-alive | in-memory | via WS | loses on process restart | | tmux session per chat | disk-backed, survives restart (with `tmux resurrect`) | `tmux attach` inside WS PTY | excellent | | screen / dtach | similar to tmux | similar | OK but tmux has better tooling | Cortex uses tmux (see `cloudcli/server`). Claude Code itself is often used inside a tmux split by Jacob. ## Decision **tmux, one session per chat, session name `picortex:<chat_id>`.** ## Consequences ### Positive - Survives backend restarts. - Web terminal (xterm.js) can attach via a backend WebSocket that shells into `tmux attach -t picortex:<chat_id>`. - Multiple browser tabs can attach to the same session (tmux natively multiplexes). - `tmux capture-pane` / `pipe-pane` gives a structured way to scrape Claude Code's output for reply routing. - Zero memory cost when idle (bash + tmux). - Consistent with how Jacob already works. ### Negative - tmux protocol has quirks when streamed over WebSocket (scrollback, resize, escape sequences). - `send-keys` + output tailing is fragile for structured reply parsing — need a small protocol on top (e.g. unique sentinel before/after each turn). - tmux must be installed on the server (trivial but still an explicit dep). ### Mitigations - Use `pipe-pane -o` to stream output to a logfile per chat; parse the logfile for reply extraction, not the terminal. - Use a delimiter protocol: before each turn, `tmux send-keys "echo '<<PICORTEX-TURN-$n-START>>'"`; after, `"echo '<<PICORTEX-TURN-$n-END>>'"`. Reply = content between delimiters, stripped of ANSI. - Resize: send `tmux refresh-client -S` on WS resize events; xterm.js reports cols/rows. - Fallback plan: if reply parsing turns out unreliable, swap to `claude --print` per turn in S3.1 and keep tmux only for the **user-visible terminal attach**, not for reply capture. ## Alternatives considered - **One long-lived `claude --print` per turn, no tmux**: Simpler, but loses the web-terminal-attach feature, which is an explicit v1 goal (FR-12). tmux covers both. - **Reuse Cortex's cloudcli PTY mux**: Heavier; carries Cortex's container assumptions. Not worth the integration cost for v1.