Sessions model

How the dashboard and CLI represent a running harness.

Two sources, one UI#

Every session in /sessions carries a source tag:

  • cu — spawned by dashboard + New session or Resume in cu. The daemon owns the PTY through pty.Broker: full read+write.
  • external — discovered: the daemon spots a running claude/codex by walking /proc (or ps/WMI) and tails its on-disk transcript via fsnotify.

Both flavours surface the same way in the dashboard — single list, same xterm view. The only behavioural difference is whether the Interactive tab accepts keystrokes (cu) or is observe-only (external).

Where the transcript lives#

text
claude_code  ~/.claude/projects/<dash-encoded-cwd>/<session-uuid>.jsonl
codex        ~/.codex/sessions/<YYYY>/<MM>/<DD>/rollout-...-<uuid>.jsonl

The discovery scanner walks recent date shards (codex) or matches by encoded cwd (claude), opens the most-recently-modified .jsonl, and confirms via payload.cwd (codex) or path naming (claude). When the process exits the daemon waits 3s before marking the session ended — covers final flushes.

Resume in cu#

External sessions can't accept dashboard keystrokes — we don't own the PTY. Click Resume in cu in the session header: the daemon launches a new cu <kind> --resume <harness-id> in the same cwd. Same conversation, PTY now owned by the broker, fully writable.

Multi-attach#

cu attach <session-id> joins a daemon-owned PTY from any terminal on the same machine. The dashboard's Interactive tab does the same thing over WebSocket. Both paths converge on pty.Broker:

  • Stdout fan-out — every subscriber sees every byte.
  • 64 KB scrollback ring per session — new attachers get recent context.
  • Controller semantics — first attacher types, others observe until --take-control.
  • Ctrl-\\ detaches without killing the session.

Permission modes#

--cu-mode is the controlum abstraction; each harness maps it to its own approval / sandbox flags. Both cu claude and cu codextranslate uniformly:

text
             claude                            codex
ask          (default — claude prompts)        (default — --ask-for-approval untrusted)
auto_safe    --permission-mode acceptEdits     --full-auto
dangerous    --dangerously-skip-permissions    --dangerously-bypass-approvals-and-sandbox

Claude additionally runs the policy engine via PreToolUse hooks — independent of the cu-mode setting. Codex doesn't have an analogous hook surface yet, so for codex sessions the cu-mode + harness flags are the only enforcement layer. The dashboard's Permissions tab is also claude-only for the same reason.