[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-81745":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":12,"contributorsCount":14,"subscribersCount":14,"size":14,"stars1d":14,"stars7d":14,"stars30d":12,"stars90d":14,"forks30d":14,"starsTrendScore":14,"compositeScore":15,"rankGlobal":9,"rankLanguage":9,"license":16,"archived":17,"fork":17,"defaultBranch":18,"hasWiki":19,"hasPages":17,"topics":20,"createdAt":9,"pushedAt":9,"updatedAt":31,"readmeContent":32,"aiSummary":33,"trendingCount":14,"starSnapshotCount":14,"syncStatus":34,"lastSyncTime":35,"discoverSource":36},81745,"claude-in-box","jiangmuran\u002Fclaude-in-box","jiangmuran","Portable Claude Code dev environment in a Docker container — multi-session, hook-driven, web-managed, with transparent SOCKS5. Runs on a Raspberry Pi.",null,"Go",29,1,28,0,0.9,"MIT License",false,"main",true,[21,22,23,24,25,26,27,28,29,30],"ai-dev-tools","anthropic","claude","claude-code","docker","pty","raspberry-pi","remote-development","socks5","websocket","2026-06-12 02:04:19","\u003Cp align=\"center\">\n  \u003Cimg src=\"assets\u002Fbanner.png\" alt=\"claude-in-box — portable Claude Code dev environment with sessions, hooks, and a web API\" width=\"800\">\n\u003C\u002Fp>\n\n\u003Cp align=\"center\">\n  \u003Cstrong>English\u003C\u002Fstrong> &middot; \u003Ca href=\"README.zh-CN.md\">简体中文\u003C\u002Fa>\n\u003C\u002Fp>\n\n\u003Cp align=\"center\">\n  \u003Cem>Run Claude Code on a real server. Drive it from anywhere — browser, phone, IoT board, even an MCU — through one web port.\u003C\u002Fem>\n\u003C\u002Fp>\n\n\u003Cp align=\"center\">\n  \u003Ca href=\"LICENSE\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-MIT-D97757\" alt=\"MIT licensed\">\u003C\u002Fa>\n  \u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fdocker-multi--arch-2496ED?logo=docker&logoColor=white\" alt=\"docker multi-arch\">\n  \u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Farch-amd64%20%7C%20arm64-success\" alt=\"amd64 \u002F arm64\">\n\u003C\u002Fp>\n\n---\n\n## Overview\n\n`claude-in-box` packages a full development environment together with [Claude Code](https:\u002F\u002Fwww.anthropic.com\u002Fclaude-code) into a single Docker container and exposes it as a web service over **one port**.\n\nThe container is designed to run on a server (cloud VM, dedicated host, or a workstation that stays on). Inside, Claude Code runs in **interactive REPL mode**, which is a hard requirement: only interactive mode consumes the Anthropic subscription quota, while `--print` \u002F headless invocations require an API key. The control plane then exposes that interactive session over the network.\n\nCapabilities:\n\n- a sandboxed Linux box preloaded with a real dev environment — Node 22, Python 3 (with FastAPI + Uvicorn + Pydantic + httpx + rich + ipython), Go 1.25, Rust, plus `nginx`, `redis-server`, `postgresql`, and the Docker CLI\u002Fdaemon — and Claude Code itself;\n- common tools out of the box: ripgrep, fd, bat, htop, tmux, vim, nano, openssh-client, less, file, tree, jq, curl, wget, build-essential, make;\n- bundled services do not auto-start; pass `CIB_SERVICES=redis,postgres,nginx` (any subset of `redis`, `postgres`, `nginx`, `docker`) and the entrypoint brings them up before the control plane;\n- one or many virtual-TTY sessions running inside it, each a live Claude Code conversation in bypass-permission mode (the container is the sandbox, so per-tool prompts are unnecessary friction);\n- a Web UI that surfaces three concurrent views on the same session — raw virtual terminal, web-native structured Claude driver, and an API inspector for developers;\n- structured event streaming: text deltas, tool calls, todo updates, token usage, status changes, stop reasons, model metadata — all available as JSON frames over WebSocket or SSE, never screen-scraped from the TTY;\n- session lifecycle controls: create, attach, resume, kill, switch models on the fly;\n- two ways to bill Claude per session: an Anthropic subscription (signed in via the in-container OAuth flow driven by the Web UI), or an API key;\n- a Web API in multiple wrappings off one port: our native frame schema (REST + WS + SSE + AES envelope), **Anthropic-compatible** `POST \u002Fv1\u002Fmessages` and **OpenAI-compatible** `POST \u002Fopenai\u002Fv1\u002Fchat\u002Fcompletions` adapters with full incremental SSE streaming so existing SDKs can target the box as a drop-in, plus an MCU-friendly slim chat (`\u002Fsse\u002Fsessions\u002F{id}\u002Fchat` or `\u002Faes\u002Fsessions\u002F{id}\u002Fchat`) and a one-shot `\u002Fapi\u002Fsessions\u002F{id}\u002Fsend` send-and-wait endpoint;\n- a transparent SOCKS5 layer so every outbound packet from inside the box can be rerouted through one upstream proxy without per-tool config;\n- programmable hooks on every lifecycle event;\n- a single multi-arch image (`linux\u002Famd64`, `linux\u002Farm64`) that boots equally cleanly on x86 servers and Ampere-class arm64 hosts.\n\nThe intent is to decouple Claude Code from a single workstation: deploy it once on a server, then access it from any device using whichever transport and API shape fits the client.\n\n## Typical workflow\n\n```\n1.  Pick an environment image: prebuilt :latest or your own custom build on\n    top of it.\n2.  Forward one port (8080 by default).\n3.  docker run — the container boots the control plane on :8080, multiplexing\n    Web UI + REST + WS + SSE + AES envelope on the same port.\n4.  Open the web panel. Authenticate with the master API key minted at boot.\n5.  Sign in once via the Web UI to choose how Claude is billed:\n    an Anthropic subscription (the unified auth modal drives an\n    OAuth flow inside the container) or an API key. The setting\n    persists; new sessions inherit it.\n6.  Dashboard shows: live sessions, token consumption, wall-clock work time,\n    current model, hook activity.\n7.  Create a new session. The panel gives you three concurrent views on it:\n       (a) raw virtual terminal — xterm.js bound to Claude Code's PTY, the\n           native CC TUI as you'd see in iTerm;\n       (b) web-native Claude driver — chat-style transcript + todo sidebar\n           + tool-call timeline + token meter + model picker;\n       (c) API inspector — every frame and every API request\u002Fresponse,\n           devtools-style.\n    You can switch between them or open them side-by-side.\n8.  Talk to Claude. Switch models mid-flight. Watch todos, tool calls, and\n    status update live in the structured panes — they are rendered from a\n    typed event stream, not by screen-scraping the terminal.\n9.  From a phone, tablet, embedded MCU, or another agent, hit the same\n    sessions over the transport and API shape that suits the client —\n    REST\u002FWS for browsers, AES envelope or SSE for an ESP32, Anthropic- or\n    OpenAI-compatible HTTP for off-the-shelf SDKs (shipped — see\n    `docs\u002FAPI.md`).\n```\n\nThe remainder of this document describes each layer in more depth.\n\n## Capabilities\n\n### Sessions and Claude Code\n\n| Capability | Notes |\n|------------|-------|\n| Multi-session | PTY-backed; spawn, attach, detach, kill, list. Multiple clients can attach to the same session simultaneously. |\n| Interactive REPL only | Claude Code is run in its full interactive mode, never with `--print`. This is mandatory for subscription-quota billing and is what powers the structured event stream via hooks. |\n| Bypass-permission mode | Default. Claude Code runs with `--dangerously-skip-permissions` because the container is the security boundary, not the per-tool prompt. Can be turned off per session; hook `PermissionRequest` events still fire and can re-authoritate. |\n| Resume | Sessions are CC's own — transcript lives at `~\u002F.claude\u002Fprojects\u002F\u003Chash>\u002F\u003Csession>.jsonl`. `POST \u002Fapi\u002Fsessions { resume: \u003Csession_id> }` re-spawns with `--resume`. |\n| Model switching | `POST \u002Fapi\u002Fsessions\u002F:id\u002Fmodel { model }` sends `\u002Fmodel \u003Cname>` into the PTY mid-session and emits a `meta` frame. |\n| Input simulation | `POST \u002Fapi\u002Fsessions\u002F:id\u002Finput` writes raw bytes (or text frames) into the session's stdin. Same primitive backs both human typing and automation. |\n| Detached \u002F headless | Sessions survive client disconnects. Reconnect with `?from=\u003Cseq>` to replay missed frames. |\n\n### Claude authentication (per session)\n\n| Mode | When to use | How |\n|------|-------------|-----|\n| Anthropic subscription (default for personal use) | You pay for Claude Pro \u002F Max and want sessions billed against that subscription. | Sign in from the Web UI's auth modal — it drives a PTY-backed `claude \u002Flogin` flow inside the container and persists the credentials in the mounted `~\u002F.claude\u002F` volume. |\n| API key | Programmatic, CI, per-token billing, or sharing one box across users that bring their own keys. | Set `ANTHROPIC_API_KEY` on the container, or configure a provider in the Web UI for per-session selection. |\n| Long-lived OAuth token (legacy) | Useful for headless CI before the interactive flow shipped. **Note:** `claude setup-token`-issued tokens move to a separate Agent SDK billing quota after 2026-06-15 and no longer consume the interactive subscription. Prefer the interactive flow above. | Pass as `CLAUDE_CODE_OAUTH_TOKEN`. |\n| Third-party Anthropic-compatible host | You want to point at jmrai.net or your own proxy with a different `api_host`. | Built-in `jmrai.net` preset in the auth modal — paste your key, save, done. Custom host\u002Fkey\u002Flabel also supported. |\n| Mutual exclusion | Subscription and API-key paths cannot both be active at once. | Configuring an API provider wipes claude.ai credentials; logging into subscription deletes all configured providers. Enforced server-side. |\n\nSubscription billing only works because CC stays in interactive REPL mode inside the container — see the row above.\n\n### Structured event stream\n\nThe streaming bridge does not just relay terminal bytes. It parses Claude Code's lifecycle into typed frames that any client can render without screen-scraping. Every frame carries `session`, `seq`, `ts`.\n\n| Frame type | Emitted when | Payload fields |\n|------------|--------------|----------------|\n| `text.delta` | Assistant text streams | `text` |\n| `thinking` | Extended-thinking block | `text` (optional, gated by config) |\n| `tool.use.start` | Tool invocation begins | `tool`, `input` |\n| `tool.use.result` | Tool returns | `tool`, `output`, `error?`, `duration_ms` |\n| `todo.update` | TodoWrite \u002F TodoUpdate fires | `items: [{ id, subject, status, activeForm? }]` |\n| `ask.question` | Model asks the user to pick | `prompt`, `options[]`, `multiSelect` |\n| `usage` | End of turn | `input`, `output`, `cache_read`, `cache_write` |\n| `status` | Session state changes | `state` in `idle \u002F working \u002F waiting_for_input \u002F stopped`, `elapsed_ms` |\n| `stop` | Turn or session ends | `reason` |\n| `meta` | Model or config changes | `model`, `workdir`, … |\n| `hook` | A user hook fired | `name`, `event`, `payload`, `result?` |\n| `pty.raw` | Optional opaque PTY bytes | `data` (off by default, on for terminal-style clients) |\n\nClients pick which frames they care about: a phone dashboard probably wants `todo.update`, `usage`, `status`, `stop`; a terminal emulator wants `pty.raw`; a watchdog wants only `status` and `stop`.\n\n### Hooks\n\nHooks are first-class. The control plane installs its own `http`-type hooks at session start (HMAC-signed, pointed at an internal route) so it can capture every lifecycle event authoritatively. User-supplied hooks compose on top, merged from image-level (`\u002Fetc\u002Fclaude-in-box\u002Fhooks.json`), user-level (`~\u002F.claude\u002Fhooks.json`), and per-session declarations. Hooks can rewrite, block, inject context, or annotate; results land on the frame bus as `hook` frames.\n\n### Web API: one port, many wrappings\n\nThe container exposes exactly one TCP port. Everything is multiplexed onto it through HTTP routing. Each capability is wrapped in multiple shapes so very different clients can use the same backend with the format they prefer.\n\n| Wrapping | Path prefix | Best for | Crypto | Auth |\n|----------|-------------|----------|--------|------|\n| Native frame REST + WS | `\u002Fapi\u002F*`, `\u002Fws\u002F*` | Browser, phone, server, our Web UI | TLS via nginx | Bearer token (master or device-scoped) |\n| Native frame SSE | `\u002Fsse\u002F*` | Cheap one-way clients, log tailers | TLS via nginx | Bearer |\n| HTTP + AES envelope | `\u002Faes\u002F*` | Bare-metal MCU (ESP32, STM32) without a TLS stack | AES-256-GCM per-device key, v2 record-stream | API key + per-request nonce |\n| Anthropic-compatible API | `\u002Fv1\u002Fmessages` (+ `stream=true` SSE) | `@anthropic-ai\u002Fsdk` etc. — point `base_url` at the box and get subscription-backed Claude | TLS via nginx | Bearer \u002F API key |\n| OpenAI-compatible API | `\u002Fopenai\u002Fv1\u002Fchat\u002Fcompletions` | `openai` \u002F `openai-node` — same idea, OpenAI wire shape | TLS via nginx | Bearer \u002F API key |\n| Slim chat (embedded) | `\u002Fapi\u002Fsessions\u002F{id}\u002Fchat`, `\u002Fsse\u002Fsessions\u002F{id}\u002Fchat`, `\u002Faes\u002Fsessions\u002F{id}\u002Fchat` | MCU clients with a few hundred KB of RAM | TLS \u002F AES envelope | Bearer \u002F AES key |\n| Send-and-wait | `POST \u002Fapi\u002Fsessions\u002F{id}\u002Fsend` | One HTTP round-trip per turn for non-streaming clients | TLS via nginx | Bearer |\n| Port mapping | `\u002Fapi\u002Fports\u002F*` | Surface an in-container service on a host port via socat (needs `CIB_PORT_RANGE` on `docker run`) | TLS via nginx | Bearer |\n| MQTT bridge | — | IoT bus integrations (not yet built) | TLS or pre-shared | Per topic |\n| Raw TCP framed | — | Absolute minimum footprint (not yet built) | AES-GCM | API key |\n\nThe Anthropic- and OpenAI-compatible adapters are **format adapters over the same session bus**, not parallel runtimes. They let any tool that already speaks those APIs route through the box and pick up subscription-backed Claude.\n\nFor HTTPS deployments we ship an [nginx template](deploy\u002Fnginx.conf.template) that terminates TLS, proxies the REST surface, upgrades WebSocket connections, holds SSE open, and forwards client IPs.\n\nFor the embedded HTTP transport we ship a small protocol spec, [`docs\u002FAES-TRANSPORT.md`](docs\u002FAES-TRANSPORT.md), so device firmware authors can implement it in a few hundred lines with any AES-GCM library.\n\n### Auth on the control plane\n\n- A master API key is minted at container boot via `CIB_AUTH_TOKEN`. The control plane refuses to start without one (override only for local dev).\n- Device tokens can be issued via the API. Each has a label, scope set, and optional TTL. Revocable independently.\n- WebSocket auth travels in the `Sec-WebSocket-Protocol` subprotocol header to keep tokens out of URL logs.\n- OIDC is planned via a fronting reverse proxy (oauth2-proxy \u002F authelia). The control plane honors `X-Forwarded-User`.\n\n### Network: transparent SOCKS5\n\nSet `CIB_PROXY_URL=socks5:\u002F\u002Fuser:pass@host:port` once at boot and every outbound TCP (and UDP through `tun2socks` where supported) from inside the box is redirected through that proxy. Claude API calls, `npm install`, `pip install`, `apt`, `git push` — all of it, with no per-app config. Implemented via `redsocks` plus `nftables`.\n\n### Embedded clients (not the server)\n\nThe server side is intentionally **not** sized for embedded hosts — running CC in interactive mode against subscription quota wants a real machine. What is embedded-friendly is the **client** side:\n\n- The AES envelope HTTP transport is designed so an ESP32 \u002F STM32 \u002F RP2040 with only an HTTP client and an AES-GCM implementation can be a first-class participant: send input to a session, poll for structured frames, react to todos \u002F stop events.\n- A reference C client lives at [`clients\u002Fc\u002F`](clients\u002Fc\u002F) (mbedtls + libcurl, ~300 LOC), with a sibling ESP-IDF example.\n- A reference Python client lives at [`clients\u002Fpython\u002F`](clients\u002Fpython\u002F) (stdlib + `cryptography`, ~250 LOC, with tests).\n- A Rust reference client is the next on the list.\n\nSee [`docs\u002FARCHITECTURE.md`](docs\u002FARCHITECTURE.md) for the system in more depth.\n\n## Architecture (high level)\n\n```\n                                                       ┌────────────────────────────────────────────┐\n                                                       │            claude-in-box container          │\n                                                       │            (real server only)               │\n   Browser \u002F phone \u002F iPad   ── \u002Fapi  \u002Fws  \u002Fsse  ───▶   │  ┌────────────┐    ┌──────────────────┐    │\n   Server \u002F CI \u002F agent      ── \u002Fapi  \u002Fws  \u002Fsse  ───▶   │  │  control   │◀──▶│ session manager  │──┐ │\n   Existing Claude SDK      ── \u002Fv1\u002Fmessages*    ───▶   │  │   plane    │    │  (PTY-backed,    │  │ │\n   Existing OpenAI SDK      ── \u002Fopenai\u002Fv1\u002Fchat* ───▶   │  │  (single   │    │   interactive,   │  │ │\n   ESP32 \u002F STM32 \u002F MCU      ── \u002Faes\u002F...          ───▶  │  │   :8080,   │    │   bypass-perm,   │  │ │\n   Watchdog \u002F dashboard     ── \u002Fsse              ───▶  │  │   multi-   │    │   resumable)     │  │ │\n                                                       │  │   wrapped) │    └──────────────────┘  │ │\n                                                       │  │            │            ▲             ▼ │\n                                                       │  │  + auth    │            │     ┌──────────┐\n                                                       │  └────────────┘            └────▶│  hooks   │\n                                                       │        ▲                          │  runtime │\n                                                       │        │  structured frames       └──────────┘\n                                                       │        │  text.delta \u002F tool.use         │   │\n                                                       │        │  todo.update \u002F usage           │   │\n                                                       │        │  status \u002F stop \u002F meta          │   │\n                                                       │        │                                │   │\n                                                       │        │              ┌─────────────────┴──┐│\n                                                       │        └──────────────┤ session files +    ││\n                                                       │                       │ transcript.jsonl   ││\n                                                       │                       └────────────────────┘│\n                                                       │                                            │\n                                                       │   Claude Code  ◀── pty ──  session N       │\n                                                       │   Claude Code  ◀── pty ──  session 2       │\n                                                       │   Claude Code  ◀── pty ──  session 1       │\n                                                       │                ▲                            │\n                                                       │                │  Anthropic subscription    │\n                                                       │                │  (OAuth long token)        │\n                                                       │                │       or API key           │\n                                                       │     ┌──────────┴────────┐                  │\n                                                       │     │ transparent socks5│  ◀── optional    │\n                                                       │     │ (redsocks + nft)  │     PROXY_URL    │\n                                                       │     └───────────────────┘                  │\n                                                       └────────────────────────────────────────────┘\n```\n\n## Quick start\n\n```bash\ndocker run -d --name claude-box \\\n  -p 8080:8080 \\\n  --cap-add NET_ADMIN \\\n  -e CIB_AUTH_TOKEN=$(openssl rand -hex 32) \\\n  `# optional headless creds: ANTHROPIC_API_KEY or CLAUDE_CODE_OAUTH_TOKEN (legacy)` \\\n  -e CIB_PROXY_URL=socks5:\u002F\u002Fuser:pass@proxy.example:1080 \\\n  -e CIB_SERVICES=redis,postgres                    `# auto-start bundled services` \\\n  -e CIB_PORT_RANGE=9000-9019 -p 9000-9019:9000-9019 `# optional: expose in-container services on host ports` \\\n  -v $(pwd)\u002Fworkspace:\u002Fworkspace \\\n  -v $(pwd)\u002Fsessions:\u002Fvar\u002Flib\u002Fclaude-in-box\u002Fsessions \\\n  -v $(pwd)\u002Fclaude-home:\u002Fhome\u002Fcoder\u002F.claude \\\n  -v \u002Fvar\u002Frun\u002Fdocker.sock:\u002Fvar\u002Frun\u002Fdocker.sock      `# optional: talk to host Docker` \\\n  ghcr.io\u002Fjiangmuran\u002Fclaude-in-box:latest\n\nopen http:\u002F\u002Flocalhost:8080\n```\n\nThe master token (`CIB_AUTH_TOKEN`) is what you paste into the Web UI on first visit; mint device-scoped tokens from there.\n\nAPI-only mode (no Web UI on `\u002F`, only `\u002Fapi\u002F*` `\u002Fws\u002F*` `\u002Fsse\u002F*` `\u002Faes\u002F*` `\u002Fv1\u002F*` `\u002Fopenai\u002Fv1\u002F*`) — same image, just a runtime flag:\n\n```bash\ndocker run -d --restart unless-stopped \\\n  -p 8080:8080 \\\n  -e CIB_MODE=headless \\\n  -e CIB_AUTH_TOKEN=... \\\n  ghcr.io\u002Fjiangmuran\u002Fclaude-in-box:latest\n```\n\nBehind HTTPS via nginx: see [`deploy\u002Fnginx.conf.template`](deploy\u002Fnginx.conf.template).\n\nImplementing the AES envelope on a microcontroller: see [`docs\u002FAES-TRANSPORT.md`](docs\u002FAES-TRANSPORT.md).\n\n\n## Contributing\n\nIssues and pull requests are welcome. For client-device integrations with specific constraints, opening an issue first makes alignment easier. Small, focused changes are preferred over broad refactors.\n\n## License\n\n[MIT](LICENSE)\n","`claude-in-box` 是一个基于 Docker 容器的便携式 Claude Code 开发环境，支持多会话、钩子驱动，并通过 Web 管理，同时提供透明 SOCKS5 代理，可在 Raspberry Pi 上运行。该项目利用 Go 语言开发，集成了 Node 22、Python 3（附带 FastAPI、Uvicorn 等）、Go 1.25、Rust 以及常用服务如 nginx、redis 和 postgresql，为开发者提供了一个完整的沙盒环境。其核心功能包括交互式的 REPL 模式下的 Claude Code 运行、Web UI 对同一会话的三视图展示（原始虚拟终端、结构化的 Claude 驱动界面和 API 调试器），以及通过 WebSocket 或 SSE 的结构化事件流传输。适合远程开发场景，无论是浏览器、手机还是 IoT 设备都能轻松访问并控制该环境，尤其适用于需要在轻量级硬件上进行 AI 开发或测试的情况。",2,"2026-06-11 04:06:14","CREATED_QUERY"]