Configuration
API reference for OCX configuration files. For the rationale behind the tier model, the merge philosophy, and worked examples, see the Configuration in-depth page.
Config files are in TOML format and are optional. OCX works without any config file using compiled-in defaults.
File Locations
| Tier | Path | Purpose |
|---|---|---|
| System | /etc/ocx/config.toml | Machine-wide defaults |
| User (Linux) | $XDG_CONFIG_HOME/ocx/config.toml or ~/.config/ocx/config.toml | Per-user defaults |
| User (macOS) | ~/Library/Application Support/ocx/config.toml | Per-user defaults; XDG_CONFIG_HOME not consulted |
| OCX home | $OCX_HOME/config.toml (default: ~/.ocx/config.toml) | Co-located with data; survives a zip-and-move of $OCX_HOME |
Missing files are silently skipped.
Explicit additions
Two mechanisms add a file on top of the discovery chain — they do not replace it. Missing files are an error in this case (explicit paths must exist).
--configFILE— CLI flag, before subcommandOCX_CONFIG=/path/to/file.toml— environment variable
When both are set, --config layers on top of OCX_CONFIG. Setting OCX_CONFIG to the empty string disables an ambient value without unsetting it.
Discovery and Merge Precedence
Settings are resolved lowest-to-highest. Higher-precedence sources override lower ones.
| Priority | Source | Notes |
|---|---|---|
| 1 (lowest) | Compiled defaults | Built into the OCX binary |
| 2 | System config — /etc/ocx/config.toml | Discovered tier |
| 3 | User config — $XDG_CONFIG_HOME/ocx/config.toml (Linux) or ~/Library/Application Support/ocx/config.toml (macOS) | Discovered tier |
| 4 | OCX home config — $OCX_HOME/config.toml | Discovered tier |
| 5 | OCX_CONFIG | Layered on top of discovered tiers |
| 6 | --config FILE | Layered on top of OCX_CONFIG |
| 7 | Environment variables (OCX_*) | Always win over any config file |
| 8 (highest) | CLI flags | Per-invocation; always win |
Merge rules
- Scalars: the nearest (highest-precedence) value wins.
- Tables (e.g.
[registries.<name>]): merged key-by-key across tiers; inner keys use nearest-wins. - Layering: every file is loaded and merged in order. Explicit paths do not replace the discovered tiers.
Kill switch
OCX_NO_CONFIG=1 skips the discovered chain only (tiers 2–4). Explicit paths (--config, OCX_CONFIG) still load.
| Goal | Invocation |
|---|---|
| Default | (no flags) |
| Layer override on ambient | --config extra.toml |
| Hermetic with a specific file | OCX_NO_CONFIG=1 --config ci.toml |
| Hermetic, no files | OCX_NO_CONFIG=1 |
Configuration Keys
[registry]
Global settings for the registry subsystem.
default
Type: string
Default: "ocx.sh"
Overridden by: OCX_DEFAULT_REGISTRY environment variable
The default registry used for bare package identifiers — those without an explicit registry prefix. When you write cmake:3.28, OCX expands it to <default>/cmake:3.28.
The value may be either a literal hostname ("ghcr.io") or the name of a [registries.<name>] entry. When it matches a named entry, OCX resolves it to that entry's url.
[registry]
default = "ghcr.io"[registries.<name>]
Per-registry settings, keyed by a friendly name. Each entry configures one registry; [registry] default can then reference it by name rather than by hostname.
The plural form (registries, not registry) is deliberate: it mirrors Cargo's convention and avoids a TOML collision with the singular [registry] global-settings section.
url
Type: string
The actual registry hostname this entry resolves to. When [registry] default names this entry, OCX uses url as the effective default registry hostname.
[registry]
default = "company"
[registries.company]
url = "registry.company.example"
[registries.ghcr]
url = "ghcr.io"v1 scope
Only url is defined in v1. The [registries.<name>] table is reserved for per-registry settings — future fields (insecure, location rewrite, timeout, auth) will slot into the same entry without breaking existing configs. Unknown fields inside an entry are rejected (typo protection); unknown top-level sections are silently ignored (forward compatibility).
Environment Variable Override Table
This table shows which OCX environment variables map to config file fields. Variables not listed here have no config equivalent.
| Environment Variable | Config Equivalent | Notes |
|---|---|---|
OCX_DEFAULT_REGISTRY | [registry] default | Env var wins when both are set |
OCX_HOME | None | Determines where config is loaded from; cannot be in a config file |
OCX_CONFIG | None | Meta-variable pointing at the config file itself |
OCX_NO_CONFIG | None | Kill switch; cannot be represented in a config file by definition |
OCX_OFFLINE | None | Per-invocation mode, not a persistent setting |
OCX_REMOTE | None | Per-invocation debugging mode, not a persistent setting |
OCX_BINARY_PIN | None | Subprocess-only: set automatically by ocx on every spawn so child ocx invocations pin to the same binary |
OCX_INSECURE_REGISTRIES | None (deferred) | Will move to a per-entry insecure field under [registries.<name>] once the flag is implemented; the env var remains the source of truth today |
OCX_NO_UPDATE_CHECK | None | CI-only concern; env var is sufficient |
OCX_NO_MODIFY_PATH | None | Install-time concern; env var is sufficient |
OCX_OFFLINE and OCX_REMOTE are intentionally absent from the config file. Both are per-invocation modes — a persistent offline = true would silently break ocx install on a fresh setup.
Error Reference
Literal sizes in the examples below reflect the current 64 KiB safety cap (MAX_CONFIG_SIZE in the loader source). Angle-bracket placeholders such as <SIZE> stand in for runtime values that depend on the offending file.
| Error | Cause | Resolution |
|---|---|---|
error: config file not found: /path/to/file.toml (check --config or OCX_CONFIG) | --config or OCX_CONFIG points to a non-existent file | Check the path; unlike the three discovery tiers, explicit paths must exist. To disable an ambient OCX_CONFIG without unsetting it, set it to the empty string. |
error: config file /path/to/file.toml exceeds maximum allowed size (<SIZE> bytes > 65536 bytes); OCX config files are typically under 1 KiB — did you point at the wrong file | A config file is larger than the 64 KiB safety cap | The hint usually explains it — a --config flag or OCX_CONFIG env var pointed at a non-config file (e.g. an archive or binary). |
error: invalid TOML at /path/to/file.toml: ... | TOML syntax error in the config file | Fix the TOML syntax error at the indicated location |
error: failed to read config file /path/to/file.toml: ... | The file exists but cannot be read — permission denied, the path is a directory, or another I/O failure | Check file permissions; --config and OCX_CONFIG must point to a regular, readable file. |
Future Config Keys
Not yet implemented in v1
These sections are documented here so the format design is stable before they land. They do not exist in the current release.
Per-registry fields beyond url
The [registries.<name>] table is live in v1, but only url is defined. Future per-registry fields will slot in without breaking existing configs:
# Future shape (not in v1 — only `url` is implemented today):
[registries.private]
url = "registry.company.example"
insecure = false # per-registry TLS opt-out
location = "mirror.company.example" # URL rewrite / mirror[patches] section
Infrastructure patch entries will live under [patches]. This section is reserved for the patches feature and is ignored by the v1 loader.
[clean] section
Retention policy configuration will live under [clean]. Deferred to the retention policy feature.
Project-level ocx.toml
A CWD-walk for a project-level ocx.toml is planned. The file name is deliberately different from config.toml so the data-directory tier and project tier are never confused. When it lands, it will sit between $OCX_HOME/config.toml and OCX_CONFIG in the precedence order.