Mission control for AI coding agents
Claude Code • OpenCode • Codex • Antigravity • Gemini • Pi • Grok • DeepSeek • OMP • Terminal - One Dashboard • Any Device
English • 简体中文
Codeman is a self-hosted mission control for AI coding agents. It spawns Claude Code, OpenCode, Codex, Antigravity, Gemini, Pi, Grok, DeepSeek Harness, or OMP inside persistent tmux sessions, streams the real terminal to any browser, and keeps agents productive after you walk away: it re-prompts on idle, resumes when a usage limit resets, runs scheduled jobs, and shows every background agent working in real time.
Get started in one line (macOS & Linux, Windows via WSL):
curl -fsSL https://getcodeman.com/install | bash
codeman web
Open http://localhost:3000 and start your first session
The installer asks before every system change, and re-running the same line updates in place. Full details: Quick Start - Installation.
- One dashboard, nine CLIs - run Claude Code, OpenCode, Codex, Antigravity, Gemini, Pi, Grok, DeepSeek, or OMP per session (plus plain shell), locally, in Docker, or over SSH, with your own dashboards open as web tabs beside them
- Truly phone-friendly - a touch-optimized terminal with instant local echo, QR login, swipe navigation, and push notifications
- Runs while you sleep - idle detection + respawn cycling and auto-resume when a subscription limit resets, for 24+ hour unattended runs
- See your agents think - live floating windows for every subagent and teammate, with real-time transcripts
- Nothing gets lost - tmux persistence across restarts and network drops, exactly-once input delivery, full-scrollback replay
- Self-hosted and private - loopback-only by default, MIT licensed, no telemetry, runs entirely on your machine
Quick Start - Installation
curl -fsSL https://getcodeman.com/install | bash
This installs Node.js, tmux and a build toolchain if missing (node-pty ships no Linux prebuilds, so it compiles from source), clones Codeman to ~/.codeman/app, and builds it. It looks at what is already on the machine, asks at most three questions, then does all the work unattended and ends on the URL with a QR code for your phone. A few things worth knowing:
- Three questions, all up front. How the dashboard is reached, optionally what to call this machine on your tailnet, and whether to run Codeman as a background service (systemd/launchd, auto-start on boot; Enter says yes). Everything that needs you, including one consent for all missing packages, one sudo password, and the Tailscale login, happens before the build, so you can walk away while it compiles.
- How it's reachable, your choice. Tailscale (loopback bind fronted by
tailscale serve, so you gethttps://with a real certificate and your tailnet as the login, no password needed), any device on your network (. .ts.net 0.0.0.0, with a strongly recommended password prompt), or this machine only (127.0.0.1, safest). Skipping the password on a network bind requires an explicit confirmation and ends with a loud warning. The highlighted default reflects what is already on the machine (Tailscale when it is already connected, your existing binding on a re-run), and a bare Enter never pulls in new software. If another app already owns:443on your node, Codeman goes underhttps://or on a second port instead of replacing it. A bare. .ts.net/codeman codeman webstarted by hand still defaults to loopback. - The name is yours to choose. By default the URL uses the machine's existing tailnet name. Answering yes to the second question renames the machine to
codeman-(which also renames it for SSH, so the default is no);install.sh namedoes it later. - Re-run to update. The same one-liner updates a finished install in place: local changes in
~/.codeman/appare stashed (never discarded), and a running service is restarted and verified. If a first install was interrupted, re-running resumes the full setup instead.install.sh statusprints the URLs and the QR code again;install.sh update,install.sh tailscaleandinstall.sh uninstallalso exist. - Flags for the impatient.
curl -fsSL https://getcodeman.com/install | bash -s -- --tailscale --serviceanswers the questions from the command line (--lan,--local,--run,--no-start,--name,--port,--yestoo). CI / headless: without a terminal attached, steps that would change your system abort with instructions instead of running silently; setCODEMAN_NONINTERACTIVE=1to approve them for automation.
codeman web
Open http://localhost:3000 and start your first session
Sharing with a small team? Start it in multi-user mode instead: each person gets their own login and workspace.
codeman users add alice --admin # create the first admin account
codeman web --multiuser # named logins + per-user case spaces
Prefer Docker Compose? A local-image Compose deployment ships in docker/: copy docker/.env.example to docker/.env, set CODEMAN_PASSWORD, then run bash docker/Start-Codeman.sh on Linux. Codeman runs in a container and spawns Docker cases as sibling containers through the host socket. After updating, run the script again rather than a plain docker compose up, so the rebuilt image, refreshed volumes and entrypoint arrive together. See the Docker deployment guide for direct Compose commands, storage and networking options.
Details in Multi-User Mode below.
Keep it running in the background
To outlive the shell you started it in, without setting anything up:
codeman web -d # detach; logs to ~/.codeman/web.log
codeman web --status # is it up, and on which pid
codeman web --stop # graceful SIGTERM; agents keep running in tmux
-d waits until the server actually answers before reporting success, and refuses to start a second one on the same data dir (two servers sharing a tmux socket attach to each other's sessions).
To have it come back after a reboot, install it as a service instead. The installer's final menu does this for you (option 2); codeman service is the equivalent for an npm i -g aicodeman install:
codeman service install # systemd user unit (Linux) or LaunchAgent (macOS)
codeman service status
codeman service uninstall
service install writes the unit with your current PATH baked in, which matters more than it sounds: launchd hands a job /usr/bin:/bin:/usr/sbin:/sbin, so a Homebrew or nvm node, tmux or claude is invisible to a hand-written plist. It never copies CODEMAN_PASSWORD into the unit file; add that yourself if the service needs auth.
To write the unit by hand instead:
Linux (systemd):
mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/codeman-web.service << EOF
[Unit]
Description=Codeman Web Server
After=network.target
[Service]
Type=simple
ExecStart=$(which node) $HOME/.codeman/app/dist/index.js web
Restart=always
RestartSec=10
[Install]
WantedBy=default.target
EOF
systemctl --user daemon-reload
systemctl --user enable --now codeman-web
loginctl enable-linger $USER
macOS (launchd):
mkdir -p ~/Library/LaunchAgents
cat > ~/Library/LaunchAgents/com.codeman.web.plist << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.codeman.web</string>
<key>ProgramArguments</key>
<array>
<string>$(which node)</string>
<string>$HOME/.codeman/app/dist/index.js</string>
<string>web</string>
</array>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
<key>StandardOutPath</key>
<string>/tmp/codeman.log</string>
<key>StandardErrorPath</key>
<string>/tmp/codeman.log</string>
</dict>
</plist>
EOF
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.codeman.web.plist
Windows (WSL)
wsl bash -c "curl -fsSL https://getcodeman.com/install | bash"
Codeman requires tmux, so Windows users need WSL. If you don't have WSL yet: run wsl --install in an admin PowerShell, reboot, open Ubuntu, then install your preferred AI coding CLI inside WSL (Claude Code, OpenCode, Codex, Antigravity, Gemini CLI, Pi, Grok Build, DeepSeek Harness, or OMP). After installing, http://localhost:3000 is accessible from your Windows browser.
Mobile-Optimized Web UI
The most responsive AI coding agent experience on any phone. Full xterm.js terminal with local echo, swipe navigation, and a touch-optimized interface designed for real remote work — not a desktop UI crammed onto a small screen.
![]() |
![]() |
| Answering prompts by touch | Accessory bar + dedicated Enter button |
| Terminal Apps | Codeman Mobile |
|---|---|
| 200-300ms input lag over remote | Local echo — instant feedback |
| Tiny text, no context | Full xterm.js terminal |
| No session management | Swipe between sessions |
| No notifications | Push alerts for approvals and idle |
| Manual reconnect | tmux persistence |
| No agent visibility | Background agents in real-time |
| Copy-paste slash commands | One-tap /init, /clear, /compact |
| Password typing on phone | QR code scan — instant auth |
- Keyboard accessory bar —
/init,/clear,/compactquick-action buttons above the virtual keyboard; destructive commands require a double-press to confirm, so you never fire one by accident; on Codex sessions the bar also shows⇧←/⇧→(Shift+Left / Shift+Right: edit the last queued message / return through the prompt stack) - Dedicated Enter button — replays the keypress through the terminal, so text buffered by local echo is flushed first rather than stranded
- Swipe navigation & smart keyboard handling — swipe left/right to switch sessions; toolbar and terminal shift up when the keyboard opens (
visualViewportAPI) - Built for phones — safe-area insets for notch and home indicator, 44px touch targets, bottom-sheet case picker, native momentum scrolling; on a folding phone (iPhone Duo) dialogs stay clear of the hinge, and opening or closing the device is never mistaken for the keyboard
codeman web --https
Open on your phone: https://<your-ip>:3000
localhostworks over plain HTTP. Use--httpswhen accessing from another device, or use Tailscale (recommended): the installer can set it up for you (choose Tailscale at the network-access prompt, or runbash ~/.codeman/app/install.sh tailscaleon an existing install). That gives youhttps://with a real certificate: private to your tailnet, no password required, and PWA install + push notifications work on your phone. The installer ends on that URL with a QR code to scan, and. .ts.net bash ~/.codeman/app/install.sh statusprints it again any time.
Secure QR Code Authentication
Typing passwords on a phone keyboard is miserable. Codeman replaces it with cryptographically secure single-use QR tokens — scan the code displayed on your desktop and your phone is authenticated instantly.
Each QR encodes a URL containing a 6-character short code that maps to a 256-bit secret (crypto.randomBytes(32)) on the server. Tokens auto-rotate every 60 seconds, are atomically consumed on first scan (replays always fail), and use hash-based Map.get() lookup that leaks nothing through response timing. The short code is an opaque pointer — the real secret never appears in browser history, Referer headers, or Cloudflare edge logs.
The security design addresses all 6 critical QR auth flaws identified in "Demystifying the (In)Security of QR Code-based Login" (USENIX Security 2025, which found 47 of the top-100 websites vulnerable): single-use enforcement, short TTL, cryptographic randomness, server-side generation, real-time desktop notification on scan (QRLjacking detection), and IP + User-Agent session binding with manual revocation. Dual-layer rate limiting (per-IP + global) makes brute force infeasible across 62^6 = 56.8 billion possible codes. Full security analysis: docs/qr-auth-plan.md
Using Codeman — A Human's Guide
A start-to-finish walkthrough for driving Codeman from the browser. If you just installed, this is where to begin.
1. Launch the server
codeman web # localhost:3000 (loopback only — safe default)
codeman web --port 8080 # custom port (or set CODEMAN_PORT)
codeman web --https # self-signed TLS (only needed for remote access)
codeman web -H 0.0.0.0 # bind LAN — REQUIRES CODEMAN_PASSWORD (see Security)
codeman web -d # detach: survives closing the shell (--status, --stop)
codeman service install # systemd/launchd service: comes back after reboots
Open the printed URL. The page is a single dashboard; everything below happens there.
2. Create your first session
Click + New Session (or Quick Start). A session is one AI CLI running in its own tmux-backed terminal. You choose:
| Field | What it does |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| Working directory / case | The folder the agent operates in. A "case" is just a named working dir Codeman remembers. Add Case creates one from scratch, links an existing folder, or clones a GitHub repo straight into one (Clone Repo). |
| CLI / run mode | Claude (default), OpenCode, Codex, Antigravity, Gemini, Pi, Grok, DeepSeek, OMP, or Terminal (plain shell). |
| Model | Per-session model (App Settings → Models → New Claude sessions). A soft default — /model still works in-session. |
| Effort / Ultracode | Reasoning effort (low–max) or ultracode for dynamic multi-agent workflows. Switchable anytime with /effort. |
Hit start — Codeman spawns the CLI via a real PTY and streams it to your browser over SSE.
3. Read the dashboard
- Tabs (top) — one per session.
Alt+1-9to jump,Ctrl+Tabfor next, drag to reorder (tab order syncs across your devices). Prefer a list? App Settings → Appearance → Tabs moves it into a left sidebar with a filter box (Alt+Bcollapses it) or a vertical rail whose rows sort by activity: blocked on you first, then longest running, then most recently quiet. - Terminal (center) — a real
xterm.jsterminal; full TUIs render correctly. Type directly and press Enter to send.Shift+Enterinserts a newline. - Side panels — Respawn, Orchestrator, Cron, Subagents, Settings (toggled from the toolbar).
4. Talk to the agent
- Type prompts straight into the terminal — input is delivered exactly-once even across reconnects (a dropped link never loses or double-sends a prompt).
- Paste or drag-and-drop images directly into the session.
- Voice input —
Ctrl+Shift+V(Deepgram Nova-3, or this machine's Claude Code login with no API key; auto-silence stop). - Attachments — register external files/docs and preview Office/PDF inline; any file path an agent prints is clickable, in the terminal and in the chat view.
- When it needs you — the tab turns yellow (waiting for input) or red (a question is blocking). The Approvals Inbox _(opt-in)_ queues every pending prompt across sessions, answerable from the header bell or the phone home screen, and 🧠 Read My Mind _(opt-in)_ drafts your next prompt from the case's goals and recent work.
- Copy what you see —
Shift+dragselects text even while the CLI owns the mouse, right-click copies it, and Auto Copy _(opt-in)_ copies a selection the moment you release it.
5. Make it autonomous
| Mode | Use it for | Where |
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| Respawn | Long unattended runs — auto-restarts the CLI on idle/limit, with adaptive timing. Presets: solo-work, overnight-autonomous, … | Respawn tab |
| Orchestrator | Turn one goal into a phased plan and drive it to completion across agents. | Orchestrator panel |
| Cron | Saved, named jobs on a schedule (once/interval/daily/weekly) that spawn a session and send a prompt when due. | ⏰ Cron button _(opt-in: App Settings → Header & Panels → Scheduling)_ |
| Auto-resume | Automatically continue after a subscription rate-limit resets. | Respawn tab (top) |
6. Reach it from anywhere
- Phone/tablet — the UI is fully touch-optimized; scan the desktop QR code to log in without typing a password.
- Outside your network —
./scripts/tunnel.sh startopens a Cloudflare tunnel (setCODEMAN_PASSWORDfirst). - SSH —
codeman tuiis a full-screen dashboard in the terminal (codeman tui --listto list,codeman tui 2to attach straight to one).
7. Operate & maintain
- App Settings — model, effort, permission startup mode, theme/skin, terminal font family and weight, entrance animations, notifications, display toggles, per-CLI options, a synced custom display name, and per-device English/Simplified Chinese UI language.
- Run it in the background —
codeman web -ddetaches from your shell (--status,--stop);codeman service installmakes it a systemd user unit / macOS LaunchAgent that survives reboots. Both verify the server actually answers before reporting success, and both refuse to start a second server on one data dir. See Keep it running in the background. - Self-update — git-clone installs update in place from App Settings → System → Updates.
- Deploy your own changes — see Development.
⚠️ Safety: if you're working _inside_ a Codeman-managed session (echo $CODEMAN_MUX→1), never runtmux kill-session/pkill claudedirectly — use the web UI or./scripts/tmux-manager.sh.
Zero-Lag Input Overlay
When accessing your coding agent remotely (VPN, Tailscale, SSH tunnel), every keystroke normally takes 200-300ms to round-trip. Codeman implements a Mosh-inspired local echo system that makes typing feel instant regardless of latency.
A pixel-perfect DOM overlay inside xterm.js renders keystrokes at 0ms. Background forwarding silently sends every character to the PTY in 50ms debounced batches, so Tab completion, Ctrl+R history search, and all shell features work normally. When the server echo arrives 200-300ms later, the overlay seamlessly disappears and the real terminal text takes over — the transition is invisible.
- Ink-proof architecture — lives as a
at z-index 7 inside.xterm-screen, completely immune to Ink's constant screen redraws (two previous attempts usingterminal.write()failed because Ink corrupts injected buffer content) - Font-matched rendering — reads
fontFamily,fontSize,fontWeight, andletterSpacingfrom xterm.js computed styles so overlay text is visually indistinguishable from real terminal output - Full editing — backspace, retype, paste (multi-char), cursor tracking, multi-line wrap when input exceeds terminal width
- Persistent across reconnects — unsent input survives page reloads via localStorage
- Enabled by default — works on both desktop and mobile, during idle and busy sessions
Extracted as a standalone library: xterm-zerolag-input — see Published Packages.
Live Agent Visualization
Watch background agents work in real-time. Codeman monitors agent activity and displays each agent in a draggable floating window with animated Matrix-style connection lines back to the parent session.
- Floating terminal windows — draggable, resizable panels for each agent with a live activity log showing every tool call, file read, and progress update as it happens
- Connection lines — animated green lines linking parent sessions to their child agents, updating in real-time as agents spawn and complete
- Status & model badges — green (active), yellow (idle), blue (completed) indicators with Haiku/Sonnet/Opus model color coding
- Auto-behavior — windows auto-open on spawn, auto-minimize on completion, tab badge shows "AGENT" or "AGENTS (n)" count
- Nested agents — supports 3-level hierarchies (lead session -> teammate agents -> sub-subagents)
Agent Teams — first-class support for Claude Code's native multi-agent teams (CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1). TeamWatcher polls ~/.claude/teams/, matches teammates to their lead session, and surfaces them as live subagent windows with team-aware idle detection — so the Respawn Controller won't fire while teammates are still working. See docs/agent-teams/.
Respawn Controller
The core of autonomous work. When the agent goes idle, the Respawn Controller detects it, sends a continue prompt, cycles context management commands for fresh context, and resumes — running 24+ hours completely unattended.
WATCHING → IDLE DETECTED → SEND UPDATE → /clear → /init → CONTINUE → WATCHING
- Multi-layer idle detection — completion messages, AI-powered idle check, output silence, token stability
- Auto-resume on usage limit _(opt-in, off by default)_ — when Claude halts on a subscription limit ("You've hit your limit · resets 3pm"), Codeman parses the reset time, waits it out plus a 2-minute safety buffer, then dismisses the rate-limit dialog and sends
continue— so an overnight run survives the 5-hour window instead of stalling until morning. Recognizes every Claude Code limit-message format, retries if still limited, survives Codeman restarts, and holds respawn cycles while paused so/clearcan't wipe the waiting conversation. Enable per session at the top of the Respawn tab - Circuit breaker — prevents respawn thrashing when Claude is stuck (CLOSED -> HALF_OPEN -> OPEN states, tracks consecutive no-progress and repeated errors)
- Health scoring — 0-100 health score with component scores for cycle success, circuit breaker state, iteration progress, and stuck recovery
- Built-in presets —
solo-work(3s idle, 60min),subagent-workflow(45s, 240min),team-lead(90s, 480min),ralph-todo(8s, 480min),overnight-autonomous(10s, 480min)
Orchestrator Loop
Beyond single-session respawn, the Orchestrator turns a high-level goal into a phased plan and drives it to completion across multiple agents — a state machine that runs idle → planning → approval → executing → verifying → (replanning) → completed.
- Plan, then execute — generates a phased plan from your goal and pauses for approval before touching anything; reject with feedback to regenerate
- Per-phase verification gates — each phase is verified before the next begins; on failure the orchestrator replans instead of barreling ahead
- Multi-agent execution — fans phases out to team agents / a task queue, coordinating work too big for one session
- Crash-safe — full state persists under the
orchestratorkey instate.json, so it survives restarts - Driven from the UI or API — the Orchestrator panel, or
POST /api/orchestrator/start→/approve→/status(10 endpoints)
Full design: docs/orchestrator-loop-architecture.md.
Multi-Session Dashboard
Run 20 parallel sessions with full visibility — real-time xterm.js terminals at 60fps, per-session token and cost tracking, tab-based navigation, and one-click management.
Persistent Sessions
Every session runs inside tmux — sessions survive server restarts, network drops, and machine sleep. Auto-recovery on startup with dual redundancy. Ghost session discovery finds orphaned tmux sessions. Managed sessions are environment-tagged so the agent won't kill its own session.
Session Manager & Command Palette
Ctrl/Cmd/Alt+K opens a fuzzy session palette; Browse all sessions opens the Session Manager: one deduped list of everything Codeman knows about (live sessions, past sessions from state and lifecycle history, and Claude transcripts), each row showing its first and most recent prompt.
- Pinning: pin a session to float it to the top of the list. Pinned sessions even survive kill (they demote to a lightweight stopped entry that stays visible and resumable).
- Name retention: resuming a past session keeps its original name instead of minting a new one.
- Cross-device tab order: drag-reordered tabs persist server-side, so your ordering follows you from desktop to phone.
Hostname-Aware Window Title
Running Codeman on multiple hosts (laptop, dev box, NAS)? The browser tab title is codeman: so you can tell which backend each tab points at without clicking in:
codeman web # codeman:<os.hostname()>
codeman web --title-hostname dev-box # codeman:dev-box (manual override for noisy hostnames)
The title is templated into the served HTML on first byte, so it's correct from the very first paint and works without JavaScript. The same hostname prefix is applied to the tab-flash format (⚠️ (N) codeman:) and to OS-level desktop notifications (codeman:), so cross-host alerts in the system notification center are also unambiguous.
Smart Token Management
| Threshold | Action | Result |
| --------------- | --------------- | ---------------------------------- |
| 110k tokens | Auto /compact | Context summarized, work continues |
| 140k tokens | Auto /clear | Fresh start with /init |
Tab Alerts
Every tab tells you its state at a glance. A running session keeps its green status dot. When a session stops and waits for input, its tab turns yellow: steady ring, tinted background, yellow dot, with a slow breathing glow on top. When a permission prompt or question is blocking the agent, the tab turns red with a faster pulse. The base tint never blinks off, so even a split-second glance (or a screenshot) reads the true state; the ring stays visible while the tab is selected, and a page reload re-arms pending alerts from the server, so a blocked session can never hide behind a fresh-looking tab.
Notifications
Real-time desktop alerts when sessions need attention — permission_prompt and elicitation_dialog trigger critical red tab blinks, idle_prompt triggers yellow blinks. Click any notification to jump directly to the affected session. Hooks auto-configured per case directory.
Run Summary
Click the chart icon on any session tab to see a timeline of everything that happened — respawn cycles, token milestones, auto-compact triggers, idle/working transitions, hook events, errors, and more.
Zero-Flicker Terminal
Terminal-based AI agents (Claude Code's Ink, OpenCode's Bubble Tea) redraw the screen on every state change. Codeman implements a 6-layer anti-flicker pipeline for smooth 60fps output across all sessions:
PTY Output → 16ms Server Batch → DEC 2026 Wrap → SSE → Client rAF → xterm.js (60fps)
More Features
- Background daemon & service install —
codeman web -druns the server detached with a pidfile,~/.codeman/web.log, and verified startup (it polls the server until it answers, so a port clash never reads as success);codeman service installwrites a systemd user unit (Linux) or LaunchAgent (macOS) with your shell's PATH baked in, so an nvm or Homebrewnode,tmuxandclaudeare actually found. Secrets are never written into unit files - Self-update — git-clone installs under systemd/launchd update in place from App Settings → System → Updates: it detects the latest release, auto-stashes a dirty tree, and streams build progress across the service restart (npm installs report as non-updatable)
- Clone a GitHub repo as a case — paste a repository URL into Add Case → Clone Repo and Codeman clones it into
~/codeman-cases/and registers it as a normal case, ready to run an agent in. It preflights the URL while you type (tells you whether it can be cloned anonymously and offers the repo's real branches and tags for the optional branch/tag field), fills the case name in from the URL, and lets you pick which CLI the Run button should use. Public repositories overhttps://; Codeman never collects or stores credentials - Multi-CLI — run Claude Code, OpenCode, Codex, Antigravity, Gemini, Pi, Grok, DeepSeek Harness, or OMP per session; env-var prefixes auto-gate (
CLAUDE_CODE_vsOPENCODE_vsCODEX_vsANTIGRAVITY_vsGEMINI_/GOOGLE_vsPI_vsGROK_/XAI_vsDSH_/DEEPSEEK_vsOMP_). Seedocs/opencode-integration.md,docs/pi-integration.md,docs/grok-integration.md,docs/deepseek-integration.mdanddocs/omp-integration.md - Custom model endpoints _(new in 1.29.0, HTTP API for now)_ — point a session's CLI at any OpenAI-compatible endpoint instead of its native backend: a local llama.cpp, llama-swap, Ollama or vLLM box, or a cloud gateway such as Azure AI Foundry or OpenRouter. Save an endpoint once (
POST /api/model-endpoints; its models are discovered from/v1/models), apply it to a session (POST /api/sessions/:id/custom-model), and the CLI restarts in place on that endpoint. Verified live for Claude, OpenCode, Pi, Grok and OMP; Codex, Gemini and DeepSeek have documented gaps, Antigravity has no mechanism. A toolbar picker is the follow-up. Seedocs/custom-model-endpoints.md - Web tabs — open Grafana, Uptime Kuma, a Vite dev server or any dashboard URL as a tab beside your sessions (Run dropdown → Web / URL → Add URL). Dashboards are proxied through Codeman's own origin, so an
http://target works from a phone over HTTPS and through the tunnel, single-page apps route on their own paths, and a frame that reloads recovers itself. Alocalhostlink an agent prints opens as a web tab automatically. Seedocs/web-tabs.md - Docker sessions — run a case inside an isolated, hardened container. One checkbox on Create New spins up a container with sensible defaults and starts the agent inside it; multiple sessions share one per-case container, or attach a case to a container you already run; export a container + its workspace to a portable
.tar.gzto move it to another machine. Seedocs/docker-cases.md - Remote SSH sessions — point a case at another machine and run the agent there inside a durable remote tmux: survives SSH drops, auto-reconnects, and can discover + attach sessions already running on the host; file previews and downloads come over the same ssh connection. See
docs/remote-sessions.md - Effort & Ultracode — set a per-session default effort (
low–max) or enable ultracode (dynamic multi-agent workflows). Soft defaults only — switchable anytime with/effortin-session. Extended-thinking budget is configurable too - Voice input — dictate prompts with Deepgram Nova-3, or through this machine's Claude Code login with no API key at all (App Settings → Voice; Web Speech API fallback): toggle recording, auto-silence stop, live level meter (
Ctrl+Shift+V) - Image input — paste or drag-and-drop images straight into a session
- Gesture control _(opt-in)_ — a MediaPipe hand-tracking overlay to grab/drag session windows and pinch buttons, hands-free. Enable with
CODEMAN_GESTURE=1+ App Settings → Terminal & Input - Multi-monitor span _(macOS)_ — one click opens a browser window maximized across all displays, so floating agent/gesture panels can cross the physical seam
- File Viewer button _(opt-in)_ — a header button that toggles the built-in file browser panel with one tap; enable under App Settings → Header & Panels → Header buttons
- CJK / IME input — full composition support for Chinese / Japanese / Korean, with Ctrl- and Alt-modified navigation keys passed through to the CLI
- Plan usage in the header — live Claude subscription usage (the 5-hour and weekly windows) from a statusline exporter Codeman hands to
claudeat spawn and never writes into your settings files, plus Codex limits from its own app-server; per device, on for desktops and off for phones - Session list, your way — the header strip, a left sidebar with a filter box, or a vertical rail whose detailed rows carry created and state stamps and sort by activity; the phone home screen and the desktop home rail use the same order
- Terminal looks — seven skins, four of them light, per-device font family and weight (the bundled JetBrains Mono covers weights 100 to 800), and opt-in entrance animations for tabs, agent windows, the terminal pane and connection lines
- OS notifications & hostname-aware titles — desktop alerts and tab titles are prefixed
codeman:so multi-host setups stay unambiguous
Isolated Docker Sessions
Run a case inside its own hardened Docker container instead of directly on your host — for security isolation, reproducible toolchains, and one-click portability.
- One click — on New Case → Create New, tick 🐳 Run in an isolated Docker container. Codeman creates the case folder, spins up a container with default settings, and starts the agent inside it. No host/image/network fields to fill in.
- Resource templates — expand the checkbox for a Small / Medium / Large / GPU preset (memory, CPUs, GPU), or set your own. Disk is elastic — storage grows as data flows in, no fixed cap.
- Shared per-case container — many sessions can
docker execinto the same container; killing one session never tears the container out from under the others. - Hardened by default — non-root,
--cap-drop ALL,no-new-privileges, PID/memory caps, never--privilegedor the docker socket; a sealed profile (no host credentials, network off) is one toggle away. - Seamless auth, isolated credentials — your host Claude / Codex / Antigravity / Gemini / OpenCode / Pi / Grok / OMP logins work inside the container out of the box: credentials are seeded (copied) in at launch and onboarding/trust prompts are pre-answered, so no login wizard appears. The container keeps its own copies and never writes back to your host credential stores; only conversation transcripts are shared, and exports never capture secrets.
- Attach to a container you already run — tick Attach to an existing container on the Docker panel to link a case to it instead of creating one. Codeman only
execs into it and never starts, stops, restarts or removes it; one adopted container can back several cases at different directories, and copy an existing case pre-fills the form from a sibling. Admin-only in multi-user mode, since the container's mounts belong to whoever started it. - Move it to another machine — export a container's whole environment (toolchain + workspace) to a portable
.tar.gz,docker loadit on the other side, and import it into a fresh case. - Durable — reconnect after a restart lands back in the same live agent; a container stop/reboot resumes the conversation from the bind-mounted transcript.
node scripts/build-agent-image.mjs). Full guide: docs/docker-cases.md.
Remote SSH Sessions
Point a case at another machine and run the agent there, over SSH, with the same dashboard, mobile UI, and autonomy features. Your laptop is just a window onto a session that lives on the remote host.
- Durable by design: the agent runs inside a dedicated tmux session on the remote host, so a dropped SSH connection, network change, or laptop sleep never kills the run. Reconnecting lands back in the same live conversation.
- Auto-reconnect: a bounded-backoff watcher notices a dead SSH pane and silently reattaches to the still-running remote session (kill-switch in settings; intentional kills are never revived).
- Discover & attach: list the
codeman-*sessions already running on a host (started by that machine's own Codeman, or by another operator) and attach to one. Attached sessions you don't own detach on tab close, never kill. - Shared sessions: several clients can attach the same remote session at different window sizes without clamping each other; discovery shows a "shared" badge with the client count.
- Injection-safe: every ssh command line flows through a single shell-escaping builder, and host/path/identity fields are schema-guarded.
- Files too: previews, downloads and text reads in a remote case go over the same ssh connection (one
realpath+statprobe, then a streamedcat,Rangeseeking included), so a clicked path opens the file on the machine the agent is on. Nothing is copied to the Codeman host; editing and Office previews answer a clear 400 instead of a misleading 404.
docs/remote-sessions.md.
Multi-User Mode (opt-in)
Share one Codeman with a small trusted team, each person getting their own login and workspace. Off by default — without the flag, nothing changes.
Enable with codeman web --multiuser (or CODEMAN_MULTIUSER=1). Create the first admin, then manage users from the CLI or the Users tab in App Settings:
codeman users add alice --admin # prompts for a password (or --password-stdin)
codeman users add bob # a regular user
codeman users list
- Per-user spaces — each user's cases live under
~/codeman-users/; sessions, cases, search, and real-time events are scoped to their owner. Admins see everything./cases - Individually revocable logins — named users with scrypt-hashed passwords in
~/.codeman/users.json; disable, reset (one-time password), or delete an account at any time. Admin actions are audited to~/.codeman/admin-audit.jsonl. - Safer defaults for regular users — non-admins run Claude in
--permission-mode auto(Anthropic's classifier-guarded mode); raw shell sessions, cronlaunchCommand, and skip-permissions require an explicit per-user grant.
⚠️ This separates workspaces; it does not sandbox users from each other. Every session runs as the same OS account, so a determined user's agent can still reach another user's files. For real isolation, pair users with Docker cases or run separate instances under separate OS accounts. Seedocs/multi-user-plan.mdand the multi-user section ofdocs/security-architecture.md.
Remote Access — Cloudflare Tunnel
Access Codeman from your phone or any device outside your local network using a free Cloudflare quick tunnel — no port forwarding, no DNS, no static IP required.
Browser (phone/tablet) → Cloudflare Edge (HTTPS) → cloudflared → localhost:3000
Prerequisites: Install cloudflared and set CODEMAN_PASSWORD in your environment.
# Quick start
./scripts/tunnel.sh start # Start tunnel, prints public URL
./scripts/tunnel.sh url # Show current URL
./scripts/tunnel.sh stop # Stop tunnel
./scripts/tunnel.sh status # Service status + URL
The script auto-installs a systemd user service on first run. The tunnel URL is a randomly generated *.trycloudflare.com address that changes each time the tunnel restarts.
Persistent tunnel (survives reboots)
# Enable as a persistent service
systemctl --user enable codeman-tunnel
loginctl enable-linger $USER
Or via the Codeman web UI: App Settings → System → Remote access → Cloudflare Tunnel
Authentication
- First request → browser shows Basic Auth prompt (username:
adminorCODEMAN_USERNAME) - On success → server issues a
codeman_sessioncookie (24h TTL, auto-extends on activity) - Subsequent requests authenticate silently via cookie
- 10 failed attempts per IP → 429 rate limit (15-minute decay)
CODEMAN_PASSWORD before exposing via tunnel — without it, anyone with the URL has full access to your sessions.
QR Code Authentication
Typing a password on a phone keyboard is terrible. Codeman solves this with ephemeral single-use QR tokens — scan the code on your desktop, and your phone is instantly authenticated. No password prompt, no typing, no clipboard.
Desktop displays QR → Phone scans → GET /q/Xk9mQ3 → Server validates
→ Token atomically consumed (single-use) → Session cookie issued → 302 to /
→ Desktop notified: "Device authenticated via QR" → New QR auto-generated
Someone who only has the bare tunnel URL (without the QR) still hits the standard password prompt. The QR is the fast path; the password is the fallback.
How It Works
The server maintains a rotating pool of short-lived, single-use tokens. Each token consists of a 256-bit secret (crypto.randomBytes(32)) paired with a 6-character base62 short code used as an opaque lookup key in the URL path. The QR code encodes a URL like https://abc-xyz.trycloudflare.com/q/Xk9mQ3 — the short code is a pointer, not the secret itself, so it never leaks through browser history, Referer headers, or Cloudflare edge logs.
Every 60 seconds, the server automatically rotates to a fresh token. The previous token remains valid for a 90-second grace period to handle the race where you scan right as rotation happens — after that, it's dead. Each token is single-use: the moment a phone successfully scans it, the token is atomically consumed and a new one is immediately generated for the desktop display.
Security Design
The design is informed by "Demystifying the (In)Security of QR Code-based Login" (USENIX Security 2025), which found 47 of the top-100 websites vulnerable to QR auth attacks due to 6 critical design flaws across 42 CVEs. Codeman addresses all six:
| USENIX Flaw | Mitigation | | ------------------------------------------ | ------------------------------------------------------------
... (README truncated for length)

