Prerequisites
- Node.js ≥ 20 —
node --version - A working local
claudeCLI — installed and logged in (which claude). This project drives your CLI; it does not ship Claude. - macOS or Linux (first-class). Native Windows is experimental; WSL2 is more reliable.
Official subscription or third-party gateway
Web inherits provider settings from the shell that starts the server. Official subscription: no extra env. Gateway/relay:
export the required ANTHROPIC_* in that shell, then start. Values in .env for ANTHROPIC_* are stripped at startup and have no effect.
Install and start
-
Clone and verify the host.
git clone https://github.com/Ike-li/claude-chat-mobile.git cd claude-chat-mobile node --version # need Node ≥ 20 which claude # must be installed & logged in -
Install runtime deps and run setup.
npm install --omit=dev # runtime only; full install if you run UI tests npm run setup # generates AUTH_TOKEN, asks WORK_DIR, writes .env (mode 0600) # or: cp .env.example .env and edit by hand -
Pre-flight check.
node scripts/doctor.js node scripts/doctor.js --fix # tighten .env and data JSON → 0600 -
Start the server.
npm start # http://localhost:3000 # startup log prints usable URLs with #token=…
Reach it from your phone
| Scenario | What to do |
|---|---|
| Same Wi‑Fi | Set a non-empty AUTH_TOKEN in .env, then open the LAN URL from the startup log: http://<lan-ip>:3000/#token=…. Without a token the server binds 127.0.0.1 only—phones cannot connect (intentional). |
| Temporary public / PWA https | In another terminal: cloudflared tunnel --url http://localhost:3000. Open the random HTTPS host with #token=. Token is stored in localStorage on first load, then cleared from the address bar. |
| Fixed production | Named tunnel + Cloudflare Access 2FA + a long-running process. See the Chinese handbook page 生产部署 and repo docs/deployment.md. |
First non-local connection: device trust (TOFU)
A valid token alone is not enough for the first non-loopback client. Approve the device once on the host:
node scripts/device.js list
node scripts/device.js approve <ID>
Security
This is a remotely reachable code-execution channel into your shell. Single-user per instance. Read the security model before exposing anything beyond your LAN: English Security Model · 中文安全模型 · README.en.md.
Security iron rules (quotable)
- One user per instance — not multi-tenant SaaS; anyone who passes auth has terminal-equivalent power.
- No
AUTH_TOKEN→ bind127.0.0.1only — phones and tunnels cannot reach it until you set a token. - CLI allow-list is inherited — no second “Web super-allowlist”; audit
~/.claude/settings.jsonbefore public exposure. - Device trust (TOFU) — first non-local client needs
device.js approve(Access JWT can skip). - Not Anthropic’s official app — independent open source; drives your local CLI via the Claude Agent SDK.
Full write-up: English Security Model.
If something fails
| Symptom | Likely cause | What to try |
|---|---|---|
| Phone cannot open the page on LAN | No AUTH_TOKEN (server on loopback only) |
Set token in .env, restart, use the URL with #token=… from the log |
| Token works but UI stays locked | Device TOFU pending | node scripts/device.js list then approve <ID> on the host |
doctor flags gateway / model |
ANTHROPIC_* only in .env |
Export vars in the same shell that runs npm start |
| Port 3000 already in use | Existing daemon or old process | Do not stack a second npm start; stop the resident service or change PORT |
claude missing / not logged in |
Host CLI not ready | Fix which claude and open a terminal conversation first |
Optional
- Statusline bridge (CLI-driven sessions mirrored in the Web status line):
npm run statusline:install— never auto-run by install/start. Check withnpm run statusline:status. - Dev loop:
npm run dev· pre-push gate:npm run check.
Already running a production daemon on port 3000?
Do not start a second
npm start against the same port for “just checking.” Use the Chinese ops page 运维与排错 or stop the daemon first.