English · 简体中文
ccfly turns a running Claude Code session into a live, controllable web view — so you can read it, steer it, and resume it from a browser, your phone, anywhere.
It does not scrape the screen. It mirrors the inner world — the jsonl transcript Claude already writes under ~/.claude, plus the underlying tmux pane — into a surface world you can render and control. Detach, lock your phone, walk away, reconnect: the session keeps running in tmux and nothing is lost.
━━━ inner world ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Claude Code ──► ~/.claude/**.jsonl transcript · tool calls
⇅
tmux pane ◄──► PTY
│
▼ reads jsonl · drives tmux · /term WS
━━━ ccfly · Go control service ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
HTTP + WebSocket API npx ccfly serve · :7699
│
▼ baseUrl (HTTP / WS)
━━━ surface world · @ccfly/react ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
transcript · tool cards · diffs · permission prompts · input
rich selects (model · effort · permission) · image upload · /compact progress
live terminal mirror · subagents · workflows
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- Zero-config web UI.
npx ccfly serve, open the browser, pick a session — a full, self-contained surface world ships inside the binary. Nothing to build. - Mirror, don't scrape. The UI is built from the structured jsonl Claude already writes — real messages, tool calls, diffs, and permission prompts — not from terminal screen-grabs.
- Detach-safe by design. Sessions live in
tmux. Drop your connection, lock your phone, reconnect later — the run continues and the scrollback is intact. - Batteries-included terminal. ccfly serves its own terminal WebSocket (a real PTY running
tmux new-session -A, ttyd-compatible frames). The live terminal mirror needs no external ttyd. - Rich, native controls. Slash menus become real pickers — switch model & thinking effort, answer permission prompts, watch
/compactprogress live — and paste, drag, or upload images straight into the session. - Two layers, cleanly split. A tiny Go control service (
ccfly) + a React component library (@ccfly/react). Use one, or both. - Transport-agnostic. Runs on loopback by default. Tunnel it, mesh it, or put your own authenticating proxy in front — ccfly only cares about rendering and controlling a session.
- Single binary, zero runtime deps. The CLI ships prebuilt Go binaries over npm (
npx ccfly), resolved per-platform with no postinstall download.
npx ccfly serveThen open the URL it prints (default http://127.0.0.1:7699). ccfly serves a complete, self-contained surface world straight from the binary — pick a session and you get the full transcript, tool cards, diffs, permission prompts, input, live terminal mirror, subagents and workflows. Nothing to build.
The right prebuilt binary for your platform is pulled in automatically (ccfly-<os>-<arch>, e.g. ccfly-darwin-arm64).
ccfly serve [--port 7699] [--bind 127.0.0.1] [--claude-dir ~/.claude/projects]💡 Run it from outside the ccfly monorepo (e.g.
cd ~ && npx ccfly serve). Inside the repo, a local workspace package namedccflyshadows the published one.
npm i @ccfly/reactimport { CCFlyProvider, SessionView, CCFlyHosts } from "@ccfly/react";
import "@ccfly/react/style.css";
export function App() {
return (
// baseUrl points at the control service started by `npx ccfly serve`
<CCFlyProvider config={{ baseUrl: "http://localhost:7699" }}>
<SessionView sid={sessionId} />
<CCFlyHosts />
</CCFlyProvider>
);
}<CCFlyProvider>injects the control-service endpoint (plus storage / tmux naming) into the subtree.<SessionView>renders one Claude Code session — transcript, tool cards, diffs, permission prompts, rich select menus (model / effort / …), image & file upload, input, and the live terminal mirror (via ccfly's own/term).<CCFlyHosts>mounts the overlay hosts once at the root (code reader, subagent stack, workflow detail, image lightbox).
| Concept | What it means |
|---|---|
| Inner world | The real session: the tmux pane Claude runs in + the append-only jsonl transcript under ~/.claude. |
| Surface world | The web rendering of that session. Every control on the surface maps to a real action on the inner world. |
| Data over scraping | Message content comes from jsonl; control state comes from structured backend detectors — the frontend never reads pixels off the screen. |
| Own terminal WS | GET /term?session=<tmux> runs a PTY (tmux new-session -A) with a ttyd-compatible frame protocol, so the live terminal needs no external ttyd. |
| Package | Install | What it is |
|---|---|---|
ccfly |
npx ccfly serve |
Go control service over npm — tails ~/.claude jsonl, drives tmux, exposes the HTTP/WS API + /term. |
@ccfly/react |
npm i @ccfly/react |
React components that render and control a session: transcript, tool cards, diffs, permissions, input, terminal, subagents, workflows. |
The control service exposes a small, stable HTTP/WS surface. Highlights:
| Group | Endpoints |
|---|---|
| Session data | GET /transcript[/stream] · GET /subtranscript[/stream] · GET /subagents · GET /workflow · GET /workflowagent[/stream] · GET /cmdresult · GET /image · GET /info · GET /state |
| Control | POST /sendkeys · POST /start · POST /upload (image/file → session cwd) |
| Terminal | GET /term (WebSocket, ttyd-compatible) |
| Fallback / health | GET /capture (screen scrape, non-jsonl sessions) · GET /healthz |
🔐 Security. The service performs no auth of its own and binds loopback by default — equivalent to the full terminal control a local
tmuxalready grants. For any remote exposure, front it with an authenticating reverse proxy / hub (or bind it to a private mesh interface). Never bind0.0.0.0on an untrusted network.
ccfly/
├─ packages/
│ ├─ cli/ # npm package "ccfly" — bin shim + per-platform optionalDeps
│ └─ react/ # npm package "@ccfly/react" — UI components
├─ go/ # Go control service (reads ~/.claude jsonl + drives tmux)
├─ npm/ # per-platform binary subpackages (filled by cross-compile)
└─ examples/
└─ web/ # Vite app consuming @ccfly/react (the default surface)
pnpm install
pnpm build # build all TS packages (@ccfly/react)
pnpm typecheck # typecheck all packages
pnpm build:go # build the Go service into ./bin/ccfly (current platform)
pnpm build:binaries # cross-compile into npm/ccfly-<os>-<arch>/bin (all targets)Build a single target:
TARGETS="darwin/arm64" pnpm build:binariesThis repo is a pnpm workspace and uses changesets for versioning and publishing.
- ✅ Go control service ·
@ccfly/reactcomponent library · self-hosted terminal WS (v0.1.x) - ✅ Zero-config web UI —
npx ccfly serve, open the browser, pick a session, full surface world with nothing to build (v0.2.0) - ⬜ Multi-instance / multi-device contexts · themeable, prefixed CSS · full CI cross-compile matrix
Issues and PRs welcome. For releases, see PUBLISH.md (npm login, the @ccfly org, publish order for the platform binaries + CLI + React package, and GitHub setup).
MIT © ccfly authors