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

cc-accounts

v0.1.4

Published

Run multiple Claude Code logins side by side. Like ccmirror, but for different claude accounts — claude-work, claude-personal, claude-team, with correct per-account billing isolation.

Readme

cca — Claude Code multi-account switcher

Run multiple Claude Code logins side by side on one machine.

Each account gets its own launcher — claude-work, claude-personal, claude-team — that starts Claude Code authenticated as a different subscription, with correct per-account billing isolation.

Install · Quick start · How it works · Commands · FAQ


Think of it as cc-mirror but for different Claude logins (not different providers), built on the proven billing-isolation core of claude-code-account-switcher.

$ cca add                     # register an account (runs claude setup-token)
Account display name: Work
Command suffix (without claude-) [work]:
Generating a one-year OAuth token for Work…
Paste the generated token: sk-ant-oat-…
Stored Work. Launch with: claude-work

$ claude-work                 # ← Claude Code, billed to your Work subscription
$ claude-personal             # ← same machine, same terminal, different subscription

🤔 Why this exists

Claude Code pins the account/org cached in ~/.claude.json's oauthAccount key onto every API request. So merely swapping an OAuth token (CLAUDE_CODE_OAUTH_TOKEN) isn't enough — Claude reads the cached org from disk and bills the wrong plan (a 403, then a silent fallback to whatever you last logged in as).

cca fixes this properly. Each account gets its own CLAUDE_CONFIG_DIR that shares all of ~/.claude/* (settings, plugins, skills, agents, memory, history) via symlinks, but writes a fresh .claude.json with oauthAccount stripped. With no cached org, Claude falls back to the org encoded in the injected token → correct billing, nothing reconfigured.

✨ What you get

Add an account. Everything else you already set up comes with it.

Most "account switchers" give you a second, empty Claude. This one gives you your Claude, signed in as someone else. Each account's config dir symlinks straight into ~/.claude, so every account inherits, live:

| Inherited | Meaning | |---|---| | skills/, plugins/ | Every skill and plugin, on every account. Install once. | | CLAUDE.md | Your global instructions follow you across accounts. | | settings.json | One config to maintain — with per-account overrides when you want them (Hybrid mode). | | MCP servers | Configured once, connected everywhere. | | projects/, history.jsonl | Memory and history stay whole — switching accounts doesn't fork your context. | | agents/, tasks/, plans/, … | Everything else in ~/.claude is shared the same way — the rule is "share it all", not a curated list. |

These are symlinks, not copies. Add a skill today and all accounts have it today — nothing to sync, nothing to duplicate, no drift between accounts.

Claude Code updates need no action. Launchers resolve claude from your PATH at launch, so the moment Claude Code updates, every account is on the new build. No per-account reinstall, no version pinning, nothing to re-run. (details)

Billing lands on the right plan. The one thing that must differ per account is the only thing cca isolates: .claude.json's cached oauthAccount, which Claude otherwise pins onto every request and bills wrong. (how)

Nothing to log into twice. Tokens live in the macOS Keychain (or a 0600 tokens.json), one claude-<slug> command per account, no re-auth on switch, no environment juggling.

Zero runtime dependencies. Your existing setup, times N accounts, billed correctly.

📦 Install

Requires: Node.js 18+ and the claude CLI on your PATH.

Option A — npx (recommended: nothing to install, nothing to update)

npx cc-accounts add

npx fetches the current release each time, so there is no update step and no stale version to chase. This is the recommended way to run one-off commands (add, list, doctor).

If npx seems to run an old version, its cache keys on the package name, not the version. Pin it once to refresh:

npx --yes cc-accounts@latest add

Option B — global install (needed for the claude-<slug> launchers)

npm install -g cc-accounts
cca add

The per-account launchers (claude-work, claude-personal, …) are symlinks that point at the cca binary. npx installs into a temporary cache that npm may clean up, so those launchers only keep working if cca is on your PATH for good. Run at least one global install if you want the claude-<slug> commands. Everything else works fine under npx alone.

Option C — from source

git clone https://github.com/nhocconan/cc-accounts.git
cd cc-accounts
npm install
npm run build
npm install -g .        # makes `cca` available globally

First-run note: cca installs per-account launchers (claude-<slug>) into a writable directory on your PATH (preferring ~/.local/bin). If that directory isn't on your PATH yet, cca will tell you exactly what to add to your shell config (~/.zshrc or ~/.bashrc):

export PATH="$HOME/.local/bin:$PATH"

Updating

| Installed via | Update with | |---|---| | npx | nothing to do — each run fetches the current release. If it looks stale: npx --yes cc-accounts@latest … | | npm install -g | npm update -g cc-accounts (or npm install -g cc-accounts@latest) | | from source | git pull && npm install && npm run build && npm install -g . |

Updating never touches your accounts: tokens stay in the Keychain (or tokens.json) and the registry stays in ~/.config/claude-accounts. After updating a global install, run cca sync to refresh the launchers.

Updating Claude Code itself

Nothing to do — every launcher always runs your current claude.

cca never pins, copies, or caches a Claude version. Each claude-<slug> launch resolves claude from your PATH at that moment and execs it, so the instant Claude Code updates itself (or you update it), every account picks the new build up on its next launch. The registry stores only slug/label/service/createdAt — no binary path.

The same holds for everything under ~/.claude (plugins, skills, agents, settings, memory): each account's config dir symlinks to it, so an update there lands for all accounts at once. Only .claude.json is written per account, to strip oauthAccount.

If several claude binaries are on your PATH (npm global, ~/.local/bin, Homebrew), cca takes the first one — the same one plain claude would run. cca doctor reports which.

🚀 Quick start

# 1. Add your first account (interactive — runs `claude setup-token`)
cca add

# 2. Add a second account
cca add

# 3. List them with live usage meters
cca list
#   claude-work            Work                            5h 42% · 7d 17% used
#   claude-personal        Personal                        5h 8% · 7d 2% used

# 4. Launch either one directly
claude-work
claude-personal

That's it. Each claude-<slug> is a standalone command — use it anywhere you'd use claude, and all args pass through verbatim:

claude-work -p "fix this test"          # one-shot prompt
claude-work --resume                    # resume a Work session
claude-personal cd ~/projects/blog      # run in a specific dir

🎯 Adding an account

When you run cca add, it launches claude setup-token, which opens a browser tab to generate a one-year OAuth token. Important: the token is bound to whichever account is signed in on claude.ai in your browser at that moment. So:

  1. Go to claude.ai and switch to the account you want this launcher to use (e.g. your Work login).
  2. Run cca add.
  3. Confirm in the browser tab that opens.
  4. Paste the generated token (sk-ant-oat-…) back into the terminal.
# Interactive (recommended)
cca add

# Fully headless — token from a flag or CLAUDE_CODE_OAUTH_TOKEN env var
cca add --name "Work" --slug work --token sk-ant-oat-…

# With per-account settings overrides (see Hybrid mode below)
cca add --name "Cheap" --slug cheap --token … \
  --settings '{"model":"haiku","env":{"MAX_THINKING_TOKENS":"4096"}}'

🧬 Per-account settings overrides (Hybrid mode)

By default every account shares your base ~/.claude/settings.json, plugins, skills, agents, and memory — so nothing needs reconfiguring. You can also give a specific account its own overrides:

# Pin a different model + extra env var for one account
cca edit personal --settings '{"model":"sonnet-4","env":{"PERSONAL_API":"v2"}}'

# Clear overrides (back to pure shared)
cca edit personal --settings clear

The override is deep-merged onto your base settings at launch — so env objects combine rather than replace. Example: base {"env":{"A":"1"}} + override {"env":{"B":"2"}}{"env":{"A":"1","B":"2"}}.

📋 Commands

| Command | Description | |---|---| | cca | Interactive account picker + actions (arrow-key TUI) | | cca list | List accounts with usage meters (5h 42% · 7d 17% used) | | cca add | Register a new account (runs claude setup-token) | | cca refresh <slug> | Replace an account's token | | cca remove <slug> | Delete an account and its token | | cca edit <slug> | Change label / slug / settings overrides | | cca launch <slug> | Launch Claude as that account | | cca sync | Rebuild launchers + refresh config dirs | | cca doctor | Audit tokens, isolation, and same-account collisions |

Or just run the launcher directly — that's the whole point:

claude-work            # = cca launch work
claude-work -p "..."   # any claude args pass through verbatim

🔧 How it works

~/.claude-accounts/                      ← cca's own data (CLAUDE_ACCOUNTS_DIR)
├── accounts.json                        ← registry: {slug, label, service, overrides}  (NO tokens)
├── configs/<slug>/                      ← per-account CLAUDE_CONFIG_DIR
│   ├── .claude.json                     ←   REAL file, oauthAccount STRIPPED  ← billing isolation
│   ├── settings.json                    ←   symlink to base, OR merged file if overrides set
│   ├── plugins/  skills/  agents/  ...  ←   symlinks to ~/.claude/*  (shared)
│   └── (daemon*, *.lock, *.sock absent) ←   per-process state NOT shared
├── usage/<slug>.json                    ← cached rate_limits (for list/doctor)
└── tokens.json                          ← Linux/Windows credstore (0600); macOS uses Keychain

~/.local/bin/claude-work → cca binary    ← busybox symlink (dispatches on its own name)

Launch flow (claude-workcca):

  1. Read the account's OAuth token from macOS Keychain (or tokens.json on Linux/Windows).
  2. Rebuild ~/.claude-accounts/configs/work/: refresh ~/.claude/* symlinks, write a stripped .claude.json, write a merged settings.json if overrides.
  3. Spawn claude with stdio: inherit, scrubbing competing auth vars (ANTHROPIC_API_KEY, _AUTH_TOKEN, _BASE_URL, Bedrock/Vertex/Foundry flags) and injecting CLAUDE_CODE_OAUTH_TOKEN, CLAUDE_CONFIG_DIR, and the account slug/label. Signals are relayed; claude's exit code is propagated.

Every launch is always fresh — current global settings, current token, current overrides — with ~50ms of Node overhead (invisible vs claude's startup).

Status line

cca registers itself as Claude's status-line command, so each session shows which account it's using plus live usage, in-session:

Work  ·  5h 42% · 7d 17%

The usage is also cached so cca list and cca doctor show meters without a running session.

Doctor

cca doctor

Audits each account: is the token present and correctly prefixed? Are any two accounts sharing one token or one usage fingerprint? (That's the classic symptom of a token generated while signed into the wrong account on claude.ai — both "accounts" silently bill the same subscription.)

Claude accounts doctor

  config isolation: per-account CLAUDE_CONFIG_DIR (.claude.json oauthAccount stripped)
  claude binary   : /Users/you/.local/bin/claude
  cca binary      : /usr/local/bin/cca

● Work  (claude-work)
    token : present (OAuth setup-token)
    usage : 5h 42% · 7d 17% used

✓ No problems detected.

The claude binary line is resolved fresh each run, so it also tells you which Claude install your launchers will exec if you have more than one.

⚙️ Environment variables

| Variable | Default | Purpose | |---|---|---| | CLAUDE_ACCOUNTS_DIR | ~/.config/claude-accounts | Root for all cca data | | CLAUDE_ACCOUNTS_BIN_DIR | first writable PATH dir (prefers ~/.local/bin) | Where claude-<slug> launchers go | | CLAUDE_ACCOUNTS_NAME_SESSIONS | (unset) | Set to 1 to name sessions after the account | | CLAUDE_CODE_OAUTH_TOKEN | — | Used by cca add/refresh as a headless token source |

🔒 Security

  • Tokens live only in the OS credential store: macOS Keychain on mac, a 0600 tokens.json elsewhere. Never in the registry, never in launchers, never logged.
  • Competing auth env vars are scrubbed before launching claude, so subprocesses, hooks, and MCP servers can't inherit a different account's credentials.
  • cca doctor is read-only and never contacts Anthropic.

🛠️ Development

npm install          # dev deps only (typescript, tsup, vitest, tsx)
npm test             # 28 unit tests: registry, isolation, settings, credstore, usage
npm run typecheck    # tsc --noEmit
npm run build        # tsup → single bundled dist/cli.js (zero runtime deps)
npm run dev -- list  # run from source via tsx

The codebase is pure TypeScript with zero runtime dependencies — the published dist/cli.js is a single ~40KB self-contained ESM bundle.

Project structure

src/
├── cli.ts                # entry: argv parse + busybox dispatch (claude-<slug> → launch)
├── tui.ts                # interactive account picker
├── core/
│   ├── paths.ts          # all path/env resolution
│   ├── registry.ts       # accounts.json read/write + slug validation
│   ├── credstore*.ts     # macOS Keychain / Linux+Windows tokens.json
│   ├── isolation.ts      # ⭐ per-account CLAUDE_CONFIG_DIR + oauthAccount strip
│   ├── settings.ts       # deep-merge base settings + overrides
│   ├── launcher.ts       # env scrub + token inject + spawn claude
│   ├── usage.ts          # cached rate-limit summaries + fingerprints
│   └── wrappers.ts       # claude-<slug> symlink create/prune
├── commands/             # list, add, refresh, remove, edit, launch, doctor, sync, statusline
└── ui/select.ts          # zero-dep arrow-key picker (fzf/numbered fallbacks)
test/                     # 28 unit tests

❓ FAQ

No — you can use this with one subscription (e.g. to separate Work/Personal contexts with different settings) or with multiple subscriptions (the main use case). The billing isolation is correct either way: each launcher bills the account whose token it carries.

No — that is the mechanism working, and it is the single most important thing to understand about this tool.

Claude Code's account panel renders the oauthAccount object cached in .claude.json. cca deliberately strips that key from each account's config dir, because Claude pins the cached org onto every API request and would otherwise bill the wrong plan no matter which token you inject. With no cached org, Claude falls back to the org encoded in the token itself.

So a blank account panel means isolation is active. Seeing a real account there would be the bug — it would mean a stale org is still cached and your requests are being billed to it.

To confirm which account a session is actually using, use the pieces built for it:

cca doctor        # per-account token + usage audit
cca list          # all accounts with usage meters

plus the in-session status line (Work · 5h 42% · 7d 17%), which cca passes to Claude at launch via --settings. That is why /status lists Setting sources: … Command line arguments.

If you added the account with cca add, no — you are on your subscription.

Two ways to check:

# 1. Token type
cca doctor
#    token : present (OAuth setup-token)      ← subscription

An sk-ant-oat… token comes from claude setup-token and bills your Claude subscription. An sk-ant-api… key is an API key and does bill per token — cca rejects those at add time.

# 2. Rate-limit windows
cca list
#    claude-work   Work   5h 24% · 7d 8% used

Those 5-hour / 7-day windows only exist on subscription plans. Pay-per-token API billing has no such window — it just meters tokens. If you see them, you are on the subscription.

Any dollar figure Claude Code displays is its generic token-cost estimator, shown regardless of how you authenticate. It is informational, not a charge against a card.

cc-mirror creates isolated Claude Code variants pointed at different providers (Z.ai, MiniMax, OpenRouter, …). cca is for switching between different Claude logins/subscriptions on the same provider (Anthropic), so you can run your Work and Personal Claude Pro/Max plans side by side.

Yes, by default — they're symlinked from ~/.claude/. That's the point: you configure once, all accounts benefit. Use per-account --settings overrides if you want an account to differ (e.g. a cheaper model for throwaway tasks).

Run cca sync — it rebuilds the claude-<slug> launchers from your registry. This happens automatically after add/edit/remove, but if you restored your config from backup or moved machines, cca sync fixes it.

If you run it with npx, there is nothing to update — every invocation pulls the current release. Otherwise see Updating:

npm update -g cc-accounts                       # global install
git pull && npm run build && npm install -g .   # from source
cca sync                                        # refresh launchers afterwards
cca list                    # note your slugs
cca remove work             # repeat for each (deletes token + launcher)
npm uninstall -g cc-accounts
rm -rf ~/.claude-accounts   # the config dir (optional, if you want a clean slate)

🙏 Credits

Built on the excellent work of:

  • claude-code-account-switcher — the billing-isolation core (.claude.json oauthAccount strip + symlinked config dir), credential store, usage meter, and doctor concept.
  • cc-mirror — the npm/npx distribution model and polished launcher DX.

📄 License

MIT © Tien Le