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.
Cordon is configured via cordon.toml. Prefer the CLI over hand-editing this file: cordon setup creates it, and cordon route / cordon listener commands validate changes and write the safer defaults for you. The file format is documented here for review, troubleshooting, and automation when a CLI command does not cover your use case.
See setup for details.
Scopes
Cordon is project-first — most integrations default to project scope, giving each repository its own config, credentials, and proxy instance. A user scope is also available for tools that span projects. The two scopes are independent: each runs its own daemon with its own config file, TLS certificates, and optional OS service. They are not merged or layered.
| Resource | Project scope | User scope |
|---|
| Config file | $CWD/cordon.toml | $XDG_CONFIG_HOME/cordon/cordon.toml |
| TLS certificates | $XDG_CONFIG_HOME/cordon/projects/<dirname>-<hash8>/certs/ | $XDG_CONFIG_HOME/cordon/user/certs/ |
| Service name | <dirname>-<hash8> | user |
<dirname>-<hash8> is the project directory basename plus the first 8 hex characters of the SHA-256 of the absolute CWD path, so two projects with the same directory name never collide.
On macOS (launchd) and Linux (systemd user units) these names are automatically namespaced. The launchd label becomes io.codezero.cordon.<name>.
Directory layout
Cordon follows the XDG Base Directory spec for its config location. $XDG_CONFIG_HOME defaults to ~/.config on both Linux and macOS — cordon intentionally uses ~/.config/cordon/ on macOS for consistency with cross-platform dev tools like git and VS Code. Set XDG_CONFIG_HOME=/custom/path to override; cordon will then use /custom/path/cordon/.
~/.config/cordon/ # base directory
├── cordon.toml # user-scope config
├── user/
│ └── certs/ # user-scope TLS material
│ ├── ca-cert.pem
│ └── ca-key.pem
└── projects/
└── myapp-a1b2c3d4/ # <dirname>-<hash8>
└── certs/ # project-scope TLS material
├── ca-cert.pem
└── ca-key.pem
<project>/
└── cordon.toml # project-scope config (one per project)
Project-scope configs live beside your code. Everything else — user-scope config and all TLS certificates — lives under the user’s cordon config directory. The <dirname>-<hash8> naming uses SHA-256 of the absolute project path so two projects sharing the same directory name never collide.
Port allocation
Each cordon setup invocation — project or user scope — asks the OS for a free port and writes it into cordon.toml at setup time. In practice this avoids collisions between concurrent projects and rapid successive cordon setup invocations. There is no base port to configure.
The allocated port is not reserved: cordon setup binds to port 0, reads the port the OS assigned, then releases the socket before writing the number into cordon.toml. Between setup and cordon start, another process could theoretically claim the port. If that happens, cordon start will fail to bind and you can rerun cordon setup to pick a new port. Persistent port reservation and re-allocation at start time is future work.
Per-integration defaults
| Integration | Default scope | Rationale |
|---|
claude-code | project | Editor configs are typically per-repo |
codex | project | Project-specific Codex env isolates credentials |
hermes | user | Hermes operates across projects; user scope avoids per-repo repetition |
Overriding the scope
Pass --scope user or --scope project to override the default for claude-code or codex:
# Configure Claude Code globally (one config for all projects)
cordon setup claude-code --scope user
Hermes only supports user scope — cordon setup hermes --scope project is rejected by the CLI.
When to choose which scope
- Project scope — the right default for most tools. Each repo gets its own credentials, port, and service. No cross-project interference.
- User scope — best for tools like Hermes that naturally span multiple projects, or when you want a single cordon instance shared across repos. One cordon process handles all requests.
cordon start and scope
cordon start with no flags uses ./cordon.toml (project scope). To start the user-scope instance explicitly:
cordon start --scope user
cordon service and scope
cordon service install/start/stop --scope <project|user> derives the service name and config path from the scope automatically:
cordon service install --scope project # installs <dirname>-<hash8>
cordon service install --scope user # installs user
After setup, use commands like cordon route add, cordon route edit, cordon listener add, and cordon listener edit to modify credential rules. For automation, prefer non-interactive CLI flags (for example, cordon setup --yes or fully-flagged cordon route add) instead of maintaining a hand-written config.
cordon service install does not write cordon.toml — it points an OS service at an existing file, typically the project-local file setup produced.
Paths in cordon.toml are literal strings: Cordon does not expand $HOME, ~, or other environment variables. Use the absolute paths written by cordon setup, or substitute placeholders like elsewhere in these docs (/path/to/...). If ca_cert_path or ca_key_path are relative, they are resolved against the config file’s directory (not the working directory), so hand-edited configs work correctly under service managers where the working directory is /.
Minimal example
The listen port is assigned automatically by cordon setup — the 6790 shown in the example is illustrative; your actual port is OS-assigned and typically in the ephemeral range. Check the listen = ... line in your generated cordon.toml to find the port in use.
listen = 6790 # illustrative — your setup may allocate a different port
[tls]
enabled = true
# Substitute paths from your real `cordon.toml` (typically under ~/.config/cordon/projects/<namespace>/certs/).
ca_cert_path = "/path/to/ca-cert.pem"
ca_key_path = "/path/to/ca-key.pem"
[[routes]]
name = "stripe"
[routes.match]
host = "api.stripe.com"
[routes.auth]
type = "header"
header_name = "Authorization"
scheme = "Bearer"
[routes.auth.secret]
source = "1password"
vault = "Engineering"
item = "Stripe API Key"
field = "secret_key"
Top-level fields
| Field | Type | Required | Description |
|---|
listen | integer | Yes | Port number to listen on. The proxy always binds to 127.0.0.1 (loopback) — this is not configurable because binding to a non-loopback address would expose injected credentials to the network. |
tls | object | No | TLS interception settings. Required only when you enable HTTPS MITM or require PostgreSQL client TLS. |
secrets | object | No | Secret provider configuration. Use to specify an explicit path to the op binary when it’s not on PATH (common for background services). See Secret Sources — Provider configuration. |
routes | array | No | List of HTTP credential route definitions. Matched routes are explicit trust decisions; see Routes. |
listeners | array | No | List of PostgreSQL listener definitions. See Listeners. |
TLS settings
| Field | Type | Required | Description |
|---|
tls.enabled | boolean | No | Enable HTTPS interception via TLS MITM. Defaults to false if omitted. |
tls.ca_cert_path | string | Conditional | Path to the CA certificate file. Required when HTTPS MITM is enabled or PostgreSQL client_tls = "require" is used. |
tls.ca_key_path | string | Conditional | Path to the CA private key file. Required when HTTPS MITM is enabled or PostgreSQL client_tls = "require" is used. |
When TLS is enabled, cordon performs MITM on HTTPS connections for matched routes. It generates per-host certificates signed by the local CA. See TLS for details.
Route and listener names share one namespace and must be unique. Listener ports must also be unique and cannot equal the HTTP proxy listen port.
Extended examples
Keep this page as the map of cordon.toml. Use the focused references for complete examples:
- Routes for HTTP credential injection, auth types, provider examples, and route matching.
- Listeners for PostgreSQL listener configuration.
- Secret Sources for 1Password, keyring, rotation, and platform behavior.
Config file location
cordon start resolves the config file based on scope:
- Project scope (default) —
./cordon.toml
- User scope (
--scope user) — $XDG_CONFIG_HOME/cordon/cordon.toml (or ~/.config/cordon/cordon.toml if XDG_CONFIG_HOME is not set)
cordon setup writes the config to the scope-appropriate path automatically. See Scopes above for the full scope path table.
You can bypass scope resolution entirely with the --config flag:
cordon start --config /path/to/cordon.toml
cordon.toml typically contains project-specific secret references and should be gitignored.