Skip to main content
Cordon integrates with Hermes Agent so your AI agent can make authenticated API calls without holding real credentials.

Scope

Hermes setup only supports user scope — Hermes operates across projects, so cordon setup hermes --scope project is rejected by the CLI. User scope stores config at $XDG_CONFIG_HOME/cordon/cordon.toml and writes proxy env vars to $HERMES_HOME/.env (or ~/.hermes/.env). A single cordon instance handles credential injection regardless of which project Hermes is working in. See Scopes for path details and trade-offs.

Automated setup

The fastest way to get started:
cordon setup hermes
This:
  1. Generates CA certificates (if not already present)
  2. Creates a scaffold cordon.toml
  3. Generates a combined CA bundle (system CAs + Cordon CA)
  4. Writes proxy env vars to Hermes’s ~/.hermes/.env (HTTPS_PROXY, HTTP_PROXY, https_proxy, http_proxy, SSL_CERT_FILE, REQUESTS_CA_BUNDLE, CURL_CA_BUNDLE)
  5. Installs a cordon agent skill to ~/.hermes/skills/cordon/SKILL.md
Your existing .env is backed up to .env.cordon.bak before any changes are made. To run cordon as a background service, run cordon service install --scope user after setup.

Remove the setup

cordon integration disable hermes

Adding routes

After setup, add a route for your LLM provider with cordon route add --scope user and, if using the keyring secret source, store the credential with cordon secret set. Pass --scope user to every cordon route, cordon start, and cordon service command — Hermes is user-scope only, and bare commands default to project scope.
Anthropic uses type: api_key with header_name: x-api-key, not type: bearer. Using the wrong auth type will result in 401 errors.

Provider auto-detection

Hermes uses env vars to auto-detect which LLM provider to use. Since cordon injects the real API key at the network layer, Hermes still needs a dummy key to select the right provider. Add a placeholder to ~/.hermes/.env:
# Hermes sees this and selects the Anthropic provider.
# Cordon strips it and injects the real key from the keychain.
ANTHROPIC_API_KEY=dummy-replaced-by-cordon
Without this, Hermes won’t know which provider to use and will fail to make API calls even though cordon has the real credentials ready to inject.

Manual setup

If you prefer manual configuration, add these to ~/.hermes/.env. Replace <PORT> with the port in your cordon.toml:
HTTPS_PROXY="http://127.0.0.1:<PORT>"
HTTP_PROXY="http://127.0.0.1:<PORT>"
https_proxy="http://127.0.0.1:<PORT>"
http_proxy="http://127.0.0.1:<PORT>"
SSL_CERT_FILE="/path/to/combined-ca.pem"
REQUESTS_CA_BUNDLE="/path/to/combined-ca.pem"
CURL_CA_BUNDLE="/path/to/combined-ca.pem"
You must create a combined CA bundle manually if not using cordon setup hermes. Concatenate your system CA bundle with the Cordon CA cert — see Combined CA bundle below.
The HERMES_HOME env var can override the default ~/.hermes/ path if Hermes is installed in a non-standard location.

How it works

Hermes uses Python’s httpx library for HTTP, which honors HTTPS_PROXY by default (trust_env=True). The OpenAI, Firecrawl, and Exa SDKs all use httpx or requests internally, and Hermes’s own Tavily client uses httpx directly, so all HTTP traffic routes through cordon automatically. No code changes or monkeypatching required. Cordon only MITMs connections to hosts with matching routes. All other traffic passes through as a transparent CONNECT tunnel — the upstream server’s real certificate is presented to the client, and no CA bundle configuration is needed for those connections.

Combined CA bundle

Python’s SSL_CERT_FILE replaces the default certificate store rather than appending to it. This means setting SSL_CERT_FILE to just the Cordon CA cert would break TLS for all non-proxied connections (the system CAs would be missing). To solve this, cordon setup hermes generates a combined CA bundle that concatenates:
  1. Your system CA certificates (e.g., from /etc/ssl/cert.pem)
  2. The Cordon proxy CA certificate
This combined bundle is written next to the Cordon CA cert (e.g., combined-ca.pem) and both SSL_CERT_FILE and REQUESTS_CA_BUNDLE point to it. REQUESTS_CA_BUNDLE is set separately because Python’s requests library does not read SSL_CERT_FILE — it has its own env var.
This is different from the Codex integration, where SSL_CERT_FILE points directly to the Cordon CA cert. Codex uses Rust’s rustls, which adds custom CAs on top of the system trust store rather than replacing it.

Sandboxed environments

Hermes supports Docker, Modal, and SSH sandboxed execution backends. These environments run in isolated network namespaces where 127.0.0.1 refers to the container’s loopback, not the host. The cordon proxy running on the host is not reachable from inside these sandboxes without network bridging. For local development (TERMINAL_ENV=local), cordon works out of the box. For sandboxed backends, a remote cordon proxy with network-accessible binding would be needed (not yet supported).

Workflow

Once configured, the workflow is:
  1. Start cordon: cordon start --scope user (or use the background service)
  2. Start Hermes as usual
  3. When Hermes makes API calls to configured hosts, cordon transparently injects credentials
  4. Hermes never sees or logs real API keys
Use cordon doctor to diagnose any setup issues. It checks config validity, cert paths, trust store status, and port availability.

Troubleshooting

  1. Wrong auth type: Anthropic uses type: api_key with header_name: x-api-key, not type: bearer. Check your cordon.toml route configuration.
  2. Missing dummy key: Hermes won’t select a provider without its API key env var set. Add ANTHROPIC_API_KEY=dummy-replaced-by-cordon to ~/.hermes/.env.
  3. Check the secret source: Secrets are fetched per-request — if you changed a secret, the next request picks it up automatically.
  4. Verify the secret is stored: cordon secret set anthropic
If you see SSL/TLS errors:
  1. Verify the combined CA bundle exists and is readable:
    cat ~/.hermes/.env | grep SSL_CERT_FILE
    ls -la "$(cat ~/.hermes/.env | grep SSL_CERT_FILE | cut -d'"' -f2)"
    
  2. Verify the bundle contains both system CAs and the Cordon CA:
    grep -c "BEGIN CERTIFICATE" /path/to/combined-ca.pem  # should be many
    grep "Cordon proxy CA" /path/to/combined-ca.pem       # should match
    
  3. If the combined bundle is missing, re-run cordon setup hermes to regenerate it.
Verify the env vars are in ~/.hermes/.env:
cat ~/.hermes/.env
Hermes loads this file at startup via load_hermes_dotenv(). If the file exists but Hermes isn’t routing through the proxy, ensure cordon is running:
cordon status
# Replace <PORT> with the listen port from your cordon.toml
curl http://127.0.0.1:<PORT>/health
If Hermes can’t determine which LLM provider to use, it’s likely missing the dummy API key env var. Add the appropriate key to ~/.hermes/.env:
ANTHROPIC_API_KEY=dummy-replaced-by-cordon    # for Anthropic
OPENAI_API_KEY=dummy-replaced-by-cordon       # for OpenAI
Cordon loads routes at startup. If you add or change routes or the cordon.toml config, restart the proxy (secrets are fetched per-request and don’t require a restart):
# If running as a service
cordon service stop --scope user && cordon service start --scope user

# If running manually
# Ctrl+C the running process, then:
cordon start --scope user