Files
tai/research/shell-multiplexer-auto-attach/conclusions/multiplexer-proposal-design-basis.md
T
retoorandClaude Sonnet 5 9dbd1fe667 Add plexer subsystem, container test infra, and last-resort opencode box backend
- Plexer: always-active terminal multiplexing. NativePlexerController/
  TmuxPlexerController share one interface, chosen by which env var is
  already set (TAI_PLEXER_SOCKET vs TMUX_PANE); NativePlexerBackend is
  the pty.fork()-based wrapper (raw mode, SIGWINCH resize forwarding,
  a Unix-socket control protocol, continuous session logging, a
  Ctrl+A prefix key distinct from tmux's own Ctrl+B). Auto-wraps new
  interactive shells via a .bashrc hook mirroring the existing
  command-not-found install pattern, gated on $TMUX/$TAI_PLEXER_ACTIVE/
  a $HOME/.tai-no-plexer bypass. New plexer_send/read/type/status
  tools, env-gated on a detected controller.
- tests/container.py + docker-compose.yml + tests/docker/Dockerfile:
  a disposable podman/docker image for the tests that must never touch
  a real machine (installing the plexer hook into a real ~/.bashrc, a
  live tmux session). Required suite (test_seal.py, test_tai.py,
  tests/plexer.py, tests/bashrc.py) gates the result; tests/rag.py
  runs as best-effort since its real-LLM dependency can't be satisfied
  inside a disposable container with no nested engine.
- tests/bashrc.py: real end-to-end hook install + bash -i auto-wrap,
  anti-recursion, tmux-active skip, non-interactive skip, a live
  TmuxPlexerController test, and an install/uninstall round-trip.
- tests/plexer.py: NativePlexerBackend under a real pty, plus a
  dedicated robustness pass (file permissions, >64KB payload framing,
  a malformed control request, a genuine self-deadlock fix in the
  write-to-child path).
- tai_test.py: the shared async process-driving framework (pipe/pty
  transport, group-wide kill-and-reap, a StdinBridge for --interactive)
  both test files build on.
- ChatClient last-resort backend: when there's no local opencode CLI
  but the sandbox box is already running, install opencode into it
  (official Node tarball, not apt -- apt's nodejs/npm pull in
  webpack/babel/jest as transitive deps) and route through it instead
  of giving up. Only reachable after the first retry round already
  failed everything else; never creates the box itself. TmuxPlexerController.status()
  fixed to use `list-panes` instead of `display-message -p`, which
  silently fell back to the default pane instead of erroring against
  a dead target.
- Fix 4 pre-existing test_tai.py bugs surfaced by running it in a
  clean environment for the first time: two stale mock signatures
  (subprocess.run's stdout= kwarg, Chat.complete's deadline= kwarg),
  one $TMUX-dependent catalog assertion, one tty-dependent color
  assertion.
- research/: a sourced research archive (Source Dossier/Citation
  Card/Conclusion tiers) backing the above design decisions, with its
  own audit.py consistency checker.
- .gitignore: fix a blanket *.md rule that was about to silently drop
  the entire research/ archive from version control; add __pycache__/
  and the one-off debug transcript this session started from.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-10 04:36:05 +02:00

7.6 KiB

Conclusion: Build on tmux, Never Guess at "Is This a Human" Alone

Metadata

Field Value
Institute Molodetz Institute — Research & Retrieval Division
Subject shell-multiplexer-auto-attach
Document type Conclusion
Tier N/A
Date decided 2026-10-09
Decided by retoor, advised by tai (agent, Claude Sonnet 5)
Status Active (research complete, proposal pending decision, no code written)
Confidence High

Question / problem statement

retoor asked for a tai-managed terminal multiplexer, auto-attached transparently whenever a real interactive bash shell starts — but explicitly not when bash is invoked by automation, scripts, or tools (including tai/Claude Code's own shell tool) that happen to also source .bashrc — supporting resize, sound/bell passthrough, events, raw keystroke handling, a named-socket or fd-based control channel, programmatic commands (read pane content, grep it, write/type at a position, animated typing), and continuous full-session logging. Deep research was explicitly requested before any implementation.

Conclusion

Build this as a thin control layer on top of tmux, not as a new PTY multiplexer kernel. tmux already provides, battle-tested, exactly the substrate this proposal needs: a client-server architecture over a configurable Unix socket (-L/-S), persistent sessions that survive disconnects, native SIGWINCH/resize handling, bell passthrough, hooks, a human-typing interface (send-keys/capture-pane), a structured scripting interface (control mode, -CC), and a continuous-logging primitive (pipe-pane) that directly satisfies "remember the whole process log." tai (per its own root README.md) already optionally depends on tmux and already shells out to tmux capture-pane rather than reimplementing terminal capture — this proposal is a natural extension of that existing posture, not a new direction.

The one genuinely hard, unsolved-by-tooling part of the request is reliably distinguishing a human-opened interactive shell from bash being invoked by a script, IDE, or AI coding agent sourcing the same .bashrc. This research found it is a recognized, actively-discussed, unsolved-in-general problem (VS Code's own agent-terminal issues, security detection-rule false-positive guidance, dedicated "AI agent terminal detection" posts) with no single reliable signal — only a combination of weaker ones ($- containing i, $TMUX unset, $SSH_TTY/$SSH_CONNECTION, parent process name, an agent-identifying env var), each individually defeatable in one direction or the other.

Supporting sources

  • ../man7-tmux-manual.md, ../tao-of-tmux-server-internals.md, ../github-tmux-discussion-3567-no-raw-socket-api.md — tmux's client-server/socket architecture and the hard boundary of what's scriptable (commands + control mode, no raw socket protocol).
  • ../tmuxai-dev-control-mode.md, ../github-tmux-discussion-4016-control-mode-output.md, ../github-tmux-wiki-control-mode.md, ../libtmux-pane-interaction.md, ../tmuxai-dev-faq.md — the concrete mechanisms (-CC framing, send-keys/capture-pane loop, pipe-pane streaming) the control layer is built from.
  • ../android-adb-cfmakeraw-commit.md, ../stalkr-remote-tty-resize-design.md, ../systemd-ptyfwd-resize-forwarding.md, ../coral-mdt-console-sigwinch-commit.md, ../lkml-2003-sigwinch-foreground-process-group.md — what would have to be hand-built (raw termios mode, SIGWINCH handling, resize-over-socket forwarding) if tmux were not used; the cost this recommendation avoids entirely, since tmux already does all of it internally.
  • ../bash-manual-interactive-shell-definition.md, ../cyberciti-nixcraft-dollar-dash-test.md, ../oreilly-bash-cookbook-interactive-test.md, ../pythontutorials-net-ps1-child-process-caveat.md, ../gitlab-mr-3383-stdin-stdout-isatty-mismatch.md, ../lkml-mailing-list-tty-s-insufficient.md — why $- is the right first-line interactivity check, and why isatty/PS1-alone checks fail in documented, specific ways.
  • ../elastic-detection-rule-interactive-terminal-python.md, ../panoramicdata-detecting-ai-agent-terminals.md, ../github-vscode-community-discussion-161238.md, ../github-vscode-issue-253265.md, ../github-fak-issue-11425-pty-interactive-prompt-detection.md — independent, cross-domain confirmation that human-vs-automation terminal detection is a recognized hard problem with no single reliable signal, only combined weaker ones plus explicit allowlisting by known tool identity.
  • ../bbs-archlinux-tmux-env-guard.md, ../codegenes-net-ssh-tty-tmux-guard.md, ../unix-stackexchange-ssh-tmux-nesting.md, ../santini-tmux-safety-file.md — the concrete guard conditions ($TMUX, $SSH_TTY/$SSH_CONNECTION) and, critically, the mandatory safety-file bypass pattern for when the auto-attach logic itself is wrong.
  • ../dasroot-net-tmux-vs-zellij.md, ../theregister-tiling-multiplexer-survey.md — why tmux specifically, not Zellij, fits this proposal's scripting-and-SSH-heavy requirements.
  • ../github-bitcanon-autotyper.md, ../nncron-send-keys-delay-docs.md, ../tabby-typewriter-mode-docs.md, ../raycast-fake-typing-effect.md, ../k6-browser-presssequentially.md — the basis for a typing-animation command syntax (per-character delay, inline pause/speed tokens, optional randomization).

Alternatives considered and rejected

  • A from-scratch terminal multiplexer (raw termios mode, SIGWINCH handling, a hand-rolled Unix-socket IPC protocol, session persistence, all built independently). Rejected: this re-solves a problem tmux has already solved, for a project whose own stated design philosophy (root README.md) is dependency-light and pragmatic, and which already optionally depends on tmux and already shells out to it for capture rather than reimplementing. The "research is done, confidence high" status above specifically reflects how thoroughly this exact problem surface (raw mode, resize forwarding, socket IPC) turned out to already be solved, documented, and battle-tested elsewhere.
  • Zellij as the substrate instead of tmux. Considered, not dismissed out of hand — but tmux fits better given tai already optionally depends on it, and the research (dasroot-net-tmux-vs-zellij.md) found tmux specifically stronger for scripting and SSH/remote use, which is the actual requirement here; Zellij's documented strength is a discoverable interactive UI, not a scripting substrate.
  • A single boolean "is this shell interactive" check as the sole auto-attach gate. Rejected: both the bash-detection dossiers and the automation-false-positive dossiers in this subject independently show this fails in both directions (automation tools that pass isatty()/$- checks; genuinely interactive shells an over-narrow check might miss).

Risks / open questions

Unconditionally auto-wrapping every bash session from .bashrc is a high-blast-radius, hard-to-reverse-if-wrong system change: it can break automation, CI, IDE-integrated terminals, and — if misdetected — the agent's own shell tool (the exact tool this research is being conducted through). This was explicitly not implemented as part of this research task; it is proposed, pending the human's explicit review and confirmation of the exact activation condition and the mandatory safety-bypass mechanism (per santini-tmux-safety-file.md) before any .bashrc on a real machine is touched.

Action taken

None yet. This was a research-and-proposal task; implementation is explicitly deferred pending retoor's review of the proposal presented alongside this archive.

Changelog

Date Change
2026-10-09 Initial conclusion recorded.