The Problem

Developers who work with Claude Code locally need a way to reach a running terminal session from a phone or any remote device. Without a dedicated tunnel they must expose ports manually (ngrok, port‑forwarding) or keep a laptop attached to the same network, which adds friction and security risk.

What This Does

The repository implements a small self‑hosted service that starts a local PTY, creates a Cloudflare (or Tailscale) tunnel, and serves a single‑page web UI that can be opened on a mobile device.

  • server/index.ts hosts the WebSocket control channel, broadcasts messages, and persists session data.
  • server/pty-session.ts wraps the PTY process, exposing getInfo, isExecutable, and other helpers.
  • web/app.js (1797 lines) renders the UI, handles QR‑code display and forwards user input to the WebSocket.
  • Tunnel providers live under server/tunnel/ (cloudflare.ts, tailscale.ts) and are selected via server/config.ts.

All runtime code is TypeScript except the monolithic UI bundle (web/app.js).

How It Is Wired

Execution begins when the CLI (npx claude-code-remote) runs the start script defined in package.json, which imports server/index.ts. The primary entry point is the WebSocket handler:

  • handleControlMessage (server/index.ts:247) receives commands from the browser, reaches 44 functions across the codebase and is the only place that calls ws.send (network outbound).
  • It frequently invokes sendControl (called 31 times) which builds a control packet and writes it to the WebSocket.
  • handleControlMessage also calls cleanupSessionHandlers, getInfo (server/pty-session.ts), broadcastToAll, and getSession.

Session lifecycle is managed by server/session-manager.ts, whose createSession, getSession, and destroySession are referenced by 1–3 callers each. The scheduler (server/scheduler.ts) reads/writes schedule files and performs a cryptographic operation when generating tokens.

Tunnel startup follows a short chain: startTunnel (server/tunnel/index.ts:19) → isAvailable (server/tunnel/cloudflare.ts or tailscale.ts) → start (creates the remote URL). This path touches only three functions.

File‑level responsibilities (ordered by blast radius):

FileCore dutiesExternal effect
server/index.tsWebSocket routing, client broadcastNetwork (ws.send), file I/O
server/scheduler.tsLoad/create cron schedules, token cryptoFile I/O, crypto
server/pty-session.tsPTY process control, info queriesFile I/O
server/tunnel/*Tunnel provider abstraction, remote URL creationNetwork
server/auth.tsToken validation middlewareNetwork
web/app.jsUI rendering, QR code, input forwarding (1797 LOC)Browser ↔ WebSocket

The import graph shows no circular dependencies; the most “unstable” module is server/index (instability = 1) because it imports nine others but is not imported itself, so changes there have the widest impact.

How To Use It

# Clone the exact repo
git clone https://github.com/moses-y/claude-code-remote
cd claude-code-remote

# Install dependencies (Node 18+ required)
npm ci

# Run the service (creates a local server and a Cloudflare tunnel)
npx claude-code-remote

The CLI prints a local URL (e.g., http://localhost:3456) and a remote Cloudflare URL with a QR code. Scanning the code with a phone opens the UI from web/index.html served by the Express server in server/index.ts. No additional configuration files are required; optional cloudflared must be installed separately if remote access is desired (see README).

Real‑World Use

A developer starts the tool on a workstation, scans the QR code on a phone, and runs git status inside the PTY from the mobile UI. Because the tunnel is managed automatically, the session persists across Wi‑Fi changes and can be revisited hours later without re‑authenticating.

Code Health & Issues

  • High – Oversized file: web/app.js (1797 LOC) makes the UI hard to maintain.
  • Medium – Deep nesting: Same file reaches indentation depth 6.
  • Medium – High branching density: server/activity-detector.ts and server/process-detector.ts each contain >44 branch points in <150 LOC.
  • Medium – Missing tests: No test files detected across the repo.
  • Medium – No LICENSE: Repository lacks a license file despite the README claiming MIT; legal reuse is ambiguous.

CI is present (.github/workflows/publish.yml), lockfile exists, and no secrets are committed.

The Bottom Line

The project delivers a functional, zero‑config remote terminal for Claude Code with a clear separation between server logic and tunnel providers. However, the monolithic UI bundle, lack of automated tests, and missing license hinder long‑term maintainability. Suitable for teams needing rapid remote access and willing to refactor the front‑end and add tests before scaling.