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

@efoo/ccprofile

v0.1.1

Published

Per-directory Claude Code account routing via CLAUDE_CODE_OAUTH_TOKEN, direnv, and macOS Keychain

Downloads

309

Readme

ccprofile

Per-directory Claude Code account routing via CLAUDE_CODE_OAUTH_TOKEN, direnv, and the macOS Keychain.

ccprofile lets you run multiple Claude Code accounts in parallel — one per terminal, one per project — with zero manual switching. It never touches Claude Code's own Keychain entry, so there is no global "active account" to corrupt.

🤖 Install with an AI agent

Paste this prompt into Claude Code, Cursor, or any coding agent:

Install and configure ccprofile by following the instructions here:
https://raw.githubusercontent.com/efoo-team/ccprofile/main/docs/install-for-agents.md

The agent will check prerequisites (direnv, hooks), install the CLI, ask whether you want shell completion, and walk you through registering accounts — only the browser OAuth step needs your hands.

Why

Claude Code stores its OAuth credentials in a single macOS Keychain entry, shared across every CLAUDE_CONFIG_DIR profile (#20553). Switcher-style tools work around this by swapping that entry in place — which breaks down the moment two sessions with different accounts run at the same time (in-session token refresh writes the old account back).

ccprofile takes the declarative route instead:

  • Each account's long-lived OAuth token (claude setup-token, valid ~1 year) is stored in the Keychain under ccprofile's own namespace — one entry per profile, no sharing, no swapping.
  • ccprofile link writes a self-contained .envrc that exports CLAUDE_CODE_OAUTH_TOKEN straight from the Keychain. direnv activates it when you enter the directory. No node/npx in the hot path.
  • CLAUDE_CODE_OAUTH_TOKEN outranks the stored login in Claude Code's documented auth precedence, so linked directories route to their account and everywhere else falls back to your normal /login.

Auth state lives in each process's environment — parallel sessions cannot interfere with each other by construction.

Requirements

  • macOS (tokens are stored in the Keychain)
  • Claude Code with a Pro / Max / Team / Enterprise subscription (claude setup-token requires one)
  • direnvbrew install direnv + the shell hook (fish: direnv hook fish | source)
  • Node.js >= 20 (only for running ccprofile itself)

Install

npm install -g @efoo/ccprofile   # provides the `ccprofile` command
# or run ad hoc:
npx @efoo/ccprofile --help

Quick start

# 1. Register an account (launches `claude setup-token`, stores the token in the Keychain)
ccprofile add work --email [email protected]

# 2. Route a project to it — run inside the project directory…
cd ~/src/my-project
ccprofile link work

#    …or point at a directory from anywhere:
ccprofile link work ~/src/my-project

# 3. Done — any claude launched in that directory (and below) runs as "work"
claude        # /status shows "Auth token: CLAUDE_CODE_OAUTH_TOKEN"

Repeat with ccprofile add personal etc. Different terminals in different directories run different accounts concurrently.

Commands

| Command | Description | | --- | --- | | ccprofile add <name> | Register a profile. Flags: --email, --expires-at <iso>, --token <token>, --force | | ccprofile list [--json] | Profiles with token presence and expiry countdown | | ccprofile link <name> [dir] | Write the managed .envrc block and direnv allow | | ccprofile unlink [dir] | Remove the managed block (deletes .envrc if nothing else remains) | | ccprofile token <name> | Print the stored token to stdout (for scripting — handle with care) | | ccprofile remove <name> | Delete the profile and its Keychain entry | | ccprofile doctor [dir] | Diagnose overriding env vars (ANTHROPIC_API_KEY etc.), apiKeyHelper, expiry, token liveness, broken links. --offline skips the server probe | | ccprofile completion <shell> | Print a completion script for fish, zsh, or bash |

Shell completion

Subcommands, flags, and registered profile names are all tab-completable:

# fish
ccprofile completion fish > ~/.config/fish/completions/ccprofile.fish

# zsh (place _ccprofile somewhere in $fpath, then restart zsh)
ccprofile completion zsh > "${fpath[1]}/_ccprofile"

# bash
echo 'eval "$(ccprofile completion bash)"' >> ~/.bashrc

ccprofile link <TAB> completes profile names by calling the hidden ccprofile _profiles helper, which only reads ~/.ccprofile/config.json (never the Keychain).

How it works

~/.ccprofile/config.json     profile metadata: email, expiry, keychain ref (no secrets)
macOS Keychain               service "ccprofile", one entry per profile (the secrets)
<project>/.envrc             managed block, generated by `ccprofile link`:

  # >>> ccprofile managed >>>
  # profile: work
  export CLAUDE_CODE_OAUTH_TOKEN="$(security find-generic-password -w -s 'ccprofile' -a 'work' 2>/dev/null)"
  # <<< ccprofile managed <<<

Notes:

  • Tokens are written to the Keychain via security -i (stdin), so secrets never appear in ps output.
  • The .envrc block is self-contained: direnv re-evaluates it on every directory entry, and it must stay fast and dependency-free. ccprofile is only needed for CRUD operations.
  • Add .envrc to your project's .gitignore — it is machine-local.

Limitations — the price of parallel accounts

ccprofile is built on claude setup-token, whose long-lived tokens are deliberately scoped to inference only ("for security reasons", per Claude Code's own /doctor). Several conveniences of a normal /login session are therefore unavailable in linked directories:

  • No account identity introspection. The token cannot answer "whose token is this?" — the OAuth profile endpoint rejects it (user:profile scope missing, see #11985). The --email you record is a self-declared label, not verified. Verify identity once, at registration time: make sure the browser is logged into the intended claude.ai account before claude setup-token, then send a couple of prompts from a linked directory and confirm on claude.ai (web) that the intended account's usage moved.
  • /status → Usage tab shows no plan utilization in token-authenticated sessions (same scope restriction). Check usage on claude.ai instead.
  • Remote Control is unavailable in token-authenticated sessions; it requires a full-scope login token.
  • Tokens last up to 1 year but can die earlier (password change, logout-all). The recorded expiry is a hint, not a guarantee — ccprofile doctor probes the server and tells live tokens apart from revoked ones.
  • claude --bare does not read CLAUDE_CODE_OAUTH_TOKEN.
  • Subscription accounting: from June 15, 2026, claude -p / Agent SDK usage on subscription plans draws from a separate monthly Agent SDK credit.
  • direnv only sees shell-launched processes. Apps started outside a hooked shell (GUI launchers) bypass the routing.
  • Higher-precedence auth wins silently. ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN, apiKeyHelper, and Bedrock/Vertex/Foundry env vars all outrank the token — ccprofile doctor flags them.
  • macOS only for now (the token store is the macOS Keychain).

Development

pnpm install
pnpm build       # tsc → dist/
pnpm test        # vitest
node dist/index.js --help

License

MIT