Stop Wrestling with SSH: Claude Code in Your Browser with TailClaude
Stop Wrestling with SSH: Claude Code in Your Browser with TailClaude
What if your most productive coding session this week happened from your phone — while waiting in line for coffee?
Sounds impossible, right? We've been conditioned to believe that "real" development requires a mechanical keyboard, three monitors, and a terminal glowing with green text. The "doom coding" movement tried to break this myth, but here's the dirty secret nobody talks about: every single mobile coding setup still chains you to a terminal. SSH keys. tmux shortcuts. Mosh connections that flake when you switch from WiFi to 5G. Tiny fonts. Finger-cramping keyboard combinations. The dream of coding anywhere dies the moment you actually try it.
But what if the terminal itself was the problem?
Enter TailClaude — a radical reimagining of how developers interact with AI coding assistants. No terminal emulator. No SSH client. No configuration files scattered across .ssh/ directories. Just a URL. Open it in any browser, on any device, and you're staring at a fully-featured Claude Code interface with real-time streaming, session history, cost tracking, and touch-optimized controls that feel native on your phone.
This isn't a wrapper around SSH. This isn't a terminal in a browser tab. This is Claude Code rebuilt for the web era — powered by the iii engine and secured by your existing Tailscale network. In this deep dive, I'll show you why top developers are quietly abandoning their terminal-based workflows, how TailClaude's architecture enables features impossible in CLI-only setups, and exactly how to get running in under 60 seconds.
What is TailClaude?
TailClaude is an open-source project by Rohit Ghumare that publishes a complete Claude Code web interface to every device on your Tailscale tailnet — or the public internet via Tailscale Funnel. It's built on top of the iii engine, a modular runtime for stateful, event-driven applications.
The project's thesis is brutally simple: terminals are a legacy interface for AI coding. When Claude Code launched, it was CLI-only — powerful but trapped in a paradigm designed for 1970s mainframes. TailClaude liberates it.
The repository has gained rapid traction among developers who've experienced the pain of "doom coding" — the practice of coding from mobile devices in challenging circumstances. Pioneers like Pete Sena, Emre Isik, and Ryan Bergamini proved phone-coding was viable, but their solutions all required terminal emulation. TailClaude asks a bolder question: why emulate a terminal when you can eliminate it?
What makes TailClaude technically fascinating is its deep integration with the iii engine's primitives — state management, PubSub event bus, stream replay buffers, cron scheduling, and OpenTelemetry tracing. This isn't a simple web wrapper; it's a distributed system that happens to serve a beautiful UI. The Node.js proxy (port 3110) handles 14 distinct endpoints, from chat streaming to cost dashboards, while the iii engine (port 3111) manages the heavy lifting of state persistence and event coordination.
Key Features That Terminal Users Can Only Dream Of
Real-time SSE streaming with per-token visibility. When Claude generates a response, you don't wait for blocks of text — you see tokens appear character by character, with live counters updating (4,521 in / 892 out). Try getting that granularity from claude -p in your terminal.
Instant session history across all devices. The terminal workflow requires tmux attach from a machine with your SSH keys. TailClaude's session index lets you browse every conversation — whether started from web or terminal — with sub-millisecond queries. Double-click to rename sessions. Long-press on mobile. See relative timestamps ("2h ago", "3d ago") without parsing Unix epochs.
One-click model switching. In the terminal, changing from Opus to Sonnet means editing CLI flags and restarting. TailClaude presents a dropdown: Opus, Sonnet, Haiku. Select, send message, done. The same applies to permission modes (default, plan, acceptEdits, bypassPermissions, dontAsk) and effort levels (low, medium, high).
Live cost tracking with real pricing. Every message displays exact cost using Claude API rates: Opus at $15/$75 per million tokens, Sonnet at $3/$15, Haiku at $0.80/$4, plus cache read/write rates. The 7-day dashboard shows spending trends with CSS bar charts. Terminal users? They're flying blind.
System metrics with overload alerts. Gradient area charts track memory RSS (orange), CPU (blue), event loop lag (gray), and worker uptime (green) — all using Anthropic's brand palette. Threshold-based alerts fire when CPU exceeds 80%, memory crosses 500MB, or lag spikes past 100ms, with 5-minute cooldowns to prevent spam.
Request traces for operational visibility. Every chat request gets an OpenTelemetry span capturing model, duration, cost, tokens in/out, and exit status. Color-coded: green for success, orange for error, gray for stopped. Average duration and cost summaries help optimize spending patterns.
Touch-optimized mobile experience. Hamburger menu, responsive layout, dark theme (#141413 background, #faf9f5 light elements, #d97757 orange accent). The QR code endpoint generates an SVG you can scan instantly — no app installation, no key exchange.
Use Cases Where TailClaude Absolutely Dominates
1. Emergency Production Fixes from Anywhere
It's 2 AM. PagerDuty screams. You're at a family dinner, phone only. With traditional setups, you're frantically installing Termius, configuring SSH keys, praying tmux survived your last session. With TailClaude, you scan the QR code on your fridge (yes, really), open the URL, and Claude Code is live with your full session history. The streaming response lets you watch Claude analyze logs in real-time. You approve edits with one tap. Crisis resolved before dessert arrives.
2. Pair Programming Across Incompatible Devices
Your designer uses an iPad Pro. Your PM has a locked-down corporate laptop. Neither can install Claude Code CLI or SSH anywhere. Share your Tailscale Funnel URL with TAILCLAUDE_TOKEN protection, and suddenly they're collaborating in the same Claude sessions you see on your workstation. The web UI democratizes access without compromising security.
3. Cost-Conscious AI Development
Running Claude Code for a team? The usage dashboard reveals who's spending what. The session cost backfill parses Claude Code's native JSONL files (~/.claude/projects/) to extract real token counts and cache usage — not estimates, actual billed amounts. Spot the developer accidentally using Opus for trivial tasks. Set per-message budget caps. Optimize with data, not guesswork.
4. Network-Challenged Environments
SSH dies when you walk from office WiFi to parking lot 5G. Mosh helps but requires client installation and has rendering limitations. TailClaude's browser reconnects automatically. The SSE activity feed resumes where you left off. The stream replay buffer (GET /chat/replay/:id) lets you reconstruct interrupted conversations. It's stateful networking without the state management headaches.
5. Demo and Teaching Scenarios
Projecting your terminal is ugly. Font sizes don't scale. Colors invert on cheap projectors. TailClaude's Anthropic-branded UI looks professional in demos, with readable Markdown rendering and clear cost displays. Students or stakeholders follow along on their own devices by scanning the QR code — no setup, no accounts, immediate engagement.
Step-by-Step Installation & Setup Guide
Prerequisites before you begin:
- iii engine installed and available on your PATH
- Claude Code CLI installed and authenticated with your Anthropic account
- Tailscale installed (optional — local-only mode works fine for testing)
- Node.js 20 or newer
The 60-Second Install
# Clone the repository
git clone https://github.com/rohitg00/tailclaude.git
# Enter the project directory
cd tailclaude
# Install dependencies
npm install
# Start the iii engine with TailClaude configuration
iii -c iii-config.yaml
That's genuinely it. The engine auto-detects Tailscale, publishes to your tailnet with HTTPS, and prints a terminal QR code. Open the URL or scan from your phone.
Alternative Run Modes
If the iii engine is already running (perhaps managed by systemd or another process):
# Start only the TailClaude worker
npm run dev
For quick proxy testing without the full iii engine:
# Start just the Node.js proxy on port 3110
npx tsx -e 'import{startProxy}from"./src/proxy.ts";startProxy()'
Verification Commands
Once running, verify each component:
# Check proxy health, Tailscale URL, and session count
curl http://localhost:3110/health
# Open the chat UI in your default browser
open http://localhost:3110
# List all sessions with metadata
curl http://localhost:3110/sessions
# View 7-day cost and token usage statistics
curl http://localhost:3110/usage
# Inspect system metrics timeline with active alerts
curl http://localhost:3110/metrics
# Review request traces with cost, tokens, and model details
curl http://localhost:3110/traces
# Generate QR code SVG for mobile access
curl http://localhost:3110/qr
Tailscale Configuration
Tailscale Serve (tailnet-only access, most secure):
# Publish to your private tailnet
tailscale serve --bg --yes --https=443 http://127.0.0.1:3110
Tailscale Funnel (public internet access, requires auth token):
# Expose to any device — ideal for phone access without Tailscale app
tailscale funnel --bg --yes --https=443 http://127.0.0.1:3110
# Set authentication token to prevent unauthorized access
export TAILCLAUDE_TOKEN="your-secure-random-token"
The auto-publish logic handles edge cases: detecting existing serve listeners, retrying status checks up to 3 times, and cleanly unpublishing on shutdown via SIGINT/SIGTERM handlers.
REAL Code Examples from the Repository
Let's examine actual implementation patterns from the TailClaude codebase, with detailed explanations of how the iii engine primitives enable sophisticated functionality.
Example 1: The Complete Architecture — Understanding Data Flow
The README provides this architecture diagram as text. Here's how to read it as a developer:
+-----------------------------------------------------------------+
| Browser (any device — phone, tablet, laptop) |
| https://your-machine.tail-abc.ts.net |
+---------------------------------+-------------------------------+
| HTTPS (auto-cert via Tailscale)
v
+-----------------------------------------------------------------+
| tailscale serve/funnel :443 -> http://127.0.0.1:3110 |
+---------------------------------+-------------------------------+
|
v
+-----------------------------------------------------------------+
| Node.js Proxy (port 3110) |
| |
| GET / -> Chat UI (Anthropic brand, tabs) |
| GET /health -> Engine state + worker metrics |
| POST /chat -> OTel-traced SSE streaming chat |
| POST /chat/stop -> Kill active process + lifecycle |
| GET /chat/active -> Active streaming request IDs |
| GET /chat/replay/:id -> Replay buffered chat events |
| GET /sessions -> State-indexed sessions (sub-ms) |
| GET /sessions/:id -> Full conversation history |
| GET /activity -> SSE live activity feed |
| GET /usage -> 7-day cost & token usage stats |
| GET /metrics -> System metrics timeline + alerts |
| GET /traces -> Request traces (cost/tokens/model) |
| GET /qr -> QR code SVG |
| GET /settings -> MCP servers list |
| * -> Proxy to iii engine (port 3111) |
+---------------------------------+-------------------------------+
|
v
+-----------------------------------------------------------------+
| iii engine (port 3111) |
| |
| State -> session_index, usage_daily, traces, metrics, |
| alert_cooldowns, alerts, backfill_state, config |
| Streams -> chat event replay buffer (LRU, 100 groups max) |
| PubSub -> chat::started/completed/stopped, session::indexed, |
| cleanup::completed, alert::* |
| Cron -> */1 metrics snapshot, */5 session re-index + |
| backfill, */30 cleanup, */6h data retention |
| OTel -> distributed tracing on every chat request |
| Logger -> structured logging with trace correlation |
| Event: engine::started -> auto-publish to Tailscale + QR |
| Signal: SIGINT/SIGTERM -> unpublish Tailscale + clean exit |
+---------------------------------+-------------------------------+
|
v
+-----------------------------------------------------------------+
| claude -p --output-format stream-json --verbose |
| (Claude Code CLI — works with Pro/Max plans) |
+-----------------------------------------------------------------+
What's happening here: This isn't a simple proxy — it's a multi-tier distributed system. The browser connects via HTTPS (auto-certified by Tailscale's MagicDNS). The Node.js proxy handles 14 distinct endpoints, each with specific responsibilities. The POST /chat endpoint is particularly sophisticated: it spawns the Claude CLI as a child process, wraps execution in an OpenTelemetry span, streams JSON events through the iii engine's stream buffer for replay capability, and publishes lifecycle events via PubSub so multiple subscribers can react independently.
The iii engine's modular design lets TailClaude compose primitives: State for persistence, Streams for replay, PubSub for decoupled notifications, Cron for maintenance, OTel for observability. This separation of concerns means the proxy stays lightweight while the engine handles complexity.
Example 2: iii Engine Configuration
The iii-config.yaml demonstrates how to configure a production-ready iii deployment:
# iii-config.yaml — enables all modules TailClaude needs
# 180-second timeout accommodates long Claude Code generations
modules:
state:
type: kv
backend: file
path: ./data/state_store.db
# 8 scopes isolate different data domains
scopes:
- session_index # Fast session lookups
- usage_daily # Cost aggregation
- traces # OTel trace storage
- metrics_timeline # Time-series system data
- alerts # Active alert states
- alert_cooldowns # Deduplication timing
- active_chats # Currently running sessions
- backfill_state # Cost backfill progress
streams:
type: memory
max_groups: 100 # LRU eviction prevents memory bloat
ttl: 1800 # 30-minute TTL for replay buffers
pubsub:
type: local # In-process; use redis for multi-node
topics:
- chat::started
- chat::completed
- chat::stopped
- session::indexed
- cleanup::completed
- alert::cpu_overload
- alert::memory_overload
- alert::lag_overload
cron:
type: kv # Cron state persists across restarts
jobs:
- name: metrics_snapshot
schedule: "*/1 * * * *" # Every minute
handler: metrics.collect
- name: session_reindex
schedule: "*/5 * * * *" # Every 5 minutes
handler: sessions.reindex
- name: cost_backfill
schedule: "*/5 * * * *" # Parallel with reindex
handler: session_costs.backfill
- name: cleanup
schedule: "*/30 * * * *" # Every 30 minutes
handler: cleanup.run
- name: data_retention
schedule: "0 */6 * * *" # Every 6 hours
handler: traces.purge_old
otel:
type: memory # Traces stored in State for dashboard queries
sample_rate: 1.0 # Capture all chat requests
shell:
type: exec
watch: src/**/*.ts # Auto-restart worker on file changes
command: npx tsx src/index.ts
Key insight: The 180-second timeout on REST API calls isn't arbitrary — it matches Claude Code's maximum generation time. The stream TTL (30 minutes) balances replay capability against memory pressure. Cron scheduling is dense but efficient: metrics every minute for responsive dashboards, session reindexing every 5 minutes with cost backfill (parsing JSONL files is I/O-bound, so parallel execution makes sense), cleanup every 30 minutes, and data retention every 6 hours to control storage growth.
Example 3: Chat API Request Body
The POST /chat endpoint accepts this structured request:
{
"message": "Refactor this React component to use useMemo for expensive calculations",
"model": "opus",
"mode": "acceptEdits",
"effort": "high",
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
"maxBudget": 2.50,
"systemPrompt": "You are an expert React performance engineer. Always explain the optimization strategy before implementing."
}
How this works in practice: The model field maps directly to Claude API model identifiers — opus, sonnet, haiku — with validation against available models. The mode controls Claude Code's permission behavior: default prompts for each tool use, plan shows the plan without executing, acceptEdits auto-approves file modifications, bypassPermissions skips all confirmation (dangerous but fast), dontAsk is most permissive. The sessionId enables conversation continuity — omit it to start fresh. maxBudget kills the process if projected cost exceeds the threshold (protecting against runaway Opus usage). The systemPrompt appends to Claude's default instructions, useful for domain-specific expertise.
Example 4: Project Structure — Modular TypeScript Architecture
tailclaude/
├── iii-config.yaml # iii engine configuration (180s timeout)
├── package.json # dependencies (iii-sdk ^0.3.0, qrcode)
├── tsconfig.json
└── src/
├── iii.ts # SDK init + connection state helpers
├── hooks.ts # useApi, useEvent, useCron, emit (PubSub publish)
├── state.ts # State wrapper (scope/key API via iii.trigger)
├── streams.ts # Chat event stream (LRU replay buffer)
├── sessions.ts # State-backed session index with filesystem scan
├── metrics.ts # WorkerMetricsCollector with 5s cached snapshots
├── activity.ts # SSE activity feed — ring buffer + PubSub→SSE bridge
├── usage.ts # Daily usage aggregation (cost, tokens, requests)
├── traces.ts # Request traces — write/query/cleanup (30-day retention)
├── metrics-timeline.ts # 1-minute metric snapshots + overload alert detection
├── session-costs.ts # JSONL parser — backfill real costs from Claude Code sessions
├── proxy.ts # HTTP proxy with OTel tracing (14 endpoints)
├── index.ts # Register all functions, streams, PubSub, crons, proxy
├── ui.html # Full UI — 4 tabs, activity sidebar, Anthropic brand (~1500 lines)
└── handlers/
├── health.ts # GET /health (engine state + worker metrics)
├── setup.ts # Tailscale auto-publish with terminal QR code
├── shutdown.ts # Graceful shutdown (SIGINT/SIGTERM + unpublish)
└── cleanup.ts # Multi-scope cleanup (sessions, chats, index, streams)
Architectural pattern: Each module has single responsibility aligned with iii primitives. hooks.ts abstracts the SDK's reactive patterns (useApi, useEvent, useCron) into developer-friendly functions. state.ts provides type-safe wrappers around the scope/key API. The handlers/ directory contains only HTTP endpoint logic, keeping business logic in domain modules. The ui.html is a self-contained single file — unusual for modern development, but brilliantly portable for deployment scenarios where build pipelines aren't available.
Advanced Usage & Best Practices
Secure your Funnel deployments. Always set TAILCLAUDE_TOKEN when using Tailscale Funnel. The token validates via Bearer header for regular requests and ?token= query parameter for EventSource connections (which can't send custom headers). Rotate tokens regularly; the iii state store makes this trivial.
Optimize cost backfill scheduling. The default */5 cron for session reindexing plus cost backfill can create I/O contention on large ~/.claude/projects/ directories. Consider separating these jobs or increasing intervals if you notice latency spikes. The backfill is idempotent — safe to rerun.
Monitor the stream buffer. With 100 groups maximum and 30-minute TTL, heavy usage can evict active conversations. For production deployments, increase max_groups or implement tiered storage (hot in memory, warm in State, cold in files).
Extend with custom PubSub subscribers. The event bus (chat::started, session::indexed, etc.) enables powerful integrations: Slack notifications on expensive requests, PagerDuty alerts on repeated errors, automatic Git commits on chat::completed. The bridge to browser SSE means your extensions get real-time UI updates for free.
Use request traces for model optimization. The traces table reveals patterns: Sonnet often suffices where you default to Opus, Haiku handles simple queries at 15x cost reduction. Export trace data to your analytics pipeline for team-wide optimization.
Comparison with Alternatives
| Capability | SSH + tmux | Mosh + tmux | Termius | TailClaude |
|---|---|---|---|---|
| Client required | Terminal + SSH | Terminal + Mosh | Mobile app | Any browser |
| Setup time | ~15 min | ~20 min | ~10 min | ~60 seconds |
| Phone onboarding | Configure keys, install apps | Same + Mosh server | App store, account | Scan QR code |
| Network resilience | Drops on switch | Survives switches | Depends on SSH | Auto-reconnects |
| Streaming display | Raw terminal output | Raw terminal output | Terminal emulator | Token-by-token SSE |
| Session history | tmux attach only |
Same | Limited | Browse all sessions |
| Model switching | Edit flags, restart | Same | Same | Dropdown UI |
| Cost visibility | None | None | None | Per-message + dashboard |
| Mobile UX | Tiny fonts, shortcuts | Same | Slightly better | Touch-optimized, responsive |
| Permission controls | CLI flags | Same | Same | One-click modes |
| Collaborative access | Share SSH keys (insecure) | Same | Account sharing | URL + token auth |
| System monitoring | Separate tools | Same | Same | Built-in metrics + alerts |
The verdict: Terminal-based solutions optimize for connection stability. TailClaude optimizes for developer experience — and the gap widens with every feature. The only scenario where terminals win is offline-first usage without any network connectivity, though even then, local TailClaude at localhost:3110 works fine.
Frequently Asked Questions
Does TailClaude replace the Claude Code CLI?
No — it complements it. The CLI remains the source of truth for session files (~/.claude/projects/). TailClaude reads these files for backfill and can spawn the CLI for chat execution. You can switch between terminal and web seamlessly.
Do I need a paid Tailscale plan?
No. Tailscale's free tier handles personal tailnets and single-user Funnel perfectly. For team sharing with ACLs, consider their paid plans.
Is my code sent to third parties?
Only to Anthropic's API, same as regular Claude Code. The iii engine and proxy run entirely on your infrastructure. Tailscale sees only encrypted WireGuard traffic — no application data.
What Claude plans work with TailClaude?
Any plan supporting Claude Code CLI: Pro, Max, and enterprise tiers. The claude -p flag requires authenticated CLI access.
Can I self-host without Tailscale?
Absolutely. Run in local-only mode at http://localhost:3110, or put the proxy behind any reverse proxy (nginx, Caddy, Traefik). Tailscale is convenience, not requirement.
How does session replay work?
The iii stream buffer captures all chat events with LRU eviction. When a browser reconnects, GET /chat/replay/:id replays buffered events, then continues with live SSE. Missed the buffer window? The session index loads full history from Claude Code's JSONL files.
What's the performance overhead?
Minimal. The proxy adds ~2ms latency. The iii engine's state operations are sub-millisecond for indexed queries. Streaming passes through with negligible buffering. The heaviest operation — JSONL parsing for cost backfill — runs on cron, not the request path.
Conclusion
TailClaude isn't just a web interface for Claude Code — it's a fundamental rethink of how developers should interact with AI coding assistants. The terminal served us well for fifty years, but it was designed for human-to-machine communication in a pre-LLM era. When your "pair programmer" generates tokens at 50ms intervals, streams multi-file edits, and costs real money per request, you need visibility and controls that terminal emulators simply cannot provide.
The integration depth with the iii engine reveals what's possible when you stop treating AI tools as command-line utilities and start architecting for them. State-backed sessions. Event-driven cost tracking. Distributed tracing for every request. Cron-managed maintenance. These aren't luxuries — they're necessities for production AI development.
I've watched the "doom coding" movement evolve from SSH curiosity to genuine productivity hack. TailClaude represents its maturation: the terminal abstraction finally removed, not worked around. Whether you're debugging production from a ski lift, reviewing PRs on a tablet, or simply preferring the ergonomics of a modern web interface, this tool delivers.
Ready to try it? The repository is open source, MIT-licensed, and genuinely installable in 60 seconds. Clone rohitg00/tailclaude, run npm install && iii -c iii-config.yaml, and scan that QR code. Your most productive coding session might happen in places you never expected.
Found this deep dive valuable? Star the TailClaude repository, share your mobile coding setups in the issues, and follow the iii engine for the infrastructure powering the next generation of AI-native applications.
Comments (0)
No comments yet. Be the first to share your thoughts!