
Security News
pnpm 11.10 Hardens Registry Authentication to Block Token Redirection
pnpm 11.10 hardens registry auth to block token redirection, tightens pack-app and deploy, and makes the Rust port (v12) installable.
@idl3/claude-control
Advanced tools
Local web UI to watch and drive your Claude Code sessions running in tmux — live transcripts, reply, answer AskUserQuestion, attach files, from a browser or phone.
A tiny, local web UI to watch and drive your Claude Code sessions from a
browser or phone. It discovers the Claude sessions you already run inside
tmux, streams each session's transcript live, lets you reply, answer
AskUserQuestion prompts, attach screenshots/files, and capture the pane — all
over 127.0.0.1 (or your Tailscale tailnet), behind an optional token you enter
in-app (never in the URL).
No daemon to babysit, no database: it reads Claude Code's transcript files and talks to tmux. Bind is localhost-only by default.
npm install -g @idl3/claude-control # or run once: npx @idl3/claude-control
claude-control: command not found? Use-g— a plain/localnpm installonly drops the binary in./node_modules/.bin/(not onPATH). If it's still missing after-g, your npm global bin dir isn't onPATH: runnpm prefix -gand add<that>/binto your shellPATH, or just usenpx @idl3/claude-control.
Prerequisites: Node ≥20 and tmux on your PATH (brew install tmux · sudo apt install tmux). Optional: ttyd for the in-browser raw terminal (brew install ttyd · sudo apt install ttyd) — set CLAUDE_CONTROL_TTYD to override its path. The web UI ships prebuilt — no build step on install.
Optional local AI (no API key):
Voice → text — run claude-control setup once: it installs ffmpeg + whisper.cpp (Homebrew) and downloads a ggml model to ~/.claude-control/models/. The mic in the composer then records audio and transcribes it locally (no API key). (Manual equivalent: brew install ffmpeg whisper-cpp and drop a model at ~/.claude-control/models/ggml-base.en.bin.)
Microphone on a phone or tablet: browsers only allow mic access on a secure context (HTTPS or
localhost). A plainhttp://192.168.x.x:4317URL leavesnavigator.mediaDevicesundefined on iOS/Android — the permission won't stick and re-prompts every reload.localhoston the Mac itself is exempt. Easiest fix:tailscale serve --bg 4317then open thehttps://<host>.ts.netURL. Or run with your own cert:TLS_CERT=cert.pem TLS_KEY=key.pem claude-control.
Prompt enhancer (✨) — defaults to a local MLX model on Apple Silicon. One-time setup:
python3 -m venv ~/.claude-control/mlx-venv
~/.claude-control/mlx-venv/bin/pip install mlx-lm
claude-control lazily starts mlx_lm.server on first use, keeps it warm, and shuts it down when idle. The model (default mlx-community/Llama-3.2-3B-Instruct-4bit, ~1.8 GB) auto-downloads on first run. Pick the backend + model in Settings (mlx → claude -p → rules fallback). Without the venv (or on non-Apple hardware) the enhancer falls back to claude -p, then a deterministic rules optimiser. Env overrides: CLAUDE_CONTROL_MLX_PYTHON, CLAUDE_CONTROL_MLX_PORT.
claude-control # start the server (prints the URL)
claude-control --help # config + subcommands
claude-control install-service # macOS: launchd auto-start on login + restart on crash
claude-control uninstall-service
Open the printed URL. If a token is configured (env CLAUDE_CONTROL_TOKEN, or a
token in ~/.claude-control/token), the app prompts for it on first load and
stores it in your browser — the token is never placed in the URL. With no token
set, it runs open on 127.0.0.1 / your tailnet.
git clone https://github.com/idl3/claude-control.git
cd claude-control
npm install
npm run build # builds the web UI (web/dist)
npm start # prints the URL
Open the printed URL (e.g. http://127.0.0.1:4317/). If a token is configured,
the app prompts for it on first load and remembers it in your browser — it's
never put in the URL. Any Claude Code session running in tmux shows up in the
left rail.
Already have tmux running with Claude sessions? You're done — just run
npm startand they appear automatically.
claude-control manages sessions through tmux: it lists tmux windows, finds the ones running Claude Code, and sends your replies as keystrokes to the right pane. So your Claude sessions need to live in tmux.
Nothing to do. claude-control reads your default tmux server (the same one
tmux ls shows). Start it and your sessions appear. To point at a non-default
tmux binary, set CLAUDE_CONTROL_TMUX=/path/to/tmux.
Install it and run Claude inside a tmux session so claude-control can see it:
# macOS: brew install tmux · Debian/Ubuntu: sudo apt install tmux
tmux new -s work # start (or attach) a tmux session
claude # run Claude Code inside it — now it's discoverable
That's it. Open more windows (Ctrl-b c) and run more Claude sessions; each
becomes a row in claude-control. (Tip: detach with Ctrl-b d — the sessions
keep running and stay visible in claude-control.)
A session is recognized when its pane is running Claude Code or has a
matching transcript under ~/.claude/projects/.
If panes show Operation not permitted when reading ~/Documents,
~/Desktop, or ~/Downloads — even though the same commands work in your normal
terminal — it's macOS privacy protection (TCC), not a bug. claude-control runs
as a launchd service, and the tmux server it starts inherits that context,
which has no Full Disk Access. Your terminal app (iTerm/Terminal) already has
the grant, which is why it works there.
Fix — grant Full Disk Access to the node that runs the service:
grep -A2 ProgramArguments ~/Library/LaunchAgents/com.*claude-control*.plist
(e.g. ~/.nvm/versions/node/vXX/bin/node, or which node → /opt/homebrew/bin/node)+. In the file
picker press ⌘⇧G, paste that node path (the ~/.nvm dir is hidden, so the
typed path is the only way in), add it, and toggle it on.launchctl kickstart -k gui/$(id -u)/com.<your-service-name>
tmux kill-server
Verify in a fresh pane: ls ~/Documents should work (no Operation not permitted).
Grant it to your own node path, not someone else's.
How you update depends on how you installed — pick your row. Check your
current version any time with claude-control --version.
npm installdoes NOT pull the git repo. The npm package ships the app prebuilt (theweb/distbundle is included), so there's no source tree togit pulland nothing to build. Update by reinstalling the package.
npm install -g)npm install -g @idl3/claude-control@latest # fetch the new version
# then restart the server (see "Restarting" below)
The in-app update banner / “Update now” button is for source checkouts
only (it runs git pull); on an npm install it has no repo to update, so use
the command above instead.
npx (no install)npx @idl3/claude-control@latest # always fetches the latest
npx re-resolves the package each run, so you're already on the newest version
every time you start it — just restart the process.
git pull && npm install && npm run build # then restart
…or click Update now in the app: the server pulls from origin, reinstalls,
rebuilds web/dist, and restarts itself in place; the page reconnects
automatically.
claude-control / npm start in a terminal): press
Ctrl-C, then run it again. The web UI reconnects on its own.claude-control install-service):
launchctl kickstart -k gui/$(id -u)/com.ernest.claude-control
or claude-control uninstall-service && claude-control install-service.Restarting is safe — sessions live in tmux, so nothing is lost; each browser re-prompts for the token once (if one is set).
Version numbers follow npm semver (claude-control --version).
All optional. Prefer CLAUDE_CONTROL_*; legacy COCKPIT_* names still work.
| Env | Default | Purpose |
|---|---|---|
CLAUDE_CONTROL_PORT | 4317 | HTTP/WS port |
CLAUDE_CONTROL_HOST | 127.0.0.1 | Bind address |
CLAUDE_CONTROL_TOKEN | (none) | Access token. Also read from ~/.claude-control/token. Sent as Authorization: Bearer (HTTP) / WS subprotocol — never in the URL. Unset and no file ⇒ tokenless. |
CLAUDE_CONTROL_PROJECTS | ~/.claude/projects | Where Claude Code transcripts live |
CLAUDE_CONTROL_UPLOADS | ~/.claude-control/uploads | Where attachments are stored (TTL-swept) |
CLAUDE_CONTROL_TMUX | (auto) | tmux binary override |
CLAUDE_CONTROL_MAX_UPLOAD_MB | 25 | Per-file upload cap |
127.0.0.1 by default; cross-origin WebSocket upgrades are rejected.tailscale serve): this UI can type into your live sessions. The token is
resolved in order from CLAUDE_CONTROL_TOKEN, else the file
~/.claude-control/token (mode 0600). With neither set it runs tokenless
(open to anything that can reach the port — the 127.0.0.1 bind, tailnet ACL,
and cross-origin check are the only guards).
localStorage. It's sent as an Authorization: Bearer header (and a WS
subprotocol) — never placed in the URL (URLs leak via history, server
logs, and referrer headers). A 401 returns you to the prompt.~/.claude-control/token, then
restart — launchctl kickstart -k gui/$(id -u)/com.ernest.claude-control
(launchd service), or just re-run npm start / claude-control. Each
browser re-prompts once. bin/install-service.sh reads the same file.0600 under the uploads dir and swept after a TTL.tmux list-windows every few seconds and matches each
window to the newest transcript for its cwd (lib/sessions.js).*.jsonl (bounded reads)
and streams appends over WebSocket (lib/transcript.js).tmux send-keys to the exact
pane (lib/tmux.js); attachments upload to the uploads dir and their path is
appended to the message for Claude to read.npm run dev # server with --watch
cd web && npm run dev # Vite dev server for the UI
npm test # node:test unit tests
MIT
FAQs
Local web UI to watch and drive your Claude Code sessions running in tmux — live transcripts, reply, answer AskUserQuestion, attach files, from a browser or phone.
The npm package @idl3/claude-control receives a total of 57 weekly downloads. As such, @idl3/claude-control popularity was classified as not popular.
We found that @idl3/claude-control demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
pnpm 11.10 hardens registry auth to block token redirection, tightens pack-app and deploy, and makes the Rust port (v12) installable.

Security News
/Research
Socket uncovered 17 malicious npm and PyPI packages typosquatting Paysafe, Skrill, and Neteller SDKs to steal developer secrets.

Security News
Node.js is debating whether AI-driven security report volume warrants moving more vulnerability reports into public workflows.