Skip to content

Repository files navigation

Claude Code Web Client

A claude.ai/code–style web client for Claude Code, built on Next.js 16 (Turbopack) + React 19 + shadcn/ui. It gives you true, live remote control of your Claude Code sessions from a browser — including your phone on the same Wi‑Fi — by talking to the same first‑party Remote Control API the official web app uses, and by reading the same local session files your terminal writes so the messages match your terminal exactly.

Reuses your existing Claude Code login — no API key required. The OAuth token stays on the server; the browser never sees it.

status react status


What it does

  • Remote Control · live — drives the actual live session (not a resumed copy) over Anthropic's first‑party Code Sessions API, exactly like claude.ai/code. No cold start, fully live, sharable.
  • Message parity — history is read from ~/.claude/projects/**/*.jsonl, the same files the terminal appends to, so what you see here is byte‑for‑byte what the terminal shows (an earlier version read cloud events and diverged when the bridge disconnected — this does not).
  • True realtime, no polling — the server tails the session file by byte offset and pushes appended lines over SSE using fs.watch; new tokens, tool calls and results stream into the UI as they land.
  • Claude‑web‑parity UI — markdown + GitHub‑dark syntax highlighting in chat and tool blocks, collapsible combined command/result blocks, Edited file +N -M diff stats, inline thinking blocks, inline images, live "responding…" status, presence and share.
  • Resume classic sessions — every session under ~/.claude/projects is listed (including terminal‑started ones); remote‑controlled sessions are flagged with a 📡 marker parsed from the bridge-session record.
  • Open a claude.ai/code link — paste a https://claude.ai/code/session_… link and it resolves to the local session hosting it.

Quick start

Requirements: Node 20+, macOS or Linux, and Claude Code installed & logged in (claude once, so credentials exist).

git clone https://github.com/serebano/claude-code-web-client.git
cd claude-code-web-client
npm install

# dev server
npm run dev                      # → http://localhost:3000

# production
npm run build && npm start

Test from your phone (same Wi‑Fi):

npm run dev -- -H 0.0.0.0        # bind to all interfaces
# then open http://<your-LAN-ip>:3000 on the phone

Add your LAN IP(s) to allowedDevOrigins in next.config.ts — Next 16 blocks cross‑origin dev asset/HMR requests by default (they 403 otherwise).

Environment overrides

Var Default Meaning
WORKDIR parent of this app Directory the interactive (SDK) agent works in
MODEL claude-opus-4-8 Model id for SDK‑driven turns

How it works

Authentication

No API key. The server reads your existing Claude Code OAuth token at runtime:

  1. macOS Keychainsecurity find-generic-password -s "Claude Code-credentials" -w (Claude Code migrated credentials into the Keychain).
  2. Fallback~/.claude/.credentials.json (older setups / Linux).

The claudeAiOauth.accessToken is used server‑side only; the organization UUID is resolved live from /api/oauth/claude_cli/roles. Nothing is hardcoded and no secret ever reaches the browser. See lib/rc.ts.

Remote Control protocol

All on https://api.anthropic.com, authed with the Claude Code OAuth token (scope user:sessions:claude_code):

Purpose Request
List sessions GET /v1/code/sessions
History (paged) GET /v1/code/sessions/{id}/events (sort_order, cursor)
Live stream GET /v1/code/sessions/{id}/events/stream (SSE: replays then tails/long‑polls)
Send / drive POST /v1/code/sessions/{id}/events{events:[{payload:{type:"user",message:{role:"user",content},client_platform,uuid}}]}
Presence heartbeat POST /v1/code/sessions/{id}/client/presence{client_id, clear}

Headers: Authorization: Bearer <token>, anthropic-version: 2023-06-01, anthropic-beta: oauth-2025-04-20, x-organization-uuid: <org>.

Local‑file realtime tailing

For message parity and instant updates the client prefers the on‑disk session file over cloud events:

  • Session mapping — a claude.ai/code/session_X link ↔ bridge id cse_X (in bridge-session records) ↔ local session UUID (the .jsonl filename).
  • Byte‑offset tailinglib/rc-local.ts reads only appended bytes since the last offset; tailLocalFromByte() is an async generator that catches up, then watches the file (fs.watch + a safety interval) and yields events for new lines. Large files (100MB+) are handled with bounded head+tail reads.
  • The SSE route (app/api/rc/stream) pushes those events to the browser's EventSource; the client folds them into the view with a pure reducer.

Architecture

 Browser (React / shadcn)              Next.js route handlers            Data source
 ────────────────────────             ─────────────────────────         ───────────────
 RcPanel  ── GET /api/rc/sessions ───▶ lib/rc.ts (list)                 api.anthropic.com
          ── GET /api/rc/stream ─────▶ tailLocalFromByte() (SSE) ─────▶ ~/.claude/projects
          ── POST /api/rc/send ──────▶ lib/rc.ts (drive live session) ▶ api.anthropic.com
          ── POST /api/rc/presence ──▶ presence heartbeat
 AppSidebar ─ GET /api/sessions ─────▶ lib/sessions.ts (parse jsonl)
 ChatPanel ── POST /api/chat (SSE) ──▶ Agent SDK query() (resume/fork)

Key files:

Path Role
lib/rc.ts Remote Control API client (token, org, list, send, stream, presence)
lib/rc-local.ts Local .jsonl parsing + byte‑offset realtime tailing
lib/sessions.ts Parse ~/.claude/projects/*.jsonl (title, cwd, branch, RC marker)
app/api/rc/* Route handlers proxying RC + streaming SSE to the browser
components/rc-panel.tsx The live Remote Control conversation view
components/markdown.tsx, code-block.tsx Markdown + highlight.js rendering
components/app-sidebar.tsx, chat-panel.tsx Sidebar + SDK‑driven chat

MCP servers (inherited from your CLI)

By default the Agent SDK runs isolated and loads none of your configured MCP servers. lib/runtime.ts opts back in with:

settingSources: ["user", "project", "local"]

This makes SDK‑driven turns load your real Claude Code config — settings, hooks, CLAUDE.md, and MCP servers — reusing the CLI's OAuth tokens. Project‑scoped MCP servers are keyed to a directory in ~/.claude.json, so point WORKDIR at the directory where the server you want is configured.


Notes & caveats

  • Localhost, unauthenticated. Add auth before exposing it beyond your LAN.
  • Undocumented, internal API. This uses the official client's OAuth token against an internal API. It works today (list, live stream, send, presence all verified) but can change without notice and is a Terms‑of‑Service gray area. Use on your own account at your own discretion.
  • Never write to session files. The .jsonl files under ~/.claude/projects are the source of truth for both the terminal and this app — the app only ever reads/tails them.

License

MIT — see LICENSE. Personal/experimental project; not affiliated with Anthropic.

About

A claude.ai/code-style web client for Claude Code — live Remote Control, byte-exact message parity with the terminal, true realtime updates. Next.js 16 + React 19 + shadcn/ui, no API key.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages