{"id":48085163,"url":"https://github.com/rohitg00/tailclaude","last_synced_at":"2026-04-04T15:14:06.808Z","repository":{"id":340347439,"uuid":"1165646300","full_name":"rohitg00/tailclaude","owner":"rohitg00","description":"Claude Code on your Tailscale tailnet, powered by the iii engine.","archived":false,"fork":false,"pushed_at":"2026-02-24T16:18:59.000Z","size":143,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-24T16:43:03.849Z","etag":null,"topics":["agent","ai","claude","claude-code","claudecode","code","genai","iii","session"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rohitg00.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-24T11:46:09.000Z","updated_at":"2026-02-24T16:21:11.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/rohitg00/tailclaude","commit_stats":null,"previous_names":["rohitg00/tailclaude"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/rohitg00/tailclaude","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rohitg00%2Ftailclaude","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rohitg00%2Ftailclaude/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rohitg00%2Ftailclaude/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rohitg00%2Ftailclaude/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rohitg00","download_url":"https://codeload.github.com/rohitg00/tailclaude/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rohitg00%2Ftailclaude/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31403954,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T10:20:44.708Z","status":"ssl_error","status_checked_at":"2026-04-04T10:20:06.846Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent","ai","claude","claude-code","claudecode","code","genai","iii","session"],"created_at":"2026-04-04T15:14:05.289Z","updated_at":"2026-04-04T15:14:06.802Z","avatar_url":"https://github.com/rohitg00.png","language":"HTML","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/banner-v2.jpg\" alt=\"TailClaude — Claude Code from any browser\" width=\"100%\" /\u003e\n\u003c/p\u003e\n\n# TailClaude\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/demo.gif\" alt=\"TailClaude Demo\" width=\"100%\" /\u003e\n\u003c/p\u003e\n\n**Claude Code from any browser. No SSH. No terminal. Just a URL.**\n\nTailClaude publishes a full Claude Code web interface to every device on your Tailscale tailnet — or the public internet via [Tailscale Funnel](https://tailscale.com/kb/1223/funnel). Powered by the [iii engine](https://github.com/iii-hq/iii).\n\nScan a QR code from your phone, open the link, and start coding with Claude — **streaming responses, full session history, model switching, real-time cost \u0026 usage dashboards, system metrics, request traces, live activity feed, and every Claude Code control in a touch-optimized UI styled with Anthropic's brand guidelines**.\n\n## Why TailClaude?\n\nEvery \"doom coding\" setup — SSH, mosh, tmux, Termius, Moshi — still puts you in a terminal. You're still typing on a tiny keyboard, memorizing shortcuts, and managing connections.\n\n**TailClaude removes the terminal entirely.**\n\n| | Terminal (SSH/mosh + tmux) | **TailClaude** |\n|---|---|---|\n| **Client** | Terminal app + SSH/mosh + tmux | **Any browser** |\n| **Phone setup** | Install app, configure keys/auth | **Scan QR code** |\n| **Network switch** | mosh helps, SSH drops | **Browser reconnects automatically** |\n| **Interface** | Terminal emulator | **Web chat UI with Markdown rendering** |\n| **Streaming** | Raw terminal output | **Real-time SSE, token-by-token** |\n| **Session history** | `tmux attach` (terminal only) | **Browse ALL sessions (terminal + web)** |\n| **Model switching** | Edit CLI flags, restart | **Dropdown: Opus, Sonnet, Haiku** |\n| **Permission modes** | CLI flags | **One-click: default, plan, acceptEdits, bypassPermissions** |\n| **Cost tracking** | None | **Live tokens + per-message cost ($0.01 · 4.5K in / 892 out)** |\n| **Stop mid-response** | Ctrl+C in terminal | **Stop button with instant feedback** |\n| **Mobile UX** | Tiny terminal, keyboard shortcuts | **Touch-optimized, responsive, dark theme** |\n| **Setup time** | ~15 minutes | **`npm install \u0026\u0026 iii -c iii-config.yaml`** |\n\nTailscale handles the secure connection. TailClaude handles everything else.\n\n## Architecture\n\n```text\n+-----------------------------------------------------------------+\n|  Browser (any device — phone, tablet, laptop)                   |\n|  https://your-machine.tail-abc.ts.net                           |\n+---------------------------------+-------------------------------+\n                                  | HTTPS (auto-cert via Tailscale)\n                                  v\n+-----------------------------------------------------------------+\n|  tailscale serve/funnel :443 -\u003e http://127.0.0.1:3110           |\n+---------------------------------+-------------------------------+\n                                  |\n                                  v\n+-----------------------------------------------------------------+\n|  Node.js Proxy (port 3110)                                      |\n|                                                                 |\n|  GET  /                  -\u003e Chat UI (Anthropic brand, tabs)     |\n|  GET  /health            -\u003e Engine state + worker metrics        |\n|  POST /chat              -\u003e OTel-traced SSE streaming chat       |\n|  POST /chat/stop         -\u003e Kill active process + lifecycle      |\n|  GET  /chat/active       -\u003e Active streaming request IDs         |\n|  GET  /chat/replay/:id   -\u003e Replay buffered chat events          |\n|  GET  /sessions          -\u003e State-indexed sessions (sub-ms)      |\n|  GET  /sessions/:id      -\u003e Full conversation history            |\n|  GET  /activity          -\u003e SSE live activity feed               |\n|  GET  /usage             -\u003e 7-day cost \u0026 token usage stats       |\n|  GET  /metrics           -\u003e System metrics timeline + alerts     |\n|  GET  /traces            -\u003e Request traces (cost/tokens/model)   |\n|  GET  /qr                -\u003e QR code SVG                          |\n|  GET  /settings          -\u003e MCP servers list                     |\n|  *                       -\u003e Proxy to iii engine (port 3111)      |\n+---------------------------------+-------------------------------+\n                                  |\n                                  v\n+-----------------------------------------------------------------+\n|  iii engine (port 3111)                                         |\n|                                                                 |\n|  State    -\u003e session_index, usage_daily, traces, metrics,       |\n|             alert_cooldowns, alerts, backfill_state, config      |\n|  Streams  -\u003e chat event replay buffer (LRU, 100 groups max)    |\n|  PubSub   -\u003e chat::started/completed/stopped, session::indexed, |\n|             cleanup::completed, alert::*                         |\n|  Cron     -\u003e */1 metrics snapshot, */5 session re-index +       |\n|             backfill, */30 cleanup, */6h data retention          |\n|  OTel     -\u003e distributed tracing on every chat request          |\n|  Logger   -\u003e structured logging with trace correlation          |\n|  Event: engine::started  -\u003e auto-publish to Tailscale + QR      |\n|  Signal: SIGINT/SIGTERM  -\u003e unpublish Tailscale + clean exit    |\n+---------------------------------+-------------------------------+\n                                  |\n                                  v\n+-----------------------------------------------------------------+\n|  claude -p --output-format stream-json --verbose                |\n|  (Claude Code CLI — works with Pro/Max plans)                   |\n+-----------------------------------------------------------------+\n```\n\n## How It Works\n\n1. **iii engine** runs the state store, event bus, stream layer, and cron scheduler\n2. **TailClaude worker** connects via WebSocket and registers functions, triggers, streams, and PubSub subscriptions\n3. **Node.js proxy** (port 3110) serves the UI and handles all endpoints with OTel tracing\n4. `POST /chat` spawns `claude -p --output-format stream-json --verbose`, wraps the request in an OTel span (model, cost, tokens, duration), writes events to the iii chat stream for replay, and emits lifecycle events via PubSub\n5. **PubSub subscribers** react to chat events: increment daily usage stats, write request traces, push to the SSE activity feed, and update the session index\n6. **Cron jobs** snapshot system metrics every minute (with overload alert detection), re-index sessions every 5 minutes (including backfilling real costs from Claude Code JSONL files), cleanup stale data every 30 minutes, and purge old usage/traces every 6 hours\n7. **Session cost backfill** parses Claude Code's native JSONL session files (`~/.claude/projects/`) to extract real token counts, model names, and cache usage — then calculates accurate costs using Claude API pricing\n8. On engine start, auto-publishes to your tailnet via `tailscale serve` and prints a terminal QR code\n9. On shutdown (Ctrl+C), unpublishes from Tailscale, unsubscribes engine listeners, and exits cleanly\n\n## Prerequisites\n\n- [iii engine](https://github.com/iii-hq/iii) installed and on your PATH\n- [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code) installed and authenticated\n- [Tailscale](https://tailscale.com) installed (optional — works locally without it)\n- Node.js 20+\n\n## Quick Start\n\n**3 commands. Under 60 seconds.**\n\n```bash\ngit clone https://github.com/rohitg00/tailclaude.git\ncd tailclaude\nnpm install\niii -c iii-config.yaml\n```\n\nThat's it. Open the URL printed in your terminal (or scan the QR code from your phone).\n\nIf Tailscale is running, TailClaude auto-publishes to your tailnet with HTTPS. No config needed.\n\n### Other Ways to Run\n\n**Run worker separately** (if iii engine is already running):\n\n```bash\nnpm run dev\n```\n\n**Proxy only** (quick testing, no iii engine):\n\n```bash\nnpx tsx -e 'import{startProxy}from\"./src/proxy.ts\";startProxy()'\n```\n\n### Verify\n\n```bash\ncurl http://localhost:3110/health    # Proxy health + Tailscale URL + sessions\nopen http://localhost:3110           # Open the chat UI\ncurl http://localhost:3110/sessions  # List all sessions with metadata\ncurl http://localhost:3110/usage     # 7-day cost \u0026 usage stats\ncurl http://localhost:3110/metrics   # System metrics timeline + alerts\ncurl http://localhost:3110/traces    # Request traces with cost/tokens/model\ncurl http://localhost:3110/qr        # QR code SVG\n```\n\n## Chat UI Features\n\n### Streaming \u0026 Chat\n- **Real-time SSE streaming** — tokens appear as Claude generates them\n- **Stop button** — abort mid-response with visual feedback (kills the claude process)\n- **Inline Markdown** rendering (code blocks, bold, italic, lists)\n- **Live token counter** — input/output tokens update as Claude streams (`4,521 in / 892 out`)\n- **Cost tracking** — per-message cost displayed on completion (`$0.0123 · 4,521 in / 892 out`)\n- **Tool use badges** — appear in real-time as Claude invokes tools, even before text arrives\n\n### Session Management\n- **Session discovery** — browse ALL Claude Code sessions (terminal + web)\n- **Conversation history** — click any session to load full chat history\n- **Session naming** — double-click (or long-press on mobile) to rename\n- **Auto-restore** — reopening the browser resumes your last session\n- **Relative timestamps** — \"2h ago\", \"3d ago\" on each session\n- **Slug names** — sessions display their Claude Code slug for identification\n\n### Claude Code Controls\n- **Model selector** — Opus (default), Sonnet, Haiku\n- **Permission modes** — default, plan, acceptEdits, bypassPermissions, dontAsk\n- **Effort levels** — low, medium, high\n- **Budget control** — set max spend per message\n- **System prompt** — append instructions to every message\n- **MCP servers** — view configured MCP servers in settings\n\n### Activity Feed (Live SSE)\n- **Real-time events** — chat started, completed, stopped, session indexed, cleanup, alerts\n- **SSE stream** at `GET /activity` — browser EventSource with auto-reconnect\n- **Ring buffer** — last 200 events stored in memory, last 50 replayed on connect\n- **PubSub bridge** — every iii PubSub event is bridged to the browser via SSE\n\n### Cost \u0026 Usage Dashboard\n- **Today's stats** — cost, requests, input tokens, output tokens\n- **7-day cost trend** — CSS bar chart showing daily cost\n- **Total accumulated cost** across all tracked days\n- **Real pricing** — uses Claude API rates (Opus $15/$75, Sonnet $3/$15, Haiku $0.80/$4 per M tokens, plus cache read/write rates)\n- **Session backfill** — parses Claude Code JSONL files for historical costs with real model and token data\n\n### System Metrics\n- **Gradient area charts** — memory RSS, CPU, event loop lag, worker uptime\n- **Per-metric colors** — orange (memory), blue (CPU), gray (lag), green (uptime) using Anthropic brand palette\n- **Min/Max/Avg stats** on each metric card\n- **Time axis labels** and grid lines\n- **30-second auto-refresh**\n- **Overload alerts** — threshold-based detection for CPU \u003e80%, memory \u003e500MB, lag \u003e100ms with 5-minute cooldown\n\n### Request Traces\n- **Full trace table** — timestamp, model, duration, cost, tokens in/out, exit status\n- **Color-coded status** — green (success), orange (error), gray (stopped)\n- **Summary stats** — average duration, average cost, today's request count\n- **30-day retention** with automatic cleanup\n\n### Access \u0026 Mobile\n- **QR code** — scan from phone to instantly access TailClaude\n- **Tailscale Funnel** — public HTTPS access (no Tailscale app needed on phone)\n- **Mobile-first** — hamburger menu, touch-optimized, responsive layout\n- **Anthropic brand design** — Dark #141413, Light #faf9f5, Orange #d97757 accent, Poppins/Lora typography\n- **Blurred Tailscale URL** — hover to reveal, keeps the URL private by default\n- **Connection status** with auto-reconnect polling\n- **Auth support** — set `TAILCLAUDE_TOKEN` env var to require bearer token (`?token=` query param for EventSource)\n\n## Project Structure\n\n```text\ntailclaude/\n├── iii-config.yaml              # iii engine configuration (180s timeout)\n├── package.json                 # dependencies (iii-sdk ^0.3.0, qrcode)\n├── tsconfig.json\n└── src/\n    ├── iii.ts                   # SDK init + connection state helpers\n    ├── hooks.ts                 # useApi, useEvent, useCron, emit (PubSub publish)\n    ├── state.ts                 # State wrapper (scope/key API via iii.trigger)\n    ├── streams.ts               # Chat event stream (LRU replay buffer)\n    ├── sessions.ts              # State-backed session index with filesystem scan\n    ├── metrics.ts               # WorkerMetricsCollector with 5s cached snapshots\n    ├── activity.ts              # SSE activity feed — ring buffer + PubSub→SSE bridge\n    ├── usage.ts                 # Daily usage aggregation (cost, tokens, requests)\n    ├── traces.ts                # Request traces — write/query/cleanup (30-day retention)\n    ├── metrics-timeline.ts      # 1-minute metric snapshots + overload alert detection\n    ├── session-costs.ts         # JSONL parser — backfill real costs from Claude Code sessions\n    ├── proxy.ts                 # HTTP proxy with OTel tracing (14 endpoints)\n    ├── index.ts                 # Register all functions, streams, PubSub, crons, proxy\n    ├── ui.html                  # Full UI — 4 tabs, activity sidebar, Anthropic brand (~1500 lines)\n    └── handlers/\n        ├── health.ts            # GET /health (engine state + worker metrics)\n        ├── setup.ts             # Tailscale auto-publish with terminal QR code\n        ├── shutdown.ts          # Graceful shutdown (SIGINT/SIGTERM + unpublish)\n        └── cleanup.ts           # Multi-scope cleanup (sessions, chats, index, streams)\n```\n\n## Configuration\n\n### Environment Variables\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `III_BRIDGE_URL` | `ws://localhost:49134` | iii engine WebSocket URL |\n| `NODE_ENV` | - | Set to `production` to enable UI caching |\n| `TAILCLAUDE_TOKEN` | - | Bearer token for proxy auth (recommended for Funnel) |\n\n### iii Modules\n\nThe `iii-config.yaml` enables these modules:\n\n| Module | Purpose |\n|--------|---------|\n| State (KV/file) | 8 scopes for sessions, usage, traces, metrics, alerts, backfill (`./data/state_store.db`) |\n| Streams | Chat event replay buffer with LRU eviction (100 groups, 30min TTL) |\n| REST API | HTTP server on port 3111 with CORS (180s timeout) |\n| Queue (builtin) | Internal task queue |\n| PubSub (local) | Event bus with 7+ topics, bridged to browser SSE for real-time updates |\n| Cron (KV) | */1 metrics, */5 sessions + backfill, */30 cleanup, */6h data retention |\n| OTel (memory) | Distributed tracing — traces stored in State for the dashboard |\n| Shell Exec | Auto-run the TypeScript worker (watches `src/**/*.ts`, auto-restarts on change) |\n\n## Tailscale Integration\n\nTailClaude supports two Tailscale modes:\n\n### Tailscale Serve (tailnet only)\n\nAccessible only from devices on your tailnet:\n\n```bash\ntailscale serve --bg --yes --https=443 http://127.0.0.1:3110\n```\n\n### Tailscale Funnel (public internet)\n\nAccessible from any device — ideal for phone access without installing Tailscale:\n\n```bash\ntailscale funnel --bg --yes --https=443 http://127.0.0.1:3110\n```\n\nWhen using Funnel, set `TAILCLAUDE_TOKEN` to prevent unauthorized access.\n\n### Auto-publish on Engine Start\n\nWhen Tailscale is available, TailClaude automatically:\n\n1. Detects your Tailscale IP and DNS name\n2. Checks for existing serve listeners (reuses if already active)\n3. Publishes via `tailscale serve` with HTTPS on port 443\n4. Verifies the proxy registered via status check (retries up to 3 times)\n5. Prints a QR code to the terminal for instant mobile access\n6. On shutdown, runs `tailscale serve --https=443 off` to unpublish\n\nIf Tailscale is not installed, it runs in local-only mode at `http://127.0.0.1:3110`.\n\n## API Reference\n\n| Endpoint | Method | Auth | Description |\n|----------|--------|------|-------------|\n| `/` | GET | No | Serve chat UI (Anthropic brand, 4 tabs) |\n| `/health` | GET | Yes | Engine state, worker metrics, session count |\n| `/chat` | POST | Yes | OTel-traced SSE streaming chat (spawn claude CLI) |\n| `/chat/stop` | POST | Yes | Stop active process + emit lifecycle event |\n| `/chat/active` | GET | Yes | List active streaming request IDs |\n| `/chat/replay/:id` | GET | Yes | Replay buffered chat events for reconnect |\n| `/sessions` | GET | Yes | State-indexed sessions with metadata (sub-ms) |\n| `/sessions/:id` | GET | Yes | Load full conversation history for a session |\n| `/activity` | GET | Yes | SSE live activity feed (`?token=` for EventSource) |\n| `/usage` | GET | Yes | Last 7 days of cost, tokens, and request stats |\n| `/metrics` | GET | Yes | System metrics timeline (60 snapshots) + active alerts |\n| `/traces` | GET | Yes | Last 100 request traces with cost/tokens/model |\n| `/qr` | GET | Yes | QR code SVG of the Tailscale URL |\n| `/settings` | GET | Yes | MCP servers and Claude Code config |\n\n### POST /chat Body\n\n```json\n{\n  \"message\": \"Hello Claude\",\n  \"model\": \"opus\",\n  \"mode\": \"default\",\n  \"effort\": \"high\",\n  \"sessionId\": \"optional-uuid-to-resume\",\n  \"maxBudget\": 5.00,\n  \"systemPrompt\": \"You are a helpful assistant\"\n}\n```\n\n## iii Integration\n\nTailClaude deeply integrates every iii engine primitive, making it a real-world reference app for the [iii SDK](https://github.com/iii-hq/iii).\n\n| Primitive | How TailClaude Uses It |\n|---|---|\n| **State** | 8 scopes: `session_index`, `usage_daily`, `traces`, `metrics_timeline`, `alerts`, `alert_cooldowns`, `active_chats`, `backfill_state` |\n| **Streams** | Chat event replay buffer — reconnect and resume mid-chat from any device |\n| **PubSub** | `chat::started/completed/stopped`, `session::indexed`, `cleanup::completed`, `alert::*` — bridged to browser via SSE |\n| **Cron** | */1 metrics snapshot, */5 session re-index + cost backfill, */30 cleanup, */6h data retention |\n| **OTel Tracing** | Every `POST /chat` wrapped in a span; traces stored in queryable State for the dashboard |\n| **Logger** | Structured logging with trace correlation across all modules |\n| **Connection Monitor** | Engine WebSocket state exposed in `/health` endpoint |\n| **Worker Metrics** | CPU, memory, event loop lag cached with 5s TTL; 1-minute timeseries in State for sparkline charts |\n\n## Background\n\nThe \"doom coding\" movement proved that coding from a phone is real — [Pete Sena](https://medium.com/@petesena), [Emre Isik](https://medium.com/@emreisik95), and [Ryan Bergamini's doom-coding repo](https://github.com/rberg27/doom-coding) showed what's possible with SSH + tmux + Termius. Others improved the connection layer with mosh and Moshi for persistent sessions through network switches.\n\nBut every approach still required a terminal client, key management, and tiny-keyboard typing.\n\nTailClaude asks: **what if you didn't need a terminal at all?** One URL, any browser, full Claude Code — with streaming, session history, model switching, and cost tracking that no terminal setup can match.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frohitg00%2Ftailclaude","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frohitg00%2Ftailclaude","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frohitg00%2Ftailclaude/lists"}