Repository navigation
feat(ccs): add CCS accounts registry configuration #596
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
52dae47
91dcbcb
2f96add
0503162
0cac924
48df057
caa22e4
a7b86e4
fea0cce
c8350db
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| { | ||
| "version": 1, | ||
| "providers": { | ||
| "agy": { | ||
| "default": "shunkakinoki@gmail.com", | ||
| "accounts": { | ||
| "shunkakinoki@gmail.com": { | ||
| "email": "shunkakinoki@gmail.com", | ||
| "nickname": "shunkakinoki", | ||
| "tokenFile": "antigravity-shunkakinoki_gmail_com.json", | ||
| "createdAt": "2026-01-17T00:00:00.000Z", | ||
| "lastUsedAt": "2026-01-17T19:28:18.251Z", | ||
| "tier": "paid" | ||
| } | ||
| } | ||
| }, | ||
| "gemini": { | ||
| "default": "shunkakinoki@gmail.com", | ||
| "accounts": { | ||
| "shunkakinoki@gmail.com": { | ||
| "email": "shunkakinoki@gmail.com", | ||
| "nickname": "shunkakinoki", | ||
| "tokenFile": "gemini-shunkakinoki@gmail.com-gen-lang-client-0359793614.json", | ||
| "createdAt": "2026-01-12T00:00:00.000Z", | ||
| "lastUsedAt": "2026-01-12T00:00:00.000Z" | ||
| } | ||
| } | ||
| }, | ||
| "codex": { | ||
| "default": "shunkakinoki@gmail.com", | ||
| "accounts": { | ||
| "shunkakinoki@gmail.com": { | ||
| "email": "shunkakinoki@gmail.com", | ||
| "nickname": "shunkakinoki", | ||
| "tokenFile": "codex-shunkakinoki@gmail.com.json", | ||
| "createdAt": "2025-12-18T00:00:00.000Z", | ||
| "lastUsedAt": "2025-12-18T00:00:00.000Z" | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
Comment on lines
+1
to
+42
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Committing a file with hardcoded personal information like your email address and nickname is a security risk, as it exposes Personally Identifiable Information (PII). It also makes the configuration harder to maintain and less portable. It's much better to generate this file dynamically from your Nix configuration, using variables that are already defined elsewhere (like
Comment on lines
+1
to
+42
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| { | ||
| "env": { | ||
| "ANTHROPIC_BASE_URL": "http://127.0.0.1:8317/api/provider/agy", | ||
| "ANTHROPIC_AUTH_TOKEN": "__CLIPROXY_API_KEY__", | ||
| "ANTHROPIC_MODEL": "claude-opus-4-5-thinking", | ||
| "ANTHROPIC_DEFAULT_OPUS_MODEL": "claude-opus-4-5-thinking", | ||
| "ANTHROPIC_DEFAULT_SONNET_MODEL": "claude-opus-4-5-thinking", | ||
| "ANTHROPIC_DEFAULT_HAIKU_MODEL": "claude-sonnet-4-5" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| { | ||
| "env": { | ||
| "ANTHROPIC_BASE_URL": "http://127.0.0.1:8317/api/provider/codex", | ||
| "ANTHROPIC_AUTH_TOKEN": "__CLIPROXY_API_KEY__", | ||
| "ANTHROPIC_MODEL": "gpt-5.1-codex-max", | ||
| "ANTHROPIC_DEFAULT_OPUS_MODEL": "gpt-5.1-codex-max-high", | ||
| "ANTHROPIC_DEFAULT_SONNET_MODEL": "gpt-5.1-codex-max", | ||
| "ANTHROPIC_DEFAULT_HAIKU_MODEL": "gpt-5.1-codex-mini-high" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,131 @@ | ||
| # CCS Unified Configuration | ||
| # Docs: https://github.com/kaitranntt/ccs | ||
| version: 7 | ||
| # ---------------------------------------------------------------------------- | ||
| # Accounts: Isolated Claude instances (each with separate auth/sessions) | ||
| # Manage with: ccs auth add <name>, ccs auth list, ccs auth remove <name> | ||
| # ---------------------------------------------------------------------------- | ||
| accounts: {} | ||
| # ---------------------------------------------------------------------------- | ||
| # Profiles: API-based providers (GLM, GLMT, Kimi, custom endpoints) | ||
| # Each profile points to a *.settings.json file containing env vars. | ||
| # Edit the settings file directly to customize (ANTHROPIC_MAX_TOKENS, etc.) | ||
| # ---------------------------------------------------------------------------- | ||
| profiles: {} | ||
| # ---------------------------------------------------------------------------- | ||
| # CLIProxy: OAuth-based providers (gemini, codex, agy, qwen, iflow) | ||
| # Each variant can reference a *.settings.json file for custom env vars. | ||
| # Edit the settings file directly to customize model or other settings. | ||
| # ---------------------------------------------------------------------------- | ||
| cliproxy: | ||
| oauth_accounts: {} | ||
| providers: | ||
| - gemini | ||
| - codex | ||
| - agy | ||
| - qwen | ||
| - iflow | ||
| - kiro | ||
| - ghcp | ||
| variants: {} | ||
| logging: | ||
| enabled: false | ||
| request_log: false | ||
| # ---------------------------------------------------------------------------- | ||
| # CLIProxy Server: Remote proxy connection settings | ||
| # Configure via Dashboard (`ccs config`) > Proxy tab. | ||
| # | ||
| # remote: Connect to a remote CLIProxyAPI instance | ||
| # fallback: Use local proxy if remote is unreachable | ||
| # local: Local proxy settings (port, auto-start) | ||
| # ---------------------------------------------------------------------------- | ||
| cliproxy_server: | ||
| remote: | ||
| enabled: true | ||
| host: 127.0.0.1 | ||
| port: 8317 | ||
| protocol: http | ||
| auth_token: __CLIPROXY_API_KEY__ | ||
| fallback: | ||
| enabled: true | ||
| auto_start: false | ||
| local: | ||
| port: 8317 | ||
| auto_start: false | ||
| # ---------------------------------------------------------------------------- | ||
| # Preferences: User settings | ||
| # ---------------------------------------------------------------------------- | ||
| preferences: | ||
| theme: system | ||
| telemetry: false | ||
| auto_update: true | ||
| # ---------------------------------------------------------------------------- | ||
| # WebSearch: CLI-based web search for third-party profiles | ||
| # Dashboard (`ccs config`) is the source of truth for provider selection. | ||
| # | ||
| # Third-party providers (gemini, codex, agy, etc.) do not have access to | ||
| # Anthropic's WebSearch tool. These CLI tools provide fallback web search. | ||
| # | ||
| # Fallback chain: Gemini -> OpenCode -> Grok (tries in order until success) | ||
| # | ||
| # Gemini models: gemini-2.5-flash (default), gemini-2.5-pro, gemini-2.5-flash-lite | ||
| # OpenCode models: opencode/grok-code (default), opencode/gpt-4o, opencode/claude-3.5-sonnet | ||
| # | ||
| # Install commands: | ||
| # gemini: npm i -g @google/gemini-cli (FREE - 1000 req/day) | ||
| # opencode: curl -fsSL https://opencode.ai/install | bash (FREE via Zen) | ||
| # grok: npm i -g @vibe-kit/grok-cli (requires GROK_API_KEY) | ||
| # ---------------------------------------------------------------------------- | ||
| websearch: | ||
| enabled: true | ||
| providers: | ||
| gemini: | ||
| enabled: true | ||
| model: gemini-2.5-flash | ||
| timeout: 55 | ||
| opencode: | ||
| enabled: false | ||
| model: opencode/grok-code | ||
| timeout: 90 | ||
| grok: | ||
| enabled: false | ||
| timeout: 55 | ||
| # ---------------------------------------------------------------------------- | ||
| # Copilot: GitHub Copilot API proxy (via copilot-api) | ||
| # Uses your existing GitHub Copilot subscription with Claude Code. | ||
| # | ||
| # !! DISCLAIMER - USE AT YOUR OWN RISK !! | ||
| # This uses an UNOFFICIAL reverse-engineered API. | ||
| # Excessive usage may trigger GitHub account restrictions. | ||
| # CCS provides NO WARRANTY and accepts NO RESPONSIBILITY for consequences. | ||
| # | ||
| # Setup: npx copilot-api auth (authenticate with GitHub) | ||
| # Usage: ccs copilot (switch to copilot profile) | ||
| # | ||
| # Models: claude-sonnet-4.5, claude-opus-4.5, gpt-5.1, gemini-2.5-pro | ||
| # Account types: individual, business, enterprise | ||
| # ---------------------------------------------------------------------------- | ||
| copilot: | ||
| enabled: false | ||
| auto_start: false | ||
| port: 4141 | ||
| account_type: individual | ||
| rate_limit: null | ||
| wait_on_limit: true | ||
| model: gpt-4.1 | ||
| # ---------------------------------------------------------------------------- | ||
| # Global Environment Variables: Injected into all non-Claude subscription profiles | ||
| # These env vars disable telemetry/reporting for third-party providers. | ||
| # Configure via Dashboard (`ccs config`) > Global Env tab. | ||
| # | ||
| # Default variables: | ||
| # DISABLE_BUG_COMMAND: Disables /bug command (not supported by proxy) | ||
| # DISABLE_ERROR_REPORTING: Disables error reporting to Anthropic | ||
| # DISABLE_TELEMETRY: Disables usage telemetry | ||
| # ---------------------------------------------------------------------------- | ||
| global_env: | ||
| enabled: true | ||
| env: | ||
| DISABLE_BUG_COMMAND: "1" | ||
| DISABLE_ERROR_REPORTING: "1" | ||
| DISABLE_TELEMETRY: "1" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| { | ||
| config, | ||
| lib, | ||
| pkgs, | ||
| ... | ||
| }: | ||
| let | ||
| dotfilesDir = "${config.home.homeDirectory}/dotfiles"; | ||
|
|
||
| # Hydration script for CCS provider settings | ||
| hydrateScript = pkgs.replaceVars ./hydrate.sh { | ||
| sed = "${pkgs.gnused}/bin/sed"; | ||
| }; | ||
| in | ||
| { | ||
| # CCS (Claude Code Switcher) account registry | ||
| # Maps OAuth token files to registered accounts for cliproxy providers | ||
| # Token files are stored separately in ~/.ccs/cliproxy/auth/ (not managed here as they contain secrets) | ||
| # Note: Using mkOutOfStoreSymlink with absolute path so CCS can write to the file (updates lastUsedAt) | ||
| home.file.".ccs/cliproxy/accounts.json" = { | ||
| source = config.lib.file.mkOutOfStoreSymlink "${dotfilesDir}/config/ccs/accounts.json"; | ||
| force = true; | ||
| }; | ||
|
|
||
| # Hydrate CCS settings templates with secrets from .env | ||
| # ANTHROPIC_AUTH_TOKEN is substituted from CLIPROXY_API_KEY at activation time | ||
| # Processes all *.settings.template.json files in config/ccs/ | ||
| home.activation.hydrateCcsSettings = lib.hm.dag.entryAfter [ "writeBoundary" ] '' | ||
| ${pkgs.bash}/bin/bash ${hydrateScript} || true | ||
| ''; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| { | ||
| "env": { | ||
| "ANTHROPIC_BASE_URL": "http://127.0.0.1:8317/api/provider/gemini", | ||
| "ANTHROPIC_AUTH_TOKEN": "__CLIPROXY_API_KEY__", | ||
| "ANTHROPIC_MODEL": "gemini-2.5-pro", | ||
| "ANTHROPIC_DEFAULT_OPUS_MODEL": "gemini-2.5-pro", | ||
| "ANTHROPIC_DEFAULT_SONNET_MODEL": "gemini-2.5-pro", | ||
| "ANTHROPIC_DEFAULT_HAIKU_MODEL": "gemini-2.5-flash" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| #!/usr/bin/env bash | ||
| # Hydrate CCS provider settings and config from templates | ||
| # Substitutes __CLIPROXY_API_KEY__ placeholder with actual API key from .env | ||
| # shellcheck source=/dev/null | ||
| set -euo pipefail | ||
|
|
||
| DOTFILES_DIR="${HOME}/dotfiles" | ||
| CCS_DIR="${HOME}/.ccs" | ||
| TEMPLATE_DIR="${DOTFILES_DIR}/config/ccs" | ||
| ENV_FILE="${DOTFILES_DIR}/.env" | ||
|
|
||
| # Load environment variables | ||
| if [ -f "$ENV_FILE" ]; then | ||
| set -a | ||
| . "$ENV_FILE" | ||
| set +a | ||
| fi | ||
|
|
||
| # Check for required API key | ||
| if [ -z "${CLIPROXY_API_KEY:-}" ]; then | ||
| echo "Warning: CLIPROXY_API_KEY not set in .env, skipping CCS hydration" >&2 | ||
| exit 0 | ||
| fi | ||
|
|
||
| mkdir -p "$CCS_DIR" | ||
|
|
||
| # Hydrate config.yaml | ||
| CONFIG_TEMPLATE="${TEMPLATE_DIR}/config.template.yaml" | ||
| if [ -f "$CONFIG_TEMPLATE" ]; then | ||
| @sed@ \ | ||
| -e "s|__CLIPROXY_API_KEY__|${CLIPROXY_API_KEY}|g" \ | ||
| "$CONFIG_TEMPLATE" >"${CCS_DIR}/config.yaml" | ||
| echo "Hydrated CCS config.yaml" >&2 | ||
| fi | ||
|
|
||
| # Process all provider settings templates | ||
| for template in "$TEMPLATE_DIR"/*.settings.template.json; do | ||
| [ -f "$template" ] || continue | ||
|
|
||
| # Extract provider name: foo.settings.template.json -> foo | ||
| filename=$(basename "$template") | ||
| provider="${filename%.settings.template.json}" | ||
| output="${CCS_DIR}/${provider}.settings.json" | ||
|
|
||
| # Substitute placeholder and write output | ||
| @sed@ \ | ||
| -e "s|__CLIPROXY_API_KEY__|${CLIPROXY_API_KEY}|g" \ | ||
| "$template" >"$output" | ||
|
|
||
| echo "Hydrated CCS ${provider}.settings.json" >&2 | ||
| done |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,7 +12,8 @@ remote-management: | |
| # Disable the bundled management control panel asset download and HTTP route when true. | ||
| disable-control-panel: false | ||
| # Authentication directory (supports ~ for home directory). If you use Windows, please set the directory like this: `C:/cli-proxy-api/` | ||
| auth-dir: "~/.cli-proxy-api" | ||
| # Use objectstore/auths subdirectory to avoid duplicate scanning (root-level files are legacy) | ||
| auth-dir: "~/.cli-proxy-api/objectstore/auths" | ||
|
Comment on lines
+15
to
+16
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # Search for migration documentation or guides related to this change
rg -i "migration\|migrate" --type=md --type=txt -A 2 -B 2Repository: shunkakinoki/dotfiles Length of output: 47 🏁 Script executed: # Check for objectstore/auths references in documentation
rg "objectstore/auths|cli-proxy-api" --type=md --type=txt --type=nix -C 2Repository: shunkakinoki/dotfiles Length of output: 3185 🏁 Script executed: # Check the actual YAML file for context and formatting
cat -n config/cliproxyapi/config.yaml | head -30Repository: shunkakinoki/dotfiles Length of output: 1807 🏁 Script executed: # Look for README or migration guides in the repo
fd -t f -i "readme\|migration\|changelog" -E node_modulesRepository: shunkakinoki/dotfiles Length of output: 47 Add migration guidance for legacy auth files. The README documents that 🤖 Prompt for AI Agents
Comment on lines
+15
to
+16
|
||
| # API keys for client authentication (optional - leave commented for open access) | ||
| # api-keys: | ||
| # - "__CLIPROXY_API_KEY__" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,6 @@ | ||
| [ | ||
| ./amp | ||
| ./ccs | ||
| ./cliproxyapi | ||
| ./codex | ||
| ./crush | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -105,7 +105,8 @@ Describe 'no shell scripts are missing from coverage list' | |
| It 'covers all non-spec shell scripts in the repository' | ||
| # List of all shell scripts that should have tests | ||
| # Update this list when adding new shell scripts | ||
| covered_scripts="config/claude/notify.sh | ||
| covered_scripts="config/ccs/hydrate.sh | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: New script config/ccs/hydrate.sh added to coverage list but missing corresponding spec-file assertion; coverage test won’t enforce a test exists for it. Prompt for AI agents |
||
| config/claude/notify.sh | ||
| config/claude/pushover.sh | ||
| config/claude/security.sh | ||
| config/claude/statusline-git.sh | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The email address in the tokenFile is inconsistent with the format used in other providers. For the gemini provider, the tokenFile uses "@" symbol ("gemini-shunkakinoki@gmail.com-gen-lang-client-0359793614.json"), while for the agy provider it uses an underscore-separated format ("antigravity-shunkakinoki_gmail_com.json"). This inconsistency could lead to confusion when managing token files. Consider standardizing the token file naming convention across all providers.