Files and storage
claude-code-proxy separates configuration and credentials from runtime state.
Directory roots
Section titled “Directory roots”| Platform | Configuration root | State root |
|---|---|---|
| macOS, Linux, Windows native builds | ${XDG_CONFIG_HOME:-<home>/.config}/claude-code-proxy |
${XDG_STATE_HOME:-<home>/.local/state}/claude-code-proxy |
| Docker | /var/lib/claude-code-proxy/config |
/var/lib/claude-code-proxy/state/claude-code-proxy |
<home> is HOME, falling back to USERPROFILE. The current native resolver uses these XDG-style paths on all three platforms; Windows builds do not automatically select APPDATA or LOCALAPPDATA. The notation above describes defaults, not Windows shell syntax.
CCP_CONFIG_DIR replaces the configuration root for the current process, including legacy credential and Kimi device identity fallback and logout. It does not change the state root. Set XDG_STATE_HOME separately when logs and captures must also be isolated. Without an explicit override, legacy credential migration remains available.
Configuration
Section titled “Configuration”config.json lives directly under the configuration root. See Configuration for its schema and precedence.
Provider credentials
Section titled “Provider credentials”Provider logins are saved to <configuration-root>/<provider>/auth.json. On macOS, Codex and Cursor can also read older proxy-owned Keychain entries when no CCP_CONFIG_DIR override is set:
claude-code-proxy.codexclaude-code-proxy.cursor
The credential file takes precedence over a Keychain entry. The current implementation saves new or refreshed credentials to files; Keychain writes are unavailable in its compatibility mode. File-backed credentials are written with restrictive permissions where supported. Linux and Windows use the same provider file layout without this macOS compatibility lookup.
When CCP_CONFIG_DIR is set, file-backed provider credentials use
<CCP_CONFIG_DIR>/<provider>/auth.json, including Codex and Cursor on macOS.
CCP_CURSOR_AUTH_TOKEN bypasses Cursor’s local credential store for that
process.
OpenCode Go is the exception: it reads its API key from
CCP_OPENCODE_API_KEY, OPENCODE_API_KEY, or opencode.apiKey in
config.json and does not create a provider auth store.
The proxy owns these credentials independently of native Codex, Grok, and Cursor Agent stores.
Separate runtime profiles
Section titled “Separate runtime profiles”Use a dedicated CCP_CONFIG_DIR for an independent proxy instance, including a container deployment, and authenticate that profile explicitly. The root must remain writable because token refresh replaces credential files atomically. Keep Kimi’s device ID with its login.
A Linux container cannot use the host’s macOS Keychain directly. A read-only credential mount also cannot persist refreshed tokens. Avoid running host and container proxies against the same writable login files: refresh coordination is currently in process, so independent processes can race when rotating tokens. Prefer one credential writer per profile.
Kimi device ID
Section titled “Kimi device ID”Kimi stores a persistent UUID at <configuration-root>/kimi/device_id for file-backed setups. It is bound into the Kimi token and must remain paired with that login.
Structured log
Section titled “Structured log”proxy.log lives under the state root. It uses JSON Lines and rotates at 20 MiB. Known credential keys, including authorization, access tokens, refresh tokens, ID tokens, and account headers, are redacted before writing.
When running under a service manager, configure stdout and stderr destinations
there; the proxy does not create a separate service.log.
Failed responses
Section titled “Failed responses”errors/ under the state root contains JSON files for failed proxy responses. A request_failed log event includes errorFile, which points to the complete redacted payload.
Error payloads are safer to share than raw traffic captures, but inspect their prompt-derived content and paths before publishing them.
Traffic captures
Section titled “Traffic captures”Set CCP_TRAFFIC_LOG=1 to create captures under traffic/ in the state root. Requests are grouped by Claude Code session and request sequence. A request directory can include:
- inbound Anthropic request and metadata
- translated upstream request
- upstream URL and redacted headers
- raw or decoded upstream events
- translated downstream events and response
- transport or reducer error details
Event filenames use monotonic sequence numbers so lexical order preserves emission order.
Enable capture only for a focused reproduction, keep the directory local, and delete it after the investigation.
Local setup files
Section titled “Local setup files”The active configuration root contains these setup files:
| File | Purpose |
|---|---|
ui-access.json |
Private management bearer key, reused across restarts |
session-profile.json |
Versioned four-role selections and client session preferences, saved atomically |
ui-runtime.json |
Running instance address and version |
ui-instance.lock |
Single server ownership of this profile |
ui-key.lock |
Coordination between CLI bootstrap and server key creation |
Provider credentials retain the files described above. Docker stores configuration under /var/lib/claude-code-proxy/config and application state under /var/lib/claude-code-proxy/state/claude-code-proxy, in one named profile volume. Protect backups of that volume as credentials. See Docker setup and updates for recreation, image replacement, and volume removal behavior.