npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@idl3/claude-control

v0.1.22

Published

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.

Readme

claude-control

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.


Install (npm)

npm install -g @idl3/claude-control     # or run once: npx @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 → textbrew install ffmpeg whisper-cpp and drop a model at ~/.claude-control/models/ggml-base.en.bin. The mic in the composer records audio and transcribes it locally.
  • 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 (mlxclaude -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.


Quick start (from source)

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 start and they appear automatically.


The tmux setup (the one requirement)

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.

A) You already use 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.

B) You don't use tmux yet

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/.


Updating

claude-control compares your checkout against its git upstream (origin) and shows an update banner when new commits are available. Click Update now — the server pulls, reinstalls, rebuilds the web bundle, and restarts itself in place; the page reconnects automatically. (Equivalent manual update: git pull && npm install && npm run build, then restart.)

Version numbers follow npm semver (bump package.json per release); this is v0.1.0.


Configuration

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 |


Security

  • Binds 127.0.0.1 by default; cross-origin WebSocket upgrades are rejected.
  • Token auth — strongly recommended before exposing it (e.g. via 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).
    • The web app prompts for the token on first load and stores it in 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.
    • Set or rotate: write the token to ~/.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.
  • Uploads are written 0600 under the uploads dir and swept after a TTL.

How it works

  • Discovery — polls tmux list-windows every few seconds and matches each window to the newest transcript for its cwd (lib/sessions.js).
  • Transcript — tails each subscribed session's *.jsonl (bounded reads) and streams appends over WebSocket (lib/transcript.js).
  • Input — replies and answers are sent with 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.

Development

npm run dev             # server with --watch
cd web && npm run dev   # Vite dev server for the UI
npm test                # node:test unit tests

License

MIT