Files
ccs/docs/system-architecture/provider-flows.md
T

21 KiB

Provider Integration Flows

Last Updated: 2026-03-30

Detailed provider integration flows including CLIProxyAPI, legacy GLMT compatibility transforms, remote CLIProxy, quota management, and authentication.


CLIProxyAPI Flow

Overview

CLIProxyAPI is a local OAuth proxy binary that enables seamless integration with multiple AI providers. CCS manages the binary and configuration automatically.

Local Backend Choice

CCS defaults to the original router-for-me/CLIProxyAPI backend because it is the stable MIT upstream. The plus backend is an explicit opt-in path that downloads the community-maintained kaitranntt/CLIProxyAPIPlus fork for providers that still require Plus-only support, such as Kiro, GitHub Copilot, Cursor, GitLab, CodeBuddy, and Kilo. CCS does not silently downgrade backend: plus to original; users choose that backend deliberately when they need those providers.

+===========================================================================+
|                      CLIProxyAPI Integration                               |
+===========================================================================+

  Claude CLI
        |
        | ANTHROPIC_BASE_URL = localhost:XXXX
        v
  +------------------+
  |   CLIProxyAPI    |  Local proxy binary (Plus fork opt-in for plus-only providers)
  |   (binary)       |
  +------------------+
        |
        +---> OAuth Authentication
        |           |
        |           +---> Authorization Code Flow (port-based)
        |           |         - Gemini, Codex, Antigravity, Kiro (port 9876)
        |           |         - Opens browser for user auth
        |           |         - Callback to localhost:PORT
        |           |
        |           +---> Device Code Flow (no port needed)
        |                     - GitHub Copilot (ghcp)
        |                     - User enters code at github.com/login/device
        |                     - Polls for token completion
        |           |
        |           v
        |     +------------------+
        |     |   OAuth Server   |  Browser-based auth
        |     +------------------+
        |
        +---> Request Transformation
        |           |
        |           v
        |     Anthropic Format --> Provider Format
        |
        +---> Image Analysis Hook (v7.34)
        |           |
        |           v
        |     Vision Model Proxying (gemini, codex, agy, clipproxy)
        |           - Auto-injected via claude-hooks
        |           - Skip for Claude Sub accounts (native vision)
        |           - Fallback with deprecated block-image-read
        |
        +---> Provider APIs
                    |
                    +---> Google (Gemini)
                    +---> GitHub (Codex)
                    +---> Antigravity (AGY)
                    +---> AWS Kiro (Claude-powered)
                    +---> GitHub Copilot (ghcp)
                    +---> OpenAI-compatible endpoints

Supported Hardcoded Providers

Provider ID Auth Method Port Binary
Gemini gemini Authorization Code 9876 CLIProxyAPI
Codex codex Authorization Code 9876 CLIProxyAPI
Antigravity agy Authorization Code 9876 CLIProxyAPI
Kiro (AWS) kiro Method-aware (default: Device Code) 9876 CLIProxyAPIPlus fork
GitHub Copilot ghcp Device Code none CLIProxyAPIPlus fork

Codex Duplicate-Email Account Identity

Codex can legitimately produce multiple auth files for the same email when the user has both a team/business login and a personal/free login. CCS now treats those as separate accounts instead of collapsing them by email.

  • Internal account IDs stay duplicate-aware for Codex only: email#variant
  • Variant keys are derived from the auth filename, for example kaidu.kd@gmail.com#04a0f049-team and kaidu.kd@gmail.com#free
  • Dashboard surfaces continue to show the canonical email, with a compact variant badge such as Team or Free
  • Quota fetch resolves the exact registry tokenFile for the selected account instead of scanning by email and taking the first match
  • Live usage/account monitor stats key by provider + account identity, so duplicate Codex emails no longer merge into one runtime bucket

This preserves the user-visible distinction between business and personal Codex sessions while keeping other providers on their existing email-backed identity model.

Hardcoded Provider Detection

CCS detects hardcoded providers via profile-detector.ts and routes through execClaudeWithCLIProxy().

// Profile name matching
const hardcodedProviders = ['gemini', 'codex', 'agy', 'kiro', 'ghcp'];

if (hardcodedProviders.includes(profileName)) {
  return execClaudeWithCLIProxy(claudeCli, profileName, args);
}

Legacy GLMT Compatibility Flow

Overview

GLMT is no longer a marketed runtime surface in CCS. Existing glmt profiles are kept as a compatibility path and normalized at launch to the direct GLM endpoint. The src/glmt/ module remains because Cursor response translation still imports its transformer pipeline.

+===========================================================================+
|                Legacy GLMT Compatibility + Internal Transforms             |
+===========================================================================+

  Claude CLI
        |
        | legacy glmt settings detected
        v
  +------------------+
  | Compatibility    |  normalizeDeprecatedGlmtEnv()
  | Layer            |  (src/utils/glmt-deprecation.ts)
  +------------------+
        |
        v
  +------------------+
  | Direct GLM API   |  https://api.z.ai/api/anthropic
  +------------------+
        |
        v
  +------------------+
  | src/glmt/*       |  retained for Cursor translation
  +------------------+

Supported Migration Targets

Provider Config Key Endpoint Auth
Z.AI (GLM) glm https://api.z.ai/api/anthropic API key
Kimi API km https://api.kimi.com/coding/ API key
Legacy compatibility glmt normalized to direct GLM at runtime existing profile only

Use ccs glm for Z.AI profiles and ccs km for reasoning-first Kimi API profiles. Keep glmt only when migrating an existing settings file.

Runtime Handling

CCS detects the deprecated glmt profile name and normalizes legacy proxy-only settings before dispatching through the normal settings-profile flow:

if (isDeprecatedGlmtProfileName(profileName)) {
  const normalized = normalizeDeprecatedGlmtEnv(settingsEnv);
  // warn user, validate against direct GLM endpoint, continue through settings flow
}

Remote CLIProxy Flow (v7.1)

Overview

Remote CLIProxy enables CCS to delegate authentication to a central proxy server instead of spawning a local binary.

+===========================================================================+
|                    Remote CLIProxy Architecture (v7.1)                    |
+===========================================================================+

  Config Resolution (proxy-config-resolver.ts)
        |
        +---> Priority: CLI flags > ENV vars > config.yaml > defaults
        |
        v
  +------------------+
  | ResolvedProxyConfig |
  | mode: local|remote |
  +------------------+
        |
        +---> [mode = local] ---> Spawn local CLIProxyAPI binary
        |                              |
        |                              v
        |                        localhost:8317
        |
        +---> [mode = remote] ---> Connect to remote server
                                       |
                                       v
                                 +------------------+
                                 | Health Check     |  remote-proxy-client.ts
                                 | /v1/models       |  2s timeout
                                 +------------------+
                                       |
                                       +---> [reachable] ---> Use remote
                                       |                           |
                                       |                           v
                                       |                      protocol://host:port
                                       |
                                       +---> [unreachable] ---> Fallback decision
                                                                     |
                                       +-----------------------------+
                                       |
                                       +---> [fallbackEnabled] ---> Start local
                                       |
                                       +---> [remoteOnly] ---> Fail with error

  CLI Flags:
    --proxy-host <host>         Remote hostname/IP
    --proxy-port <port>         Port (default: 8317 HTTP, 443 HTTPS)
    --proxy-protocol <proto>    http or https
    --proxy-auth-token <token>  Bearer authentication
    --local-proxy               Force local mode
    --remote-only               Fail if remote unreachable

  Environment Variables:
    CCS_PROXY_HOST              Remote hostname
    CCS_PROXY_PORT              Remote port
    CCS_PROXY_PROTOCOL          Protocol (http/https)
    CCS_PROXY_AUTH_TOKEN        Auth token
    CCS_PROXY_FALLBACK_ENABLED  Enable fallback (true/false)

Configuration Resolution

// proxy-config-resolver.ts: Priority order
const resolved = {
  ...DEFAULT_CONFIG,                    // 4. Defaults (lowest)
  ...yamlConfig,                        // 3. config.yaml
  ...envConfig,                         // 2. Environment variables
  ...cliFlags,                          // 1. CLI flags (highest)
};

Health Check

// remote-proxy-client.ts
async function checkRemoteProxyHealth(config: ResolvedProxyConfig): Promise<boolean> {
  try {
    const url = `${config.protocol}://${config.host}:${config.port}/v1/models`;
    const response = await fetch(url, {
      headers: config.authToken ? { Authorization: `Bearer ${config.authToken}` } : {},
      timeout: 2000,
    });
    return response.ok;
  } catch {
    return false;
  }
}

Quota Management Flow (v7.14)

Overview

Hybrid quota management enables automatic detection of exhausted accounts and failover to next available account. When CCS detects exhaustion and a healthy fallback exists, it also temporarily pauses the exhausted account out of CLIProxy rotation and automatically resumes that pause after the configured cooldown expires.

+===========================================================================+
|                      Quota Management Architecture (v7.14)                |
+===========================================================================+

  Pre-Flight Check (before session start)
        |
        v
  +------------------+
  | quota-manager.ts |  Hybrid quota management
  +------------------+
        |
        +---> Get all active accounts for provider
        |
        +---> For each account:
        |           |
        |           v
        |     +------------------+
        |     | quota-fetcher.ts |  Provider-specific API calls
        |     +------------------+
        |           |
        |           +---> Check isPaused flag --> Skip if paused
        |           |
        |           +---> Fetch quota from provider API
        |           |       - Gemini: /models endpoint
        |           |       - Codex: /api/v1/account
        |           |       - Kiro: /api/usage
        |           |
        |           +---> Detect tier (free/paid/unknown)
        |           |
        |           +---> Check exhaustion status
        |
        +---> Select best account (not paused, not exhausted)
        |
        +---> Auto-failover to next account if current exhausted
        |
        +---> Temporarily pause exhausted account when fallback exists
        |       - move token out of live auth discovery
        |       - persist cooldown expiry across launches
        |       - auto-resume only CCS-created quota pauses

  CLI Commands:
    ccs cliproxy pause <account>   --> Set isPaused=true in account-manager
    ccs cliproxy resume <account>  --> Set isPaused=false
    ccs cliproxy status [account]  --> Display quota + tier info

  Dashboard UI:
    - Pause/Resume toggle per account
    - Tier badge (free/paid/unknown)
    - Quota usage display

Account Selection Algorithm

// quota-manager.ts: Best account selection
function selectBestAccount(accounts: AccountInfo[]): AccountInfo | null {
  // Priority:
  // 1. Not paused
  // 2. Not exhausted
  // 3. Paid tier over free tier
  // 4. Highest remaining quota

  return accounts
    .filter(acc => !acc.isPaused && !acc.isExhausted)
    .sort((a, b) => {
      if (a.tier !== b.tier) return (a.tier === 'paid' ? -1 : 1);
      return (b.remainingQuota || 0) - (a.remainingQuota || 0);
    })[0] || null;
}

Authentication Flow

OAuth Providers - Authorization Code Flow

Providers: Gemini, Codex, Antigravity, Kiro (aws method)

+===========================================================================+
|              OAuth - Authorization Code Flow (Port-based)                 |
+===========================================================================+

  1. User runs: ccs codex
        |
        v
  2. Check token cache (~/.ccs/cliproxy/auth/)
        |
        +---> [Valid token] ---> Use cached token
        |
        +---> [No/Expired token]
                    |
                    v
  3. Start local OAuth server (localhost:9876)
        |
        v
  4. Open browser with OAuth request
        |     https://oauth-provider/authorize?redirect_uri=http://localhost:9876/callback
        v
  5. User authorizes in browser
        |
        v
  6. OAuth provider redirects to localhost:9876/callback?code=XXXX
        |
        v
  7. Exchange auth code for access token
        |
        v
  8. Cache token locally (~/.ccs/cliproxy/auth/gemini.json)
        |
        v
  9. Proceed with Claude CLI

OAuth Providers - Device Code Flow

Providers: GitHub Copilot (ghcp)

Provider identity note:

  • Providers that do not expose a reliable email no longer require a manual nickname during first auth.
  • CCS derives a stable internal account identifier from the token/cache context and still allows the user to rename the account later.
+===========================================================================+
|               OAuth - Device Code Flow (No Port Needed)                   |
+===========================================================================+

  1. User runs: ccs ghcp
        |
        v
  2. Check token cache (~/.ccs/cliproxy/auth/)
        |
        +---> [Valid token] ---> Use cached token
        |
        +---> [No/Expired token]
                    |
                    v
  3. Request device code from GitHub
        |
        v
  4. Display user code + verification URL
        |     "Enter code XXXX-XXXX at github.com/login/device"
        v
  5. User opens URL in browser and enters code
        |
        v
  6. Poll GitHub for token completion
        |
        v
  7. Receive and cache token locally
        |
        v
  8. Proceed with Claude CLI

Kiro OAuth - Method-Aware Flow

Supported methods:

  • aws: Device Code (default, AWS org friendly)
  • aws-authcode: Authorization Code via CLI flow
  • google: Social OAuth via management API
  • github: Social OAuth via management API (Dashboard flow)
+===========================================================================+
|                    Kiro OAuth - Method-Aware Flow                         |
+===========================================================================+

  Configuration:
    ccs_profile:
      target: claude
      cliproxy:
        provider: kiro
        kiro_method: aws  # or aws-authcode, google, github

  Flow:
    Device Code (aws)
      → /start endpoint (no callback port)
      → Opens browser
      → User enters code
      → Poll /status

    Authorization Code (aws-authcode, google, github)
      → /start-url endpoint
      → Returns auth_url
      → User visits URL
      → Callback handled
      → Poll /status for completion

  Key behavior:
    - Device Code method uses /start route (no callback port)
    - Callback/social methods use /start-url + status polling
    - Some management flows return state first, auth_url later
    - Manual nicknames are optional when the upstream provider does not return an email
    - Account storage uses a stable internal identifier so reauth/update flows do not depend on dashboard list order

API Key Profiles (GLM, Kimi)

+===========================================================================+
|                     API Key Profile (Non-OAuth)                          |
+===========================================================================+

  1. User configures API key in settings
        |
        v
  2. Key stored in ~/.ccs/<profile>.settings.json
        |
        v
  3. Profile detection: APIKeyProfile
        |
        v
  4. Key passed via ANTHROPIC_AUTH_TOKEN env var
        |
        v
  5. Target adapter (Claude/Droid) handles delivery
        |
        └─ Claude: env var
        └─ Droid: config file (~/.factory/settings.json)

Anthropic Direct API Key

+===========================================================================+
|                  Anthropic Direct API Key (Native Auth)                   |
+===========================================================================+

  1. User creates profile: ccs api create --preset anthropic
        |
        v
  2. Key stored in ~/.ccs/<profile>.settings.json
        |  env: { ANTHROPIC_API_KEY: "sk-ant-..." }
        |  (NO ANTHROPIC_BASE_URL, NO ANTHROPIC_AUTH_TOKEN)
        v
  3. Profile detection: settings-based
        |
        v
  4. Key passed via ANTHROPIC_API_KEY env var
        |  Claude CLI uses native endpoint (api.anthropic.com)
        v
  5. Claude CLI authenticates with x-api-key header

  Detection logic (profile-writer.ts):
    - apiKey.startsWith('sk-ant-') -> native mode
    - baseUrl.includes('api.anthropic.com') -> native mode
    - Otherwise -> proxy mode (existing behavior)

Image Analysis Hook Flow (v7.34)

Overview

Image Analysis Hook enables vision model proxying through CLIProxy with automatic injection for all profile types.

+===========================================================================+
|                    Image Analysis Hook Flow (v7.34)                       |
+===========================================================================+

  Claude CLI with image input
        |
        v
  Hook Installer (ensureProfileHooks)
        |
        +---> Check ~/.claude/hooks/openai-vision-hook.cjs exists
        |
        +---> If missing: auto-install via image-analyzer-hook-installer
        |
        v
  Hook Configuration
        |
        +---> Set ANTHROPIC_IMAGE_HOOK_URL
        |           (proxy endpoint URL)
        |
        v
  Claude CLI processes image request
        |
        v
  Claude prefers ImageAnalysis MCP tool
        |
        v
  CCS provider-backed image analysis
        |
        +---> Provider route resolved before launch
        |
        +---> Direct request to /api/provider/<backend>/v1/messages
        |
        +---> Native Read fallback if runtime/auth/proxy is unavailable
        |
        v
  Text description returned to Claude CLI

Runtime Environment

// getImageAnalysisHookEnv()
{
  CCS_IMAGE_ANALYSIS_RUNTIME_BASE_URL: 'http://127.0.0.1:8317',
  CCS_IMAGE_ANALYSIS_RUNTIME_PATH: '/api/provider/agy',
  CCS_IMAGE_ANALYSIS_RUNTIME_API_KEY: 'ccs-internal-managed',
}

Provider Support

Provider Vision Support Notes
Gemini Via CCS ImageAnalysis provider route
Codex Via CCS ImageAnalysis provider route
Antigravity Via CCS ImageAnalysis provider route
Kiro Via mapped CCS provider route when configured
Copilot Via mapped ghcp provider route
GLM/Kimi Via explicit or fallback backend mapping

Session Tracking

All execution paths record session metadata including target CLI used:

{
  profileName: 'gemini',
  profileType: 'clipproxy',
  provider: 'google-gemini',
  targetCli: 'claude',        // NEW: which target was used
  timestamp: '2026-02-16T10:40:00Z',
  duration: 12345,
  exitCode: 0,
  model: 'claude-opus-4-6',
}

This enables analytics on target CLI usage and adoption.