TeamClaude

repository·master·Indexed 41 days ago

https://github.com/karpeleslab/teamclaude

A multi-account proxy for Claude Code and Codex that pools Claude Max, ChatGPT/Codex, API-key, and third-party backend accounts. It automatically rotates accounts based on quota usage to prevent rate limits and session caps for coding agents. Version 1.1.21.

Tokens
37.8K
Snippets
106
Records
155
Agent score
58%

What's inside TeamClaude

  1. Revalidating spent Fable or Sonnet family buckets

    master

    Specific model-scoped weekly caps (like 7d_oi headers for Fable) are only present in responses from those specific models.

    The Staleness Mechanism:

    • When a family (e.g., Fable) is detected as spent (at or above the switch threshold), rotation stops sending that family to the account.
    • Because no more requests are sent, the reading cannot be refreshed passively.
    • A spent reading is trusted for 30 minutes (configurable via TEAMCLAUDE_FAMILY_STALE_MS).
    • After 30 minutes, the reading is dropped, the family falls back to the shared weekly bucket, and the next request re-establishes the truth from real headers.
    • Running the Quota Probe sidesteps this staleness by refreshing family buckets from the usage endpoint without consuming message quota.
  2. Configure Usage Dimensions for Project Tracking

    master

    Usage dimensions allow you to track token consumption by project, branch, or pull request without changing the proxy for every new grouping.

    1. Configure the Proxy: Define the dimension name and the HTTP header it should look for in the proxy.usageDimensions config.
    2. Set Identity in Client: Developers can set the identity in .claude/settings.json using the ANTHROPIC_CUSTOM_HEADERS environment variable.
    3. Set Identity in CI: CI environments can export ANTHROPIC_CUSTOM_HEADERS with newline-separated values.

    Constraints:

    • Dimensions are capped at 500 distinct values; additional values are grouped into (other).
    • Header values are sanitized and length-capped.
    • Dimension headers are consumed by the proxy for labeling and are not forwarded upstream.
    • Forbidden Headers: The proxy refuses to use authorization, proxy-authorization, cookie, x-api-key, x-app, x-claude-code-session-id, x-claude-code-agent-id, x-claude-code-parent-agent-id, and x-anthropic-additional-protection as dimensions.
    // Proxy Configuration
    {
      "proxy": {
        "usageDimensions": [
          { "name": "project", "header": "x-teamclaude-project" },
          { "name": "ref", "header": "x-teamclaude-ref" }
        ]
      }
    }
    // .claude/settings.json
    {
      "env": {
        "ANTHROPIC_CUSTOM_HEADERS": "X-Teamclaude-Project: KarpelesLab/teamclaude"
      }
    }
    # CI Usage
    export ANTHROPIC_CUSTOM_HEADERS=$'X-Teamclaude-Project: KarpelesLab/teamclaude\nX-Teamclaude-Ref: pull/123'
  3. How TeamClaude observes and persists quota

    master

    TeamClaude uses two primary methods to track quota:

    1. Passive Observation (Default): It reads anthropic-ratelimit-unified-* headers from responses flowing through the proxy. This is zero-cost but requires traffic to learn an account's status.
    2. Quota Probe (Optional): A background job that polls usage endpoints. This is zero-cost for message quota but requires the probe to be enabled.

    Persistence: Observed quota and tier metadata are stored in teamclaude.state.json next to the configuration file. This allows rotation state to survive restarts. If the file is deleted, quota is simply re-learned from subsequent traffic.

  4. Handle OAuth entitlement denials (403)

    master

    If an account returns a 403 with the error code error.details.error_code: oauth_not_allowed_for_organization, it means the organization does not permit OAuth.

    Behavior:

    • TeamClaude fails the current request to another account.
    • The denied account is quarantined (kept out of automatic rotation) for five minutes.
    • This cooldown is shared by subsequent requests but is not persisted to config.
    • If all accounts return this specific denial, the proxy returns a 502 error, names the denied accounts, and recommends pinning a different eligible account.

    Note: Pinning an account via TC_ACCT will bypass automatic rotation and continue targeting that specific account, even if it is quarantined due to an OAuth denial.

  5. Handle different types of 429 Rate Limit responses

    master

    TeamClaude distinguishes between three types of 429 responses to prevent unnecessary account rotation or cache loss:

    TypeTriggerAction
    Quota RejectionSpent 5h or weekly bucket (unified-…-status: rejected)Switches accounts immediately
    Rate-limit 429Per-minute throttleDoes NOT switch. Pauses the account, absorbs short retry-after durations (default $\le$ 60s via TEAMCLAUDE_RATE_LIMIT_ABSORB_MAX_SECONDS), and retries the same account.
    Request-scoped 429No retry-after or anthropic-ratelimit-* headers (often model refusal)One failover hop to an idle sibling, followed by one retry after TEAMCLAUDE_HEADERLESS_429_RETRY_DELAY_MS (default 2s). After the hop, it stays on the new account.

    Why not rotate on rate-limits? Rotating on a per-minute throttle simply moves the burst to the next account and discards the prompt cache of the first account.

  6. Understand session-aware routing and conversation pinning

    master

    TeamClaude has shifted from tracking load by client session to tracking load by conversation.

    Key Concepts

    • Conversation vs. Session: A single client session (like a Claude Code instance) may contain multiple conversations (e.g., a parent task and several subagents). Load is measured per conversation.
    • Pinning: A conversation is pinned to an account for a specific model family's weekly quota bucket. This ensures the conversation keeps hitting the same account to preserve its prompt cache.
    • Subagents:
      • A fresh subagent (not sharing context) is treated as a new conversation and can be routed to a different account.
      • A forked subagent (sent with the parent's messages) shares the same conversation digest and stays on the account holding the parent's cache.
    • Load Metrics: In teamclaude status, load is reported as active N sess (active conversations) and N inflight (requests currently in flight).
  7. How prompt caching interacts with account rotation

    master

    TeamClaude's account rotation is transparent to the client (like Claude Code), but it has implications for Anthropic's prompt caching:

    1. Context Continuity: Your conversation context is never lost. TeamClaude rewrites the account_uuid in the request to match the injected token, ensuring the new account sees the complete history.
    2. Cache Misses on Rotation: Prompt caches are scoped to the specific account/organization that created them. When TeamClaude rotates you to a new account, the first turn will be a cache miss (no discount). The new account will then begin warming its own cache for subsequent turns.

    Because TeamClaude attempts to keep you on a single account for as long as possible, these cache misses are infrequent.

  8. Understand the TeamClaude request lifecycle

    master

    TeamClaude acts as a local proxy between your client (e.g., Claude Code) and api.anthropic.com. The lifecycle follows these steps:

    1. Connection: The client connects to the local proxy.
    2. Account Selection: The proxy selects an active account and forwards requests using that account's credentials.
    3. Token Management: OAuth tokens expiring within 5 minutes are automatically refreshed and persisted to your config.
    4. Quota Tracking: The proxy monitors anthropic-ratelimit-unified-* headers to track 5-hour (session) and 7-day (weekly) quota usage.
    5. Rotation: When usage hits the switchThreshold (default 0.98), the proxy switches to the best available account.
    6. Error Handling:
      • On 429 responses, the proxy waits for the retry-after duration and retries. Persistent errors trigger an account switch.
      • On transient network errors (timeouts, connection resets), the proxy drops the connection so the client can retry.
    7. Exhaustion: If all accounts are exhausted, the proxy returns a 429 with the soonest reset time. If holdSeconds is configured, it will hold the connection open and retry silently until an account recovers.
    8. Token Refresh: Client requests to /v1/oauth/token are relayed to the upstream provider untouched.
  9. How Preemption and Pinned Conversations work with Expiry-Routing

    master

    When expiryRouting.preempt is set to true, the router can move a pinned conversation (and its sticky current account) if the account's governing weekly window rolls over.

    When a Pin is Re-routed:

    • Only occurs when the account's weekly window resets (rollover). This prevents a conversation from 'sitting' on a freshly reset account while other accounts' quota expires.
    • What does NOT trigger a move: Simple quota draining or pressure changes alone will not move a pin. This prevents unnecessary prompt cache thrashing.

    When a Pin is Broken (Standard Behavior): Preemption is separate from standard pin invalidation. A pin stops being honored if:

    1. The account cannot serve the request (e.g., spent quota, rate-limit hold, or upstream refusal).
    2. A higher-priority account becomes available.
    3. The account was already tried and failed earlier in the same request.
    4. A manual route pin or TC_ACCT override is used (these bypass affinity entirely).
    5. The conversation becomes idle past the known window.

    Implementation Detail: A rollover move is only considered 'settled' once the request is successfully served at the destination (HTTP status < 400).

  10. How TeamClaude proxying works

    master

    TeamClaude acts as a local MITM (Man-in-the-Middle) forward proxy between your coding agent (like Claude Code) and the provider's API (e.g., api.anthropic.com).

    The Request Lifecycle:

    1. Interception: The coding agent communicates with the local proxy instead of the direct Anthropic endpoint. The proxy also catches hardcoded api.anthropic.com calls via its MITM capabilities.
    2. Account Selection: The proxy selects an eligible account from the pool, injects the real token, and rewrites the account_uuid in the request body to match the selected account.
    3. Quota Tracking: The proxy monitors anthropic-ratelimit-unified-* response headers to track 5-hour (session) and 7-day (weekly) quotas. This state persists across restarts.
    4. Rotation: When an account reaches a threshold (98% by default), the proxy rotates to the next account. If a request hits a quota 429, the proxy transparently resends the request using a different account so the client never sees the error.
    5. Resilience: The proxy handles expiring tokens, transient network errors, and client token refreshes internally to prevent session interruptions.
  11. Enable session titles in the activity log

    master

    When using Claude Code, the proxy can display human-readable session names in the activity log instead of just session IDs. This requires sessionTitles.enabled to be set in your configuration.

    How titles are resolved:

    1. <session-id>/custom-title.json (created via /rename in Claude Code).
    2. A custom-title record within the session transcript.
    3. An ai-title record generated by Claude Code.
    4. Fallback: The first six hex characters of the session ID.

    TUI Interaction: While the proxy is running, you can toggle these labels on or off by pressing g → Session titles.

    Configuration: Use sessionTitles.width to adjust the column width allocated to the session name.

  12. How the `id` field works in account entries

    master

    Every account entry in the configuration contains a unique id. This ID ties the configuration entry to the active account instance in the running server.

    • Do not manually edit the id; it is managed by TeamClaude.
    • If you delete an id, a new one will be issued on the next read.
    • If you duplicate an account block, the system will detect the duplicate id and assign a fresh one to the second entry on the next read.