Coding Agent Account Manager (caam)

repository·main·Indexed 41 days ago

https://github.com/dicklesworthstone/coding_agent_account_manager

A tool for sub-100ms account switching for AI coding CLIs, allowing developers to swap between subscription accounts (such as Claude Max, GPT Pro, and Gemini Ultra) to bypass rate limits. It supports Vault Profiles for sequential switching, Isolated Profiles for parallel sessions, and Shallow Profiles for concurrent multi-account multiplexing. Compatible with Claude Code, Codex CLI, Antigravity CLI, Gemini CLI, and Grok Build.

Tokens
44.7K
Snippets
165
Records
211
Agent score
52%

What's inside caam

  1. Use Isolated Profiles for parallel sessions

    main

    Isolated Profiles allow you to run multiple accounts simultaneously with full directory isolation. Each profile receives its own $HOME and tool-specific home variables (like $CODEX_HOME), using symlinks to pass through your real development tooling (like .ssh, .gitconfig, and .npm).

    Isolation details:

    • Isolated (Real directories): Provider auth directories (e.g., ~/.claude, ~/.config/claude-code, $CODEX_HOME, ~/.gemini, ~/.config/opencode).
    • Symlinked (Passthrough): .ssh, .gitconfig, .gnupg, .aws, .cargo, .npm, .local/bin, and most $XDG_CONFIG_HOME entries (e.g., gh, uv).
    • Shared (Symlinked): Claude ~/.claude/skills, plugins, commands, and agents are symlinked so user tooling and skills are shared across sessions.
    • Never passed through: ~/.local/share/caam (contains the vault).

    Use this mode when you need two accounts running at the same time in different terminals.

    # Add profiles for different accounts
    caam profile add codex work@company.com
    caam profile add codex personal@gmail.com
    
    # Execute commands using specific profiles
    caam exec codex work@company.com -- "implement feature X"
    caam exec codex personal@gmail.com -- "review code"
  2. Understand credential namespaces: vault, isolated, and shallow

    main

    A single profile name can exist in three distinct credential namespaces. caam manages them separately to avoid invalidating OAuth credentials through accidental rotation.

    NamespaceLocationManaged By
    vault<vault>/<provider>/<name>/caam backup / caam activate
    isolatedProfile's HOME/XDG config dircaam login or in-app /login via caam exec
    shallow~/orch-homes/<name>/Signing in inside a shallow-spawn session

    When using caam limits <tool> --profile <name>, caam reads from the vault by default. You can explicitly override this using --source vault|isolated|shallow to list or read from a specific namespace.

  3. How Distributed Auth Recovery works

    main

    The Distributed Auth Recovery system automates the process of handling Claude Code rate limits across multiple remote terminal sessions. It solves the problem of manually copying OAuth URLs from a remote server to a local browser and pasting challenge codes back.

    Architecture

    • Remote (Linux Server): Runs a caam auth-coordinator daemon. It polls WezTerm panes using wezterm cli, detects rate limit messages, injects /login commands, extracts OAuth URLs, and eventually injects the challenge code back into the pane.
    • Local (Mac Mini): Runs a caam auth-agent daemon. It polls the remote coordinators, uses Playwright + Chrome to complete the OAuth flow (including Google account selection), and sends the challenge code back to the remote coordinator.

    The Recovery State Machine

    When a rate limit is detected in a WezTerm pane, the coordinator follows these steps:

    1. IDLE $\rightarrow$ Detects "You've hit your limit".
    2. RATE_LIMITED $\rightarrow$ Injects /login\n.
    3. AWAITING_METHOD_SELECT $\rightarrow$ Detects "Select login method:" and injects 1\n.
    4. AWAITING_URL $\rightarrow$ Extracts the OAuth URL via regex.
    5. AUTH_IN_PROGRESS $\rightarrow$ Sends URL to local agent and waits for the code.
    6. CODE_RECEIVED $\rightarrow$ Injects the code + \n.
    7. AWAITING_CONFIRM $\rightarrow$ Detects email confirmation and injects a resumption prompt (e.g., proceed. Reread AGENTS.md...).
    8. IDLE $\rightarrow$ Session resumes.
  4. Understand the difference between Vault and Isolated profiles

    main

    caam provides two distinct ways to manage accounts:

    • Vault profiles (backup/activate): These swap authentication files in place. This is a simple, instant method where only one account is active at a time per tool.
    • Isolated profiles (profile add/exec): These provide full directory isolation with a pseudo-HOME environment. This allows you to run multiple accounts simultaneously in parallel terminals.
  5. Claude Usage and Pricing Assumptions

    main

    The manager provides features for monitoring usage and pricing, but they are subject to the following conditions:

    • Pricing: Displayed pricing models apply specifically to API key mode. They do not apply to Claude Max subscriptions (which are 'all-you-can-eat').
    • Usage API: The usage monitoring feature (which tracks five_hour, seven_day, and opus utilization windows) uses an undocumented/experimental Anthropic beta API (anthropic-beta: oauth-2025-04-20). This feature is considered experimental and may fail without notice.
  6. Understanding Claude Identity and Token Limitations

    main

    When working with Claude accounts via this manager, be aware of the following constraints regarding identity and tokens:

    • Opaque Tokens: Claude access tokens are opaque and cannot be decoded (e.g., they are not JWTs). Consequently, identity information like email or accountId may not be extractable from the token itself.
    • Missing Identity Fields: Recent versions of Claude auth files may no longer include email or accountId fields. The manager is designed to handle these missing fields gracefully by returning empty strings rather than failing.
    • Token Expiry: The manager correctly parses expiresAt as Unix milliseconds to monitor session health.
  7. Understand Profile Health Scoring

    main

    caam uses a health scoring system to indicate the status of your AI provider profiles. This helps you decide which accounts are ready for use and which need attention.

    Health Status Indicators

    IconStatusMeaning
    🟢HealthyToken valid for >1 hour, no recent errors
    🟡WarningToken expiring within 1 hour, or minor issues
    🔴CriticalToken expired, or repeated errors in the last hour
    ⚪UnknownNo health data available yet

    Key Health Signals

    When inspecting profiles via caam ls --json or caam status --json, you will see three additive signals per profile:

    • refresh_due: true if caam should renew the credential soon. Note: This is false for self-refreshing Claude credentials and credentials without a refresh token.
    • launch_usable: true if a new session can start on this account right now. Rotation controllers should use this signal.
    • login_required: true if a human must re-authenticate (the credential has lapsed and cannot be renewed automatically).

    Note on Rate Limits: An active rate-limit cooldown sets launch_usable to false, but login_required remains false because it is not a login problem.

  8. Synchronize configuration in Shallow Profiles

    main

    Because a shallow profile's provider configuration (like .claude.json or .codex/config.toml) is a real, private file, it can diverge from your real HOME when you make changes within a session. To prevent stale configurations (e.g., old MCP server settings), you should sync them.

    caam shallow-profile sync-config <name>|--all reconciles the profile with your real HOME using these rules:

    • Unit Replacement: Sections (like [mcp_servers.*]) are replaced as a unit, not merged key-by-key. This prevents stale command/args from persisting alongside new url settings.
    • Non-destructive: Nothing is deleted. If a profile has a table that your real HOME does not, that table is preserved.
    • Codex Enforcement: cli_auth_credentials_store = "file" is re-enforced on every sync to prevent accidental use of shared keychains.

    Note: caam shallow-spawn performs a sync automatically unless --no-sync-config is passed.

  9. Handle `caam robot` exit codes and streams

    main

    When integrating with caam robot, follow these protocol constraints for robust error handling and data processing:

    Exit Codes

    • 0: Success
    • 1: Error
    • 2: Partial success

    Output Streams

    • Stdout: Reserved exclusively for data (JSON or NDJSON). Do not parse stdout for logs or warnings.
    • Stderr: Used for diagnostics, warnings, and statistics. Agents should monitor stderr for non-fatal issues.
    • Streaming: The robot watch command emits NDJSON (Newline Delimited JSON), where each line is a valid standalone JSON object representing a status change.
  10. How rotation policies work: availability vs drain

    main

    Rotation policies determine which profile caam switches the host to during caam activate, caam next, or caam run.

    • availability (default): Maximizes immediate headroom. It picks the seat with the most available quota.
    • drain (opt-in): Prioritizes spending included subscription quota that is about to expire. It ranks profiles whose included allowance resets soonest, provided they are below a headroom ceiling (default: 95% used). This prevents wasting subscription quota by leaving it unused while fresher accounts are consumed.

    To use the drain policy, pass --policy drain or configure stealth.rotation.policy in ~/.caam/spm_config.yaml.

  11. Syncing profiles across machines

    main

    You can use caam sync to replicate profiles across machines, but you must be aware of provider-specific security constraints.

    Rotating Refresh-Token Providers (e.g., Claude, Codex): These providers use a rotating refresh-token family. Replaying a stale token from another machine can revoke the entire account. By default, caam treats these as host-local: caam sync replicates the profile metadata so the machine knows the account exists, but it never replicates the credential payload. Each machine must perform its own caam add to maintain an independent grant.

    Non-rotating Providers (e.g., Gemini, OpenCode, Cursor): These maintain the old bidirectional replicate behavior.

    Customizing Sync Policy: You can override the sync behavior per provider or per profile in ~/.config/caam/config.json:

    {
      "sync_policy": {
        "providers": { "codex": "replicate" },
        "profiles":  { "claude/build-host": "replicate" }
      }
    }

    Warning: Forcing replicate on a rotating provider will trigger a loud warning if machines have diverged, as converging them risks account revocation.