About Tango
Tango is an MCP server in the Other category.
Install
git clone https://github.com/heyadam/tangoThis server has no ConduID identity, so agent calls to it are not receipted. Pin the version you install and review the source before granting it credentials.
Ask AI
Ask AI about Tango
Powered by Claude · Grounded in docs
Security checks
- ✓README presentThe repository ships documentation.
5 checks have not been run yet.
README
tango
A split-pane web app for collaborating with terminal-based coding agents. The left pane is an Excalidraw canvas (and other UI surfaces, over time); the right pane is a real interactive terminal running claude --dangerously-skip-permissions in your chosen workspace. An optional further-right sidebar mirrors a booted iOS Simulator via serve-sim for tight feedback while building mobile UI. An in-process MCP server gives Claude tools to read and write the canvas, and a small gpt-5.5 controller agent in the toolbar can drive the visible UI on your behalf — moving the cursor, clicking buttons, and dispatching work to terminal-Claude.
The repo is tango itself. The directory tango operates on (where Claude's shell runs, where snapshots get written) is a separate workspace you pick from the in-app picker on first launch.
Stack
- Next.js 16 (App Router) on a custom Node server —
next devis not used; the WebSocket bridge and MCP transport live in-process. - React 19 + Tailwind v4 + a shadcn-style primitive layer in src/components/ui/.
- node-pty for the terminal, bridged over
/ws/terminal. - Excalidraw for the canvas, bridged over
/ws/canvas. @modelcontextprotocol/sdkin-process MCP server at/mcp, exposing canvas tools and agent UI tools.- Vercel AI SDK v6 +
@ai-sdk/mcpcontroller agent at/api/agent, driving anAgentCursorOverlayover/ws/agent-cursor.
Getting started
Prereqs: Node 20+, a working C/C++ toolchain for node-pty's prebuilds, and an OPENAI_API_KEY in .env.local if you want to use the controller agent.
npm install # postinstall fixes node-pty perms + symlinks .env.local
npm run dev # tsx server.ts on :3000
Open http://localhost:3000. On first launch a blocking dialog asks you to pick a workspace directory — pick (or create) the folder you want Claude to operate in. After that the right pane spawns a terminal there and runs claude.
Other scripts:
npm run build # next build (server stays the same)
npm start # production server
npm test # vitest run
npm run test:watch
If a fresh clone errors with posix_spawnp failed, run node scripts/fix-node-pty.js (the postinstall hook should already handle this).
How it works
browser ──HTTP──► Next request handler ┐
browser ──HTTP──► /mcp StreamableHTTPServerTransport │
browser ──HTTP──► /api/agent streamText + @ai-sdk/mcp client │── server.ts
browser ──HTTP──► /api/sim/status → getSimStatus() │
browser ──WS────► /ws/terminal → attachPty │
browser ──WS────► /ws/canvas → attachCanvas │
browser ──WS────► /ws/agent-cursor → attachAgentCursor ┘
↓ ↓ ↓
node-pty.spawn($SHELL) scene cache McpServer + tools
cwd: WORKSPACE_DIR (canvasBridge) (canvas + agent UI tools)
auto-runs `claude`
Plus, on darwin, server boot also spawns npx serve-sim once and the right-most panel iframes its preview UI.
- Custom server (server.ts) hosts Next, three
WebSocketServers, and the MCP transport in one process. Required fornode-ptyand for the SDK's Node-typed transport — don't migrate tonext devor edge runtimes. - MCP tools (src/server/mcp.ts) split into canvas (
get_canvas_state,set_canvas_state,add_elements,clear_canvas,screenshot_canvas) and agent UI (dom_inspect,cursor_move,cursor_click,cursor_type,terminal_type). Terminal-Claude sees all of them; the controller agent sees only the agent UI subset (it's a controller, not the brain — it delegates creative work back into the terminal viaterminal_type). - Designer canvas is duplex: Excalidraw changes snapshot to the server every 500ms, and MCP tool writes broadcast back to all connected browsers as scene patches.
- Simulator sidebar (src/server/sim.ts, darwin only) mirrors a booted iOS Simulator. Server boot spawns
npx serve-sim, parses the preview URL from its stdout, and the right-most aside iframes that URL inside a sandboxed frame. Best-effort: ifxcrunor the package isn't available, the panel surfaces the error and the rest of tango is unaffected.
Workspace
Resolution order at boot (src/server/workspace.ts):
TANGO_WORKSPACEenv var — pinned, picker is read-only.~/.tango/state.json#lastWorkspace— last-picked, if it still exists.- Unset — picker blocks the UI; PTY and snapshot routes refuse work until a workspace is chosen.
Picking a workspace is non-destructive. Five things land in the chosen directory:
.claude/tango.md— generated docs about thetango-canvasMCP tools (overwritten).CLAUDE.md— a 3-line sentinel block (<!-- tango:start … -->) is managed; everything outside is preserved byte-for-byte..mcp.json— merged undermcpServers['tango-canvas']; refuses on malformed JSON..claude/settings.json— merged to addenv.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1.design-scratch/—mkdir -p. PNGs from the canvas's "Send to Claude" button land here.
You can switch workspace mid-session via the pill in the top bar; the terminal and canvas tear down and reopen against the new cwd.
Going deeper
CLAUDE.md is the canonical architecture reference — it documents the wire protocols, the subtle invariants (why terminal_type writes text and \r as separate writes, why transport.onclose must not call mcpServer.close(), why appState needs sanitizing on every JSON boundary, etc.), the design system, and the load-bearing test surfaces. Read it before changing anything in src/server/ or src/components/Terminal.tsx, SketchPanel.tsx, DesignerCanvas.tsx, or AgentCursorOverlay.tsx.
docs/test-coverage-proposal.md tracks the test gaps and a tiered plan for closing them.
README copy captured when this server was indexed; it may lag the repository. The original is authoritative.