> ## Documentation Index
> Fetch the complete documentation index at: https://docs.codezero.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Claude Code

> Set up cordon to give Claude Code secure API access without exposing secrets.

Cordon integrates with [Claude Code](https://docs.anthropic.com/en/docs/claude-code) so your AI agent can make authenticated API calls without holding real credentials.

<Warning>
  Cordon can inject an `ANTHROPIC_API_KEY` for Claude's API access, but this requires adding a route for `api.anthropic.com` and setting a dummy `ANTHROPIC_API_KEY` env var — see [API key setup](#api-key-setup). If you use Claude Code with a Claude Pro/Team/Enterprise subscription (OAuth login), Anthropic API credential injection won't apply — Claude Code authenticates directly via OAuth, bypassing the proxy. This limitation applies only to Claude's own authentication; cordon supports `header` and `basic` auth types for routes to other APIs. Support for OAuth-based subscriptions is coming soon.
</Warning>

## Scope

Claude Code setup defaults to **project scope**: `cordon.toml` lives in `$CWD`, and settings are written to `$CWD/.claude/settings.local.json`. This keeps credentials and proxy configuration isolated per repository and per checkout — `settings.local.json` is Claude Code's gitignored-by-convention override file, so git worktrees do not inherit stale proxy env vars from a tracked `settings.json`.

To share a single cordon configuration across all projects, use **user scope**:

```bash theme={null}
cordon setup claude-code --scope user
```

User scope writes settings to `$HOME/.claude/settings.json` and stores config at `$XDG_CONFIG_HOME/cordon/cordon.toml`. See [Scopes](/configuration/overview#scopes) for path details and trade-offs.

## Automated setup

The fastest way to get started:

```bash theme={null}
cordon setup claude-code
```

This:

1. Generates CA certificates (if not already present)
2. Creates a scaffold `cordon.toml`
3. Generates the standard proxy and CA env vars from [`cordon env`](/cli/env)
4. Configures Claude Code's settings file (`.claude/settings.local.json` for project scope, `~/.claude/settings.json` for user scope) and adds `NODE_OPTIONS` when the Node bootstrap loader is discoverable
5. Installs a [health-check hook](#health-check-hook) that blocks Claude Code when cordon is not running
6. Installs a cordon agent skill (`.claude/skills/cordon/SKILL.md` for project scope, `~/.claude/skills/cordon/SKILL.md` for user scope)
7. Offers to add routes and store secrets interactively (post-setup wizard)

Any existing settings file is backed up to `<name>.cordon.bak` before any changes are made. If setup detects cordon env vars in a project's tracked `settings.json` (from a pre-fix install), they are migrated into `settings.local.json` automatically during the next `cordon setup claude-code` run.

To run cordon as a background service, run `cordon service install` after setup (add `--scope user` if you set up Claude Code with `--scope user`).

### Remove the setup

```bash theme={null}
cordon integration disable claude-code
```

## Sandbox configuration (macOS)

Claude Code runs tools in a macOS sandbox that manages proxy env var propagation to subprocesses. The sandbox must be **enabled** for `HTTP_PROXY`/`HTTPS_PROXY` env vars (set in your settings file) to reach tools like curl, wget, and gh. When the sandbox is disabled, these env vars are not propagated — requests bypass cordon entirely and no credential injection occurs.

`cordon setup claude-code` configures these settings automatically. The resulting sandbox configuration in your Claude Code settings file (`.claude/settings.local.json` for project scope, `~/.claude/settings.json` for user scope) looks like:

```json theme={null}
{
  "sandbox": {
    "enabled": true,
    "autoAllowBashIfSandboxed": true,
    "network": {
      "allowLocalBinding": true,
      "allowedDomains": ["127.0.0.1"]
    }
  }
}
```

* **`enabled: true`** activates the sandbox and its proxy env var propagation pipeline. Without this, subprocesses will not receive proxy env vars and cordon credential injection will silently fail.
* **`autoAllowBashIfSandboxed: true`** allows Bash commands to run without individual permission prompts when the sandbox is active.
* **`allowLocalBinding: true`** and **`allowedDomains: ["127.0.0.1"]`** permit sandboxed processes to connect to Cordon's loopback listener.

### Go-based tools (`gh`, `terraform`, `kubectl`, `gcloud`)

If you use Go-based CLI tools through Claude Code's sandbox, you also need `enableWeakerNetworkIsolation`. Go binaries use Apple's Security.framework for TLS certificate verification, which delegates to the `trustd` daemon via Mach IPC. The sandbox blocks this by default, causing `OSStatus -26276` errors. This must be added manually — `cordon setup claude-code` does not set it by default because it reduces sandbox isolation.

```json theme={null}
{
  "sandbox": {
    "enabled": true,
    "autoAllowBashIfSandboxed": true,
    "enableWeakerNetworkIsolation": true,
    "network": {
      "allowLocalBinding": true,
      "allowedDomains": ["127.0.0.1"]
    }
  }
}
```

`enableWeakerNetworkIsolation` allows sandboxed processes to communicate with `com.apple.trustd.agent`. It is strictly more secure than disabling the entire sandbox with `dangerouslyDisableSandbox: true`, but it does [reduce isolation](https://code.claude.com/docs/en/settings) by opening access to the system TLS trust service. Only add it if you need Go-based tools to work through the proxy.

Users who only use curl, npm, or Node.js tools through the sandbox do **not** need `enableWeakerNetworkIsolation`.

<Warning>
  Sandbox settings are applied when Claude Code launches. After changing these settings, you must restart Claude Code for them to take effect.
</Warning>

## Adding routes

<Note>
  The `cordon route`, `cordon start`, and `cordon service` commands below default to **project scope**. If you set up Claude Code with `--scope user`, append `--scope user` to each of these commands so they target `~/.config/cordon/cordon.toml` instead of `./cordon.toml`.
</Note>

After setup, add a route for your API provider. Claude Code's own Anthropic API-key path uses `x-api-key`:

```bash theme={null}
cordon route add --name anthropic --host api.anthropic.com \
  --auth-type header --header-name x-api-key \
  --source keyring --account anthropic-api-key
```

Anthropic uses a raw `x-api-key` header. For bearer-style APIs, set the `Authorization` header with a scheme. For example, to add a GitHub API route:

```bash theme={null}
cordon route add --host api.github.com --auth-type header --header-name Authorization --scheme Bearer --source keyring --account github
```

If you chose keyring as the secret source, store the secret using the account name from the route:

```bash theme={null}
cordon secret set <account>
```

See [Routes](/configuration/routes#provider-auth-quick-reference) for provider auth types, dummy-key behavior, and route change restart guidance.

## API key setup

Claude Code needs an API key env var set so it selects the API key auth path. Add a placeholder to your settings file — `.claude/settings.local.json` for project scope or `~/.claude/settings.json` for user scope:

```json theme={null}
{
  "env": {
    "ANTHROPIC_API_KEY": "dummy-replaced-by-cordon"
  }
}
```

Cordon strips this dummy key and injects the real one from your secret store at the network layer.

## Manual setup

Prefer `cordon setup claude-code` for Claude Code configuration. It writes the proxy, CA, sandbox, and health-check settings consistently and backs up existing files before changing them. If setup cannot cover your environment, add the values from [`cordon env`](/cli/env) to Claude Code's `env` settings. For project scope, write `.claude/settings.local.json`; for user scope, write `~/.claude/settings.json`.

The settings shape is:

```json theme={null}
{
  "env": {
    "HTTPS_PROXY": "http://127.0.0.1:<PORT>",
    "NODE_EXTRA_CA_CERTS": "/path/to/ca-cert.pem",
    "SSL_CERT_FILE": "/path/to/combined-ca.pem"
  }
}
```

Use [Any tool (generic)](/guides/generic) for the full env-var contract, [TLS](/configuration/tls#troubleshooting-certificate-errors) for certificate errors, and [SDK Compatibility](/guides/sdk-compatibility#node-register-import) for Node's bootstrap loader.

## Workflow

Once configured, the workflow is:

1. Start cordon: `cordon start` (or use the background service)
2. Start Claude Code as usual
3. When Claude Code makes API calls to configured hosts, cordon transparently injects credentials
4. Claude Code never sees or logs real API keys

<Tip>
  Use `cordon doctor` to diagnose any setup issues. It checks config validity, cert paths, trust store status, and port availability.
</Tip>

## Health-check hook

When `cordon setup claude-code` runs, it installs a `UserPromptSubmit` hook that checks whether cordon is responding before every message you send. If cordon is configured but not running, the hook **blocks the message** and shows an error — preventing you from sitting through repeated `ConnectionRefused` retries with no explanation.

The hook runs `cordon status -q`, a fast health check (50ms timeout with one retry) that exits 0 if cordon is healthy and 1 if not.

### What you see when cordon is down

```
Cordon proxy is not running. Run `cordon start` or remove the hook.
```

The hook exits with code 2, which blocks the message. The `!` prefix runs shell commands directly from Claude Code's prompt without going through the AI — use it to start cordon or remove the integration even while the hook is blocking.

### Recovery options

| Option             | Command                                          | Notes                                                                              |
| ------------------ | ------------------------------------------------ | ---------------------------------------------------------------------------------- |
| Start as service   | `! cordon service start`                         | Requires prior `cordon service install`. Runs in background.                       |
| Start manually     | `cordon start` (separate terminal)               | Foreground process — keeps running until you Ctrl+C.                               |
| Remove integration | `! cordon integration disable claude-code --yes` | Removes proxy env vars, hook, and skill. Restart session with `claude --continue`. |

<Note>
  Hooks are loaded when Claude Code starts. If you install or remove the hook mid-session, restart with `claude --continue` for the change to take effect.
</Note>

### Hook details

* **Project scope**: script is installed at `.claude/cordon-status-hook.sh` in the project directory
* **User scope**: script is installed at `~/.config/cordon/hooks/claude-code-status.sh`
* The hook entry is added to `settings.local.json` (project) or `~/.claude/settings.json` (user) under `hooks.UserPromptSubmit`
* The hook appends to existing hooks — it does not overwrite any `UserPromptSubmit` hooks you already have
* Running setup again is idempotent — if the hook is already installed, it prints "Hook already installed" and moves on
* `cordon integration disable claude-code` removes both the hook entry from settings and the script file
* The hook script is scope-aware: if setup was given an explicit `--config <path>`, the hook passes `--config <path>` to `cordon status -q`. For user scope (without explicit config), it passes `--scope user`. This ensures the hook checks the correct cordon instance.

## Troubleshooting

<AccordionGroup>
  <Accordion title="Cordon proxy is not running">
    This message comes from the health-check hook. It means cordon's proxy env vars are set in your Claude Code settings, but `cordon status -q` could not reach the health endpoint.

    1. **Start cordon**: type `! cordon service start` in the Claude Code prompt, or run `cordon start` in another terminal
    2. **Check status**: `! cordon status` shows whether the proxy is running, stopped, or blocked by another process
    3. **Remove the integration**: if you no longer want cordon for this project, type `! cordon integration disable claude-code --yes`, then restart with `claude --continue`
  </Accordion>

  <Accordion title="Certificate errors">
    Claude Code uses the same proxy and CA env vars documented in [`cordon env`](/cli/env). Check [TLS troubleshooting](/configuration/tls#troubleshooting-certificate-errors), then verify those values are present in `.claude/settings.local.json` or `~/.claude/settings.json`.
  </Accordion>

  <Accordion title="OSStatus -26276 / TLS failures in Go tools (macOS sandbox)">
    If Go-based tools (`gh`, `terraform`, `kubectl`, `gcloud`) fail with:

    ```
    tls: failed to verify certificate: OSStatus -26276
    ```

    This means Claude Code's macOS sandbox is blocking `com.apple.trustd.agent` Mach IPC. Go uses Apple's Security.framework for TLS certificate verification, which communicates with the `trustd` daemon. The sandbox blocks this by default.

    Add `enableWeakerNetworkIsolation` to your sandbox settings:

    ```json theme={null}
    {
      "sandbox": {
        "enabled": true,
        "autoAllowBashIfSandboxed": true,
        "enableWeakerNetworkIsolation": true,
        "network": {
          "allowLocalBinding": true,
          "allowedDomains": ["127.0.0.1"]
        }
      }
    }
    ```

    See [Sandbox configuration](#go-based-tools-gh-terraform-kubectl-gcloud) for details and trade-offs. Restart Claude Code after changing sandbox settings.

    Python tools may also encounter TLS errors in the sandbox, but these are more commonly resolved by ensuring `SSL_CERT_FILE` and `REQUESTS_CA_BUNDLE` point to the combined CA bundle -- see the [Certificate errors](#troubleshooting) accordion above.
  </Accordion>

  <Accordion title="Proxy not being picked up">
    Verify the env vars are in Claude Code's settings file. Project scope writes `.claude/settings.local.json`; user scope writes `~/.claude/settings.json`.

    ```bash theme={null}
    # Project scope
    cat .claude/settings.local.json

    # User scope
    cat ~/.claude/settings.json
    ```

    If the vars are set but Claude Code isn't routing through the proxy, use the shared [proxy not running checks](/guides/process-management#proxy-not-running-checks).
  </Accordion>

  <Accordion title="Proxy env vars not reaching subprocesses (sandbox disabled)">
    If `HTTP_PROXY`/`HTTPS_PROXY` are set in your settings file but subprocesses (curl, wget, gh) don't see them — requests go directly to the internet and cordon credential injection silently fails.

    **Cause:** The sandbox is disabled (`"enabled": false` or absent). Claude Code's sandbox manages proxy env var propagation to subprocesses. When the sandbox is off, the proxy env vars from your settings file are not passed through, even though other env vars (like CA cert paths) may be.

    **Diagnosis:** Run `env | grep HTTP_PROXY` in a Claude Code Bash tool call. If the proxy vars are missing but CA cert vars are present, the sandbox is likely disabled.

    **Fix:** Ensure `sandbox.enabled` is `true` in your settings file:

    ```json theme={null}
    {
      "sandbox": {
        "enabled": true,
        "autoAllowBashIfSandboxed": true,
        "network": {
          "allowLocalBinding": true,
          "allowedDomains": ["127.0.0.1"]
        }
      }
    }
    ```

    Restart Claude Code after changing sandbox settings.
  </Accordion>

  <Accordion title="MCP servers not using the proxy">
    MCP servers launched by Claude Code inherit the env vars written by `cordon setup claude-code`. If a server is launched outside Claude Code, or its config replaces rather than inherits the parent environment, follow the [MCP server guide](/guides/mcp-servers).
  </Accordion>

  <Accordion title="Routes not appearing in cordon logs (Node.js)">
    Node.js built-in `fetch` needs the Cordon bootstrap loader. `cordon setup claude-code` sets this automatically when `register.mjs` is discoverable; otherwise follow [SDK Compatibility: Node register import](/guides/sdk-compatibility#node-register-import).
  </Accordion>

  <Accordion title="New routes not taking effect">
    Restart Cordon after adding or editing route definitions. See [Routes: route changes and secret rotation](/configuration/routes#route-changes-and-secret-rotation).
  </Accordion>

  <Accordion title="401 Unauthorized errors">
    1. **Verify the secret is stored**: `cordon secret set <account>` (find the account name with `cordon route show <name>`)
    2. **Check the header**: Anthropic uses `type: header` with `header_name: x-api-key` and no `scheme`
    3. **Check the secret source**: HTTP route secrets are fetched per-request — if you changed a secret, the next request picks it up automatically
  </Accordion>
</AccordionGroup>
