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.<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/.<dirname>-<hash8> naming uses SHA-256 of the absolute project path so two projects sharing the same directory name never collide.
Port allocation
Eachcordon 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
Overriding the scope
Pass--scope user or --scope project to override the default for claude-code or codex:
--scope. Their default config paths are ~/.hermes/cordon.toml and ~/.openclaw/cordon.toml; pass --config to follow-up commands when you need to target those instances explicitly.
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 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 service and scope
cordon service install/start/stop --scope <project|user> derives the service name and config path from the scope automatically:
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
Thelisten 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.
Top-level fields
TLS settings
When TLS is enabled, cordon performs MITM on HTTPS connections to configured route hosts. Inner request path and method filters decide whether credentials are stripped and injected after the tunnel is decrypted. 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.
Denylist exceptions
Cordon permits outbound requests to any public destination by default — it does not maintain an egress allowlist. What it always enforces is an SSRF denylist that blocks private, loopback, link-local, and cloud metadata addresses, plus CGNAT,0.0.0.0/8, documentation and benchmarking ranges, multicast, IETF-reserved space, and the IPv6 equivalents of these. The denylist_exceptions list carves specific host:port destinations out of that denylist, without credential injection. This is useful for local development services (databases, mock APIs, local Supabase instances) that the proxy needs to forward traffic to but that do not require credential injection.
Loopback expansion: Loopback entries auto-expand across
localhost, 127.0.0.1, and [::1]. Configuring localhost:54321 also allows 127.0.0.1:54321 and [::1]:54321.
Denylist bypass scope: Entries bypass the entire SSRF denylist, not just loopback blocking. An exception for a private-network address (e.g., 192.168.1.50:8080) will be allowed through.
Trust model: Denylist exceptions follow the same operator opt-in trust model as configured routes. Each entry is an explicit decision by the developer to permit a denylisted destination. Unlike routes, exceptions do not inject credentials — requests are forwarded unmodified.
Extended examples
Keep this page as the map ofcordon.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.tomlifXDG_CONFIG_HOMEis 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.toml typically contains project-specific secret references and should be gitignored.