AI agent orchestration harness — multiple PTY sessions, MCP tools, live reload, pattern-based automation
Overview
(Takes Two To Tango) is a Rust-based terminal multiplexer purpose-built for AI agent orchestration. It allows a root AI agent (e.g., Claude Opus) to spawn, monitor, and coordinate multiple worker agents (e.g., Claude Sonnet, local models like Qwen) — each running in its own PTY session — while maintaining full control through MCP (Model Context Protocol) tools. Think of it as : session management, screen reading, keystroke injection, pattern-based notifications, live reload, and remote monitoring — all exposed as MCP tools that AI agents can call programmatically. Current AI coding assistants run as single agents in a single terminal. When tasks get complex, you want multiple agents working in parallel — but coordinating them requires infrastructure that doesn't exist in standard terminal multiplexers. was built to answer: What if the AI agent could manage its own workspace?
README
tttt — Takes Two To Tango
tttt (Takes Two To Tango) is a Rust-based terminal multiplexer purpose-built for AI agent orchestration. It allows a root AI agent (e.g., Claude Opus) to spawn, monitor, and coordinate multiple worker agents (e.g., Claude Sonnet, local models like Qwen) — each running in its own PTY session — while maintaining full control through MCP (Model Context Protocol) tools.
Think of it as tmux designed for AI agents: session management, screen reading, keystroke injection, pattern-based notifications, live reload, and remote monitoring — all exposed as MCP tools that AI agents can call programmatically.
**WARNING: This software gives AI agents direct access to terminal sessions, including the ability to execute commands, send keystrokes, and manage processes. Session sandboxing is not yet implemented. Use only in experimental / proof-of-concept environments and always supervise the running agents. Do not deploy in production or on systems with sensitive data without proper isolation in place. ALSO: If you enable the input logging, everything including your password keystrokes are logged into ~/.local/share/tttt/tttt.db - keep this in mind and avoid entering any sensitive info ! **
Why This Exists
Current AI coding assistants run as single agents in a single terminal. When tasks get complex, you want multiple agents working in parallel — but coordinating them requires infrastructure that doesn’t exist in standard terminal multiplexers.
tttt was built to answer: What if the AI agent could manage its own workspace?
The result: Claude Opus running inside tttt can autonomously launch Sonnet workers, delegate implementation tasks, monitor progress, review and commit code, restart itself to pick up new tools, and even message the human on Webex when it needs input — all without human intervention.
Demo: What a Real Session Looks Like
In a single session, Claude Opus (running as the root agent inside tttt):
- Launched a Sonnet worker in a new terminal and sent it a feature spec
- Monitored progress using
tttt_get_status(idle time, last output line) - Approved permissions when Sonnet hit permission prompts
- Reviewed the code, ran tests, and committed — all while Sonnet worked on the next task
- Live-reloaded tttt with
SIGUSR1to pick up code changes without losing any sessions - Restarted itself with
SIGUSR2to discover newly-added MCP tools, auto-continuing via--resume - Messaged the human on Webex when it needed input, read the reply, and continued working
All of this happened in a single 3-hour session where 16 features were implemented — most by delegating to Sonnet.
Features
Terminal Management (MCP Tools)
tttt_pty_launch— Spawn new terminal sessions with custom commands, dimensions, working directoriestttt_pty_get_screen— Read current screen contents (what the human would see)tttt_pty_send_keys— Inject keystrokes (including special keys like Ctrl+C, Enter, arrow keys)tttt_pty_list/tttt_get_status— Dashboard view of all sessions with idle times and last outputtttt_pty_wait_for— Block until a regex pattern appears on screentttt_pty_wait_for_idle— Block until a session stops producing output (withignore_patternfor filtering timestamps)tttt_pty_kill/tttt_pty_resize— Session lifecycle managementtttt_pty_start_capture/tttt_pty_stop_capture— Capture raw PTY output to file
Agent Coordination
tttt_notify_on_pattern— Watch a session’s screen and inject text into another session when a pattern matchestttt_notify_on_prompt— One-shot version for prompt detectiontttt_self_inject— Agent injects text into its own sessiontttt_pty_handle_rate_limit— Detects Claude Code rate limit dialogs, parses the reset time (timezone-aware), waits, and auto-continues
Session Replay
tttt replay— Interactive ratatui-based TUI for browsing and replaying recorded terminal sessions- Differential logging — All PTY output is automatically logged to SQLite with timestamps (only new bytes per update)
- Full-color playback — Replays terminal output with accurate colors, bold, italic, underline, and cursor positioning
- Playback controls — Play/pause, speed control (0.125x–16x), frame stepping, seeking via keyboard
- MCP replay tools —
tttt_replay_list_sessions,tttt_replay_get_screen,tttt_replay_get_timelinefor programmatic access - Legacy database support — Works with databases created before session tracking was added
--danger-log-user-input-including-passwords— Opt-in flag to also record keystrokes (disabled by default for security)
Persistence & Communication
tttt_scratchpad_write/tttt_scratchpad_read— Key-value store that persists across reloadstttt_sidebar_message/tttt_sidebar_list— Display messages in the TUI sidebar (persists across reloads)- Scheduler — Cron jobs and one-shot reminders with
tttt_cron_create/tttt_reminder_set
Live Reload
SIGUSR1— Lightweight reload viaexecv(): replaces the binary while preserving all PTY sessions (child processes never notice — same PID, inherited FDs)SIGUSR2— Full reload: kills and relaunches the root agent with--resume, enabling new MCP tool discovery while auto-continuing the conversation- MCP proxy auto-reconnect — The MCP proxy detects socket disconnection during reload and reconnects with backoff
- Attach viewer auto-reconnect — Remote viewers (
tttt attach) survive reloads seamlessly
Keyboard Shortcuts
All keybindings use a prefix key: Ctrl+\ (like tmux’s Ctrl+b).
| Keys | Action |
|---|---|
Ctrl+\ then 0-9 |
Switch to terminal N |
Ctrl+\ then n |
Next terminal |
Ctrl+\ then p |
Previous terminal |
Ctrl+\ then c |
Create new terminal session |
Ctrl+\ then r |
Live reload (SIGUSR1 equivalent) |
Ctrl+\ then w |
Enable/disable the web server (opens a host/port/htpasswd dialog) |
Ctrl+\ then d |
Detach / quit |
Ctrl+\ then ? |
Show help |
Ctrl+\ then Ctrl+\ |
Send literal Ctrl+\ to the terminal |
Remote Monitoring
tttt attach— Connect from another terminal (or phone via SSH) to watch the AI work in real-time- Virtual screen rendering — Attach uses a virtual vt100 screen to absorb rapid updates, only rendering the final state
- Bracketed paste detection — Prevents accidental detach during paste operations
Web Console (EXPERIMENTAL)
⚠️ The web console is experimental. Use it only on trusted local networks or over a VPN. Do not expose it to the open internet: the feature is young, the auth is a single shared token or htpasswd file, and whoever connects can type into your terminal sessions.
An optional browser UI (xterm.js over WebSocket) for watching and driving sessions when SSH isn’t handy:
# Loopback only (default; no auth required)
tttt --http-port 8080 -e "claude"
# LAN/VPN bind: an access token is auto-generated and printed in the URL,
# and it survives SIGUSR1 live reloads
tttt --http-port 8080 --http-host 0.0.0.0 -e "claude"
# HTTPS with a self-signed certificate (or supply --tls-cert/--tls-key)
tttt --http-port 8080 --http-host 0.0.0.0 --secure -e "claude"
# Username/password auth (bcrypt, apr1, {SHA} and plaintext entries);
# can be combined with --token
tttt --http-port 8080 --http-host 0.0.0.0 --htpasswd users.htpasswd -e "claude"
- Toggle it at runtime with
Ctrl+\w— a dialog prompts for host, port, and an optional htpasswd file (prepopulated from any CLI/config values) - Watch and type into any session; create and close sessions from the sidebar
- Follows the PTY size owned by the TUI (the browser never resizes your terminal)
- The access URL is shown at the top of the root terminal on startup and in
the help overlay (
Ctrl+\?) - Config keys (
http_port,http_host,secure,tls_cert,tls_key,htpasswd,token) andTTTT_HTTP_PORT/TTTT_HTTP_HOST/TTTT_SECUREenv vars mirror the CLI flags
Architecture
tttt (TUI process)
|
├── PTY sessions (managed via SessionManager)
│ ├── pty-1: root agent (Claude Opus)
│ ├── pty-2: worker agent (Claude Sonnet)
│ ├── pty-3: local model (apchat + Qwen)
│ └── pty-N: ...
│
├── MCP proxy socket (/tmp/tttt-mcp-PID.sock)
│ └── JSON-RPC bridge: Claude Code ←stdio→ proxy ←socket→ tttt
│
├── Viewer socket (/tmp/tttt-PID.sock)
│ └── Remote attach clients (screen streaming + input relay)
│
├── Notification system (pattern watchers + injection queue)
├── Scheduler (cron + reminders)
├── Logger (text + SQLite)
└── Sidebar renderer (sessions + messages + uptime)
Workspace Crates
| Crate | Purpose |
|---|---|
tttt-pty |
PTY session management, MockPty for testing, RestoredPty for live reload |
tttt-mcp |
MCP server implementation, 15 tool handlers, proxy with auto-reconnect |
tttt-tui |
Terminal UI: sidebar, pane rendering, input parsing, viewer protocol |
tttt-log |
Logging to text files + SQLite, session replay engine |
tttt-scheduler |
Cron job parsing and reminder system |
tttt-sandbox |
Session sandboxing profiles (placeholder for future isolation) |
vt100 |
Vendored vt100 terminal emulator (modified for scrollback + formatting) |
Quick Start
# Build
cargo build
# Run with Claude Code as the root agent
./target/debug/tttt -e "claude"
# Attach from another terminal to watch
./target/debug/tttt attach
# Or watch from a browser (EXPERIMENTAL — local networks/VPNs only)
./target/debug/tttt -e "claude" --http-port 8080
# Replay recorded sessions
./target/debug/tttt replay
# Live reload after code changes
kill -USR1 $(pgrep -f "target/debug/tttt -e")
# Full reload (restarts root agent, discovers new tools)
kill -USR2 $(pgrep -f "target/debug/tttt -e")
Docker
A pre-built Docker image is available. By default it runs tttt -e docker, which uses the Docker-specific environment configuration:
# Run with the default Docker environment
docker run -it ghcr.io/ayourtch-llm/tttt:latest
# Pass custom arguments to tttt instead
docker run -it ghcr.io/ayourtch-llm/tttt:latest -e "claude --prompt 'hello'"
When no arguments are given, the entrypoint launches tttt -e docker. Any arguments you supply are passed directly to tttt, replacing the default.
MCP Configuration
tttt automatically generates an MCP config and injects it when it detects a supported root command:
- Claude Code: injects
--mcp-configwith a generated config file containing thettttMCP server. - opencode: injects the
ttttMCP server via theOPENCODE_CONFIG_CONTENTenvironment variable (merged with any existing opencode config). - Codex CLI: injects invocation-scoped
--configoverrides for thettttMCP server, without modifying~/.codex/config.toml.
The root agent gets all tttt_* tools available immediately.
For external MCP tools (e.g., Webex messaging), add them to ~/.claude.json (Claude), your opencode.json (opencode), or ~/.codex/config.toml (Codex):
{
"mcpServers": {
"webex": {
"command": "/path/to/mcp-webex-messaging"
}
}
}
The Autonomous Agent Loop
With tttt, the root agent can operate fully autonomously:
1. Receive task from human (or Webex message)
2. Write plan to scratchpad
3. Launch Sonnet worker: tttt_pty_launch("claude --model sonnet")
4. Send task spec: tttt_pty_send_keys(spec)
5. Wait for completion: tttt_pty_wait_for_idle(session, 30s)
6. Review output: tttt_pty_get_screen(session)
7. Run tests: cargo test
8. Commit if passing
9. Build and reload: cargo build && kill -USR1
10. If new tools needed: kill -USR2 (auto-restarts with --resume)
11. If stuck or need human input: send_webex_message(...)
12. If rate limited: tttt_pty_handle_rate_limit (auto-waits and resumes)
13. Loop
Testing
# Run all tests (~140 tests across all crates)
cargo test
# Run specific crate tests
cargo test -p tttt-mcp # MCP tools and handlers
cargo test -p tttt-pty # PTY session management
Status
This project is under active development. The core infrastructure is solid and battle-tested through real autonomous coding sessions. The web console is experimental — keep it on trusted local networks or VPNs. Key areas for future work:
- TextFSMPlus integration — Automated permission approval via state machine templates
- Git worktree isolation — Per-worker sandboxed repositories
- Heterogeneous agent teams — Mixing different AI models with role-based routing
Background: An AI-Designed Tool for AI Agents
tttt has an unusual origin story — it was designed by an AI, for AI agents, based on real operational pain points.
Phase 1: The Research Session (8+ hours)
A Claude Opus instance was orchestrating a Claude Sonnet executor via tmux to run 60+ medical survival prediction experiments. Over 8 hours, the root agent encountered every pain point that tttt now solves: 80+ manual permission approvals, 40% of tokens wasted on polling, messages lost to scroll, UI state confusion, and no way to run experiments in parallel.
The two-Claude collaboration beat the Kaggle competition winner (0.7231 vs 0.7424) — but the interaction overhead was brutal. Afterward, the root Claude documented everything as 18 user stories with prioritized pain points, design principles, and hard-won lessons (see docs/user-stories/).
Key insights from that session:
- “Permission prompts are blocking — if the root agent doesn’t notice, the executor sits frozen indefinitely” (now solved by
tttt_pty_handle_rate_limitand notification watchers) - “The sleep-tail-read cycle wasted 40% of tool calls” (now solved by
tttt_pty_wait_for_idle) - “After ~4 hours, earlier results get compressed away. The scratchpad is not a nice-to-have — it’s essential” (now solved by persistent scratchpad and sidebar messages)
- “AI agents think out loud with creative verbs: ‘Crunching…’, ‘Prestidigitating…’ — match on spinner characters, not verbs” (pattern matching in notification system)
Phase 2: Implementation
The harness was built iteratively with Claude as both architect and primary user. The test suite was designed based on a test plan written by the “Original Claude” from the research session.
Phase 3: Self-Hosting
Once the core was functional, development shifted to a bootstrapping model: Claude Opus running inside tttt orchestrated Claude Sonnet workers to implement new features — using the harness itself as the development environment. In a single session, 16 features were shipped with Sonnet implementing most of them in 3-5 minutes each, while Opus reviewed, tested, committed, and live-reloaded without restarting.
The companion mcp-webex-messaging MCP server was also built during self-hosting, enabling the root agent to contact the human via Webex when operating autonomously.
This bootstrapping loop — AI agents building their own orchestration infrastructure while using it — validated every design decision in real-time and continues to drive development.
Author
Andrew Yourtchenko — Systems engineer with deep expertise in AI agent infrastructure, terminal systems, and autonomous workflows.
- Building tools at the intersection of AI and systems programming
- Experienced in designing multi-agent orchestration architectures
- Available for consulting on AI agent infrastructure, MCP tool development, and autonomous workflow design
GitHub | AI Agent Projects | Email
Built With
tttt was built collaboratively with Claude Code by Anthropic. The architecture was designed by Claude Opus, and many features were implemented by Claude Sonnet workers running inside tttt itself — making this one of the first projects where AI agents built their own orchestration infrastructure while using it.
The mcp-webex-messaging companion crate (MCP server for Webex messaging) was also built during the same session, enabling the root agent to contact the human via Webex when operating autonomously.
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Install
docker run -it ghcr.io/ayourtch-llm/tttt:latestConfiguration
{
"mcpServers": {
"webex": {
"command": "/path/to/mcp-webex-messaging"
}
}
}