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

@buffbirb/unclaude

v1.0.29

Published

An opinionated AI dev tool setup script with a terminal UI. Configure privacy, code intelligence, and tool wrappers for Claude Code and OpenCode.

Readme

unclaude

An AI sanitizer and setup script with a TUI and CLI.

Why?

Do you make VSCode your commit author? Do you write "sent from my Dell XPS" in your PRs?

If not, then maybe you don't want AI agents leaving their dirty footprints all over your git history. This package will clean up commits from your local environment or Claude Code Web.

Want local sandboxes with better default sanitization? Try the sbx Apple Container wrapper.

I also added opt-in support headroom and openspec, which I consider broadly useful.

Quick start

# ───────── Installing ──────────

# Launch the TUI anywhere
npx @buffbirb/unclaude@latest

# Certain features (clangd on linux, apple container) may require sudo
sudo -v && npx @buffbirb/unclaude@latest

# ───────── Extras ───────────

# After installation:
# Run opencode in sandbox with --dangerously-skip-permissions and headroom token compression
headroom-start sbx opencode

Presets

Local environments are very simple to set up, but managed/remote environments employ a lot of tricks to make their attributions stick:

  • system prompt overrides CLAUDE.md
  • container/environment overrides git config and settings.json
  • GitHub PRs use MCP, most likely remote, which is not interceptable
  • tracked files are reverted between the pre-install script and session start, potentially scrubbing .claude/* and .gitignore
  • sometimes the setup script is skipped

This script offers two preset solutions:

  • Local preset (default) — minimal setup for local repos; no commits.
  • Hybrid preset — setup for local and managed environments; some items are committed and pulled into the remote environment to control attribution.

I could not make a purely remote setup work without relying on any committed items. There is nothing special about claude code web so feel free to explore other options.

Features

| Feature | What it does | |---|---| | Stop Telemetry | Exports CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 in ~/.unclaude/airc | | Agent JSON config for git commits | Sets attribution: { commit: '', pr: '', sessionUrl: false } in Claude Code settings.json | | Agent SessionStart hook for git commits | Registers a Claude Code SessionStart hook that installs a bash commit-msg hook in .git/hooks (and sets local git identity) at the start of every session | | Git branch rename (immediate + pre-push) | Renames the current claude/* or claude-* branch immediately, and installs a pre-push hook in .git/hooks/ that intercepts any claude/* push, rewrites it to the stripped name on the remote, deletes the old remote branch, and aborts the original push | | GitHub Action for PR body | Writes a workflow that strips Claude attribution from PR bodies on opened/edited | | LSP | Installs Claude Code plugins for C++, Swift, Python, TypeScript, Go, and Rust LSP support (claude-plugins-official). Language servers themselves are not installed — see LSP Install Details. | | Headroom | Installs headroom via uv; writes a headroom-start wrapper script to ~/.local/bin/ that starts the proxy and execs its arguments (e.g. headroom-start claude) | | OpenSpec | Installs @fission-ai/openspec globally via npm; optionally runs openspec init in the current directory | | Playwright CLI | Global. Installs the playwright npm package and its Chromium browser so the agent can drive a headless browser directly through its shell tool (playwright open, playwright screenshot, playwright codegen, or scripting against the playwright package) — no MCP server, no per-repo registration. | | Apple Container Sandbox | Writes an sbx wrapper script to ~/.local/bin/ that runs Claude or OpenCode inside an Apple Container (macOS only). The sandbox images ship the same Playwright CLI and headless browser pre-installed, run entirely inside the container (no exposed port, isolated profile) so it never touches a browser outside the sandbox. |

Feature matrix

| Feature | Agents | Scope | Local default | Hybrid default | |---|---|---|---|---| | Stop Telemetry | Claude Code | Global | ✓ | ✓ | | Agent config for git commits | Claude Code | Project | ✓ | ✓ | | Agent SessionStart hook for git commits | Claude Code | Project | | ✓ | | Git branch rename (immediate + pre-push) | Claude Code, OpenCode | Project | | ✓ | | GitHub Action for PR body | Claude Code, OpenCode | Project | | ✓ | | LSP | Claude Code | Global | | | | Headroom | Claude Code, OpenCode | Global | | | | OpenSpec | Claude Code, OpenCode | Global (install), Project (init) | | | | Playwright CLI | Claude Code, OpenCode | Global | | | | Apple Container Sandbox | Claude Code, OpenCode | Global | | |

Personalization

If you select Agent SessionStart hook for git commits or Git branch rename, a second screen asks whether to personalize the setup to your identity.

| Field | Purpose | |---|---| | Git user | Your user.name (prefilled from git config --global user.name). Used by Agent SessionStart hook for git commits. | | Git email | Your user.email (prefilled from git config --global user.email). Used by Agent SessionStart hook for git commits. | | Branch prefix | Prepended to renamed claude/* branches (e.g., username/foo). Used by Git branch rename (immediate + pre-push). |

This is most useful in managed/remote environments (e.g., Claude Code Web) where the AI does not have access to your local git configuration. By embedding your identity, commits and branch metadata are authored under your name rather than an AI-generated default.

Note: Commits will still show as unverified on GitHub / GitLab because most managed providers do not offer a secure place to store a GPG or SSH signing key.

Git Settings

Currently only .gitignore is amended with a section covering generated attribution-related files.

Optional Tools

LSP Install Details

When the LSP feature is selected, unclaude runs claude plugin marketplace update claude-plugins-official followed by claude plugin install <plugin>@claude-plugins-official for each plugin below. Claude Code only — OpenCode isn't supported for this feature.

Language servers are not installed. Each plugin expects the corresponding server on PATH; install it yourself however you normally manage toolchains. If a server is missing, Claude Code surfaces it in the /plugin command's Errors tab.

| Language | Claude Plugin | |---|---| | C++ | clangd-lsp | | Swift | swift-lsp | | Python | pyright-lsp | | TypeScript | typescript-lsp | | Go | gopls-lsp | | Rust | rust-analyzer-lsp |

Headroom helper

headroom-start <command> starts the headroom proxy if it isn't already running, then execs its arguments. On each invocation it:

  • Starts the proxy if needed — checks port 8787 with lsof; if nothing is there, launches headroom proxy --port 8787 in the background with HEADROOM_CODE_AWARE_ENABLED=1 and HEADROOM_HOST=0.0.0.0, then waits briefly for it to bind.
  • Sets LLM base URLs — exports ANTHROPIC_BASE_URL=http://localhost:8787 and OPENAI_BASE_URL=http://localhost:8787/v1 so any agent started after it automatically routes through the proxy.
  • Execs the rest of the command — replaces itself with "$@", so headroom-start claude is equivalent to running claude directly, just with the proxy in front.

If called with no arguments it just starts the proxy and sets the env vars, which is useful when sourced in a pre-session script.

Playwright CLI

Selecting Playwright CLI installs the playwright npm package globally and downloads its headless Chromium build. There's no MCP server and nothing is registered into .mcp.json or opencode.json — the agent gets browser automation the same way it gets any other CLI tool: by invoking playwright directly through its shell tool (playwright open <url>, playwright screenshot, playwright codegen, playwright pdf, or a one-off script requiring the playwright package). Because it's a plain global install rather than a per-repo registration, it works out of the box in every project without a prompt to approve a server, and it can't collide with a separately-registered MCP server the way the old project/user-scope split could.

The sbx sandbox ships the same CLI and browser baked into its image (see Sandbox) — no extra setup needed inside the container.

Sandbox (macOS only)

sbx claude / sbx opencode runs the agent inside an Apple Container. On each launch it:

  • Fetches the image — pulls the latest sandbox image from GHCR if a newer version is available; falls back to the locally cached image when offline.
  • Skips the directory trust warning — the working directory is bind-mounted into the container at /workspace, so the agent starts there without prompting.
  • Skips the permissions warning--dangerously-skip-permissions is passed automatically; you never see the interactive prompt.
  • Copies auth from the host — forwards your LLM credentials (see AI agent auth) and a GitHub token (see GitHub auth), so you don't log in again inside the container.

The sandbox image is based on node:22-bookworm-slim and comes with git, curl, sudo, jq, python3, gh, the agent CLI, and the Playwright CLI with a headless Chromium (contained in the sandbox — no exposed port; drive it via playwright ... through the agent's shell tool, no MCP registration needed) pre-installed. git is pre-configured to use the forwarded token for HTTPS operations and to rewrite SSH remotes to HTTPS, so the agent can clone and push without an SSH key. Language toolchains aren't baked into the image but are bootstrapped on demand for repos that opt in — see On-demand language toolchains.

AI agent auth

How your LLM credentials reach the agent inside the sandbox, and whether they expire:

Claude Code (priority order):

  1. ANTHROPIC_API_KEY from the host environment, forwarded as-is — never expires (until revoked).
  2. Claude subscription — on macOS the OAuth access token is read from the Claude Code-credentials Keychain entry and forwarded as CLAUDE_CODE_OAUTH_TOKEN. Only the access token is passed (not the refresh token), so it can't refresh inside the container. These tokens last ~8 hours; when one lapses, re-run sbx to grab a fresh one (your host app keeps the Keychain refreshed in the background).

OpenCode:

  • Provider API keys are forwarded from the host environment (a curated allowlist — ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY, OPENROUTER_API_KEY, AWS / Azure / Bedrock / Vertex, …). Never expire.
  • OAuth providers (/connect logins) live in ~/.config/opencode and ~/.local/share/opencode, which are bind-mounted read-write. Since that credential store is shared with the host, OpenCode refreshes an expired token in place — so it doesn't hard-expire like the Claude Keychain token.

In short: API-key auth never expires; the Claude subscription token is the one that lapses (~8h) and is renewed by re-running sbx.

GitHub auth

The sandbox runs the agent with --dangerously-skip-permissions, so any GitHub token forwarded into it can be used unattended. To keep the blast radius minimal, sbx can optionally mint a short-lived, single-repo token from a GitHub App instead of forwarding your full gh login.

# One-time setup after install step:
npx @buffbirb/unclaude container-gh-app

Follow the instructions and set up a GitHub app. The process is mostly automatic.

GitHub Apps are private by default, and a private App can only ever be installed on the single account (your personal account, or one org) that owns it. So one App does not cover both your personal repos and an org's repos — container-gh-app supports multiple Apps side by side, one per account, stored under ~/.unclaude/github-apps/<owner>.json (Keychain entries are similarly keyed per App). Run npx @buffbirb/unclaude container-gh-app from inside a repo whose owning account isn't configured yet, and it'll ask which account to create the App on (personal or a specific org) and set one up for it. Run it again from a repo whose account is already configured and it skips the questions, reusing that account's App and just reopening its install page so you can authorize the new repo.

How it works on each sbx claude launch:

  1. sbx reads the working directory's origin remote to determine owner/repo, then looks for a configured App for owner.
  2. If one exists, it signs a JWT with that App's private key read straight from the macOS Keychain (the key never enters the container) and mints an installation token scoped to only that repo, with contents / pull_requests / workflows / issues = write. There is no administration permission, so the token cannot delete repositories or touch any other repo.
  3. That ~1-hour token is forwarded as GITHUB_TOKEN / GH_TOKEN. gh and git push over HTTPS both use it (SSH github.com remotes are auto-rewritten to HTTPS inside the image).

The token lasts up to 1 hour and cannot be refreshed from inside the container (the key stays on the host). For a session longer than an hour, re-run sbx to mint a fresh one.

If you choose not to configure a GitHub app, sbx falls back to forwarding your host's existing GitHub credentials as-is:

  1. gh auth token, if gh is installed and logged in on the host.
  2. Otherwise, the GITHUB_TOKEN environment variable, if set.

That token carries whatever scopes your host login already has — it isn't limited to the current repo — so the agent inside the sandbox can act on any repo (or org) your login can reach.

Headroom in the sandbox

If headroom is already running on the host when sbx launches, the container's LLM base URL is automatically pointed at it:

  • ClaudeANTHROPIC_BASE_URL=http://<host>:8787
  • OpenCode → additionally OPENAI_BASE_URL=http://<host>:8787/v1

The host address is derived from Apple Container's bridge network (192.168.64.0/24 by default; the host is its .1 address). headroom-start binds to 0.0.0.0 so it's reachable from the container.

Headroom is a transparent proxy — it forwards the client's real credentials upstream and injects none of its own, so the container still needs the genuine credentials described in AI agent auth. If headroom is not running at launch time, the container talks to the Anthropic API directly using those same credentials.

Image paste (Claude only)

Claude Code reads a pasted image by shelling out to xclip — but the container has neither xclip nor an X clipboard, and it's fully isolated from the macOS pasteboard. sbx bridges the gap so Ctrl+V pastes your macOS clipboard image straight into the sandboxed agent.

  • In the container — an xclip shim is mounted at /usr/local/bin/xclip. When Claude reads the clipboard, the shim fetches the current image from the host over a forwarded Unix socket instead of a real X clipboard. Text/copy calls are no-op'd.
  • On the hostsbx starts an in-process HTTP server bound to a Unix socket in a per-launch temp directory (mktemp -d, mode 700) and reads the pasteboard directly via osascript/JXA (NSPasteboard), normalizing whatever's on it (PNG, TIFF, JPEG, GIF, HEIC, PDF, or a copied image file) to PNG.
  • Forwarded via container run --ssh — the socket is passed into the sandbox by repurposing SSH agent forwarding as a generic tunnel (SSH_AUTH_SOCK/var/host-services/ssh-auth.sock in the guest); nothing SSH-specific actually runs on either end. No port is opened, nothing is network- or LAN-reachable, and no token is needed — the socket is a private per-launch file only the container process can reach.
  • Nothing resident — the HTTP server and its temp directory live only for the duration of that one sbx claude session; both are torn down as soon as the container exits.

Self-installing on sbx claude — no separate setup step, no files written to ~/.cache/unclaude/ for this feature. Requires macOS + a container CLI build that supports run --ssh (both checked; the whole block is skipped otherwise — on an older container CLI or a non-Mac host, sbx just runs without image paste). Reading the clipboard via osascript needs no special permission prompt.

To copy an image on macOS: Cmd+C in most apps, or screenshot to clipboard with Cmd+Ctrl+Shift+4. Then Ctrl+V in the sandboxed agent.

On-demand language toolchains (makey)

Language toolchains aren't baked into the image (unlike python3 — see the Dockerfiles). Instead they're bootstrapped on demand via makey — a project's own Makefile defines just a venv target with its install commands; the shared plumbing in ~/.makey/common.mk supplies prepare/finalize/install around it, so the project Makefile stays boilerplate-free.

  • Detection — before launching the container, sbx checks the repo root for a Makefile with a venv: target.
  • In-container install — if found, the container's entrypoint becomes a small init script instead of the CLI directly: it runs make install (which drives preparevenvfinalize) inside the container, so anything it downloads matches the container's Linux/arch, not the host's, then sources .makey/activate before exec-ing into claude/opencode.
  • ~/.makey is mounted read-only — the project Makefile does include $(HOME)/.makey/common.mk, which needs to resolve at container-runtime too, so sbx bind-mounts your host ~/.makey/ into the container at the same path.
  • Per-project, host-persisted cachemake venv's output lands in .makey/ inside the project directory itself (via $(MAKEY_DIR), which defaults to ./.makey). Since the whole project directory is already bind-mounted into the container, no extra -v flag is needed for it — .makey/ is just part of the repo on the host and survives across runs for that project.

Projects without a Makefile/venv target never trigger any of this. See makey/Makefile and ~/.makey/common.mk for the rustup/cargo example this pattern replaced.

Viewing a dev server from the sandbox

sbx publishes no ports by default — the image runs with none exposed, and the Playwright browser inside must never be reachable from outside the sandbox. A dev server (dx serve, vite, etc.) you start inside the container is a different thing, though, and it's often useful to watch its live-reloading output in a real browser on the host instead of through agent-driven Playwright screenshots.

Opt in per-launch with SBX_PORTS, a comma-separated list of container ports to publish:

SBX_PORTS=8080 sbx claude          # dx serve --addr 0.0.0.0 --port 8080 inside the container
SBX_PORTS=8080,5173 sbx claude     # multiple dev servers at once

Each port is published to 127.0.0.1 on the host only — never the LAN — so http://localhost:8080 on your Mac reaches the dev server running inside the container. The server itself still needs to bind 0.0.0.0 (not 127.0.0.1) inside the container, since the publish only forwards the port, not the loopback interface.

CLI arguments

Running with no arguments launches the interactive TUI. Pass a subcommand for non-interactive use:

unclaude install   [--preset <name>] [--agents <list>] [--scopes <list>] [--features <list>] [--no-gitignore]
                   [--git-user <name>] [--git-email <email>] [--branch-prefix <prefix>]
unclaude uninstall [--preset <name>] [--agents <list>] [--scopes <list>] [--features <list>] [--no-gitignore]

Each list option takes a comma-separated value. Omitting --scopes or --agents defaults to all valid values; omitting --features uses the preset's defaults.

| Option | Description | |---|---| | --preset | local, hybrid (default: local; hybrid must be selected manually) | | --agents | claudeCode, openCode | | --scopes | global, project | | --features | stopTelemetry, stripCommitJSON, stripCommitAgentHook, renameBranchGit, stripPrWorkflow, lsp, headroom, openspec, playwrightCli | | --no-gitignore | Skip adding generated project-scope files to .gitignore (default: adds them) | | --git-user | Your user.name — used by stripCommitAgentHook to set local git identity. | | --git-email | Your user.email — used by stripCommitAgentHook to set local git identity. | | --branch-prefix | Prefix for renamed claude/* branches (e.g. username) |

Development

npm install
npm run dev      # run (tsx, no build step)
npm run build    # compile → dist/
npm publish      # builds automatically via prepublishOnly

Requires Node ≥ 18 and tsx (npm install handles dev dependencies).