English · 한국어
Run a fleet of AI coding agents from anywhere — even your phone.
AgentBoard is a browser-based command center for running many AI coding agents in parallel. Spawn Claude Code, Codex, Aider, or any shell-based agent in its own tmux session, switch between them with a tap, and pick up exactly where you left off — from your laptop, your tablet, or your phone.
Designed for the moment your agents outgrow a single terminal tab.
Modern coding agents are most useful when they run for minutes or hours, not seconds. Soon you're juggling three, five, ten of them — and tmux alone gets old fast on mobile. AgentBoard wraps tmux in a clean dashboard that:
- Just works on mobile. Real touch scroll with momentum, no broken gestures, no pinch traps. Built and tuned on actual devices, not emulators.
- Knows what each agent is doing. Each session shows an
idle/working/waitingbadge derived from its terminal output. - Refuses to lose state. Sessions live in
tmux— they survive page reloads, server restarts, and flaky networks. - Is honestly fast. 80 ms screen refresh on the session you're looking at, 2 s on the rest. Adaptive, never wasteful.
- Long-running refactors — kick off an agent at your desk, check its progress from your phone over coffee, tap once to send
ywhen it asks for confirmation. - Parallel coding — three agents on three branches, one dashboard, zero context-switching tax.
- Pair-programming with yourself — the same
tmuxstate, viewed live from any device on the network. - Tablet-first development — file browser, code editor, PDF viewer, and a live terminal — all in one tab.
| Multi-session terminal | Spawn, kill, rename, and switch between unlimited tmux sessions |
| Mobile-first UI | Custom touch handlers — momentum scroll, scroll-to-bottom, keyboard-friendly input |
| Live state detection | Per-session badges: idle, working, waiting-for-input |
| Adaptive polling | 80 ms on the active session, 2 s on background sessions |
| File browser & editor | CodeMirror 6 with syntax highlighting for 13+ languages |
| Markdown + KaTeX | Inline preview, sanitized, math rendered server-free |
| PDF viewer | Zoom (50–300%), fit-to-width, lazy-loaded for instant boot |
| Cookie auth | Single password, HMAC-SHA256 signed |
| Optional Cloudflare tunnel | Expose the dashboard publicly with one env var |
| Survives everything | tmux-backed sessions persist across reloads, restarts, and disconnects |
git clone https://github.com/ralbu85/AgentBoard.git
cd AgentBoard
# Backend (Python 3.12 + FastAPI)
python3.12 -m venv backend/.venv
backend/.venv/bin/pip install -r backend/requirements.txt
# Frontend (React + Vite)
cd frontend && npm install && cd ..
# Configuration — path is set in backend/config.py
mkdir -p /root/TermHub
cat > /root/TermHub/.env <<EOF
DASHBOARD_PASSWORD=changeme
AGENTBOARD_PORT=3002
EOF
# Build the frontend and start the server
./deploy.shOpen http://localhost:3002, log in, hit + New — and you're spawning agents.
Browser (xterm.js + React)
│
│ HTTPS / WSS
▼
nginx :12019
│
▼
uvicorn :3002 ──── pipe-pane FIFO
│ capture-pane polling
▼
tmux sessions
| Layer | Stack |
|---|---|
| Frontend | React 19, xterm.js 5.5, Zustand, Vite, CodeMirror 6 |
| Backend | FastAPI, asyncio, tmux via async subprocess |
| Auth | HMAC-SHA256 signed cookie |
| Proxy | nginx (optional, recommended for HTTPS) |
| Method | Path | Body |
|---|---|---|
POST |
/api/login |
{pw} |
GET |
/api/workers |
— |
POST |
/api/spawn |
{cwd, cmd} |
POST |
/api/kill |
{id} |
POST |
/api/remove |
{id} |
POST |
/api/input |
{id, text} |
POST |
/api/key |
{id, key} |
GET |
/api/browse?path= |
directory listing |
GET |
/api/files?path= |
file metadata |
GET |
/api/file?path= |
read file |
POST |
/api/file |
{path, content} |
GET |
/api/health |
readiness probe |
- Client → server:
resize,active,resync,title,key,terminal-input,input - Server → client:
spawned,snapshot,screen,stream,status,cwd,aiState,info,title,titles
backend/
main.py FastAPI app, lifespan, static serving
config.py .env loading, auth token, project root
auth.py HMAC-SHA256 cookie auth
sessions.py SessionStore: spawn / kill / recover tmux
streamer.py pipe-pane FIFO + capture-pane polling
state_detector.py idle / working / waiting heuristics
tmux.py async tmux wrappers
ws.py WebSocket routing + broadcast
routes_session.py REST: login, workers, spawn, kill, input
routes_file.py REST: browse, files, read / write
tunnel.py optional Cloudflare tunnel
frontend/
src/
App.tsx root + login flow
store.ts Zustand state
ws.ts WebSocket singleton
api.ts REST wrappers
components/Terminal/ xterm.js lifecycle, mobile scroll
components/Sidebar/ session list, mobile overlay
components/Viewer/ split layout, code editor, file content
components/SpawnModal/ new-session dialog
components/FilePanel.tsx file browser
components/PdfViewer.tsx PDF rendering
components/Header.tsx status bar, + New
components/Login.tsx password login
components/Toaster.tsx toast notifications
A few non-obvious decisions that have already burned someone:
- Static assets are served
no-cache. Build outputs use fixed names (app.js,index.css); cache busting is via a?v=<timestamp>query injected bydeploy.sh. Never add a client-sidesetTimeoutauto-reload — it loops on slow mobile. - xterm.js native touch is disabled (
pointer-events: noneon.xterm*). A custom handler on.xterm-wrapdrives mobile scroll. Playwright's CDP touch direction is the opposite of real devices — trust real-device feedback over emulator output. - Raw stream is not applied to the client. Pipe-pane output contains escape sequences that destroy the scrollback. The client receives
writeScreen(in-place capture-pane) and a one-timewriteSnapshoton session switch. - Always launch from the project root.
start.shanddeploy.shhandle this — theycdfirst sobackend.mainresolves correctly.
Private. Not currently licensed for redistribution.