Config — arca.toml
Top level
| field | type | required | notes |
|---|---|---|---|
vaults | {name: vault} | optional | Named vault backends. local always exists implicitly (age, default paths); an entry only overrides it or adds more. |
envs | `{env: vault | {vault}}` | optional |
secrets | {VAR: arca://ref} | optional | The declared secret surface: env-var name → arca:// ref. Bounds what run/env may inject — least privilege, no ambient vault dump. |
deploy | {name: target} | optional | Named deploy targets — write-only sinks (arca deploy pushes a stored value in; nothing ever reads one back). |
guardrails | table | optional | Advisory op guardrails — accident prevention for standalone use, honestly not a policy boundary (a locally claimed actor is spoofable by construction). |
serve | table | optional | The arca serve surface — ndjson request/response on stdio plus the optional policy decision point. Absent, serve runs with no PDP — same advisory posture as the single-shot CLI. |
[vaults.NAME] — a named vault backend
| field | type | required | notes |
|---|---|---|---|
kind | string | optional | Backend kind — "age" (built-in, local file) or "cf" (self-hosted Cloudflare Worker + D1, arca-vault-cf). |
path | string | optional | Vault file path override (age impl; ~ is not expanded — write the path in full). |
identity | string | optional | Age identity file override (ARCA_IDENTITY_FILE wins over this; see arca-ops). cf vaults decrypt with the same keyfile — all vault impls store age ciphertext (ADR-0001). |
recipients | list | optional | Extra age recipients to encrypt to, beyond the identity's public key (age1… strings). |
url | string | optional | Worker base URL (cf impl), e.g. https://arca-vault.you.workers.dev. |
token_env | string | optional | Name of the env var holding the bearer token (cf impl) — the token name lives in config, the token value only in the process env. |
tokens | BTreeMap<Env, Ref> | optional | Per-env scoped credentials (cf impl, P-003): env → the arca:// ref of a token stored in the local vault. Each resolved token authenticates as ArcaHmac <ref-path>, ts, sig — the ref path is the wire token_id. Token refs live in config, never token values. |
private_refs | bool | optional | Opt-in private ref metadata (cf impl, P-004): storage keys become HMAC-derived hex and every record carries an age-encrypted name blob, so the remote store can't see which secrets exist. Default false; arca migrate --private-refs rewrites existing rows. |
cache | CacheScope | optional | Read-through encrypted local cache in front of this vault (P-007): true caches every env; a name or list scopes it — cache = "dev" or cache = ["dev", "staging"]. Rows land at $XDG_CACHE_HOME/arca/<name>.age as ordinary age ciphertext carrying the remote version/rotated_at verbatim; freshness is TTL-bounded (cache_ttl_secs) and writes are always remote-first. Meant for remote backends — dev may cache, prod should live-fetch. |
cache_ttl_secs | int | optional | Cache freshness window in seconds — a cached row or env listing younger than this answers without a remote round-trip; past it the remote is re-fetched and the cache updated. A remote failure falls back to the stale copy — the offline mode. Absent → 300. |
[envs] — env → vault routing (table form)
| field | type | required | notes |
|---|---|---|---|
vault | string | required | Vault name in [vaults] (or the implicit local). |
[deploy.NAME] — a write-only push target
| field | type | required | notes |
|---|---|---|---|
kind | string | optional | Target kind — "cf-secrets-store" (Cloudflare account Secrets Store, arca-deploy-cf). |
account_id | string | optional | Cloudflare account id (cf-secrets-store). |
store_id | string | optional | Secrets Store id (cf-secrets-store). |
token_env | string | optional | Name of the env var holding the API token — never the token itself (cf-secrets-store defaults to CLOUDFLARE_API_TOKEN). |
base_url | string | optional | API base URL override — for tests, gateways, and self-hosted proxies. Defaults to https://api.cloudflare.com/client/v4. |
[guardrails] — advisory op table
| field | type | required | notes |
|---|---|---|---|
default | `"allow" | "deny"` | optional |
allow | op list | optional | Ops always allowed. |
deny | op list | optional | Ops always refused — deny wins over allow. |
deny_adhoc | bool | optional | Refuse -s VAR=arca://ref ad-hoc injection on run/env (MED-5). Without it, a posture like deny = ["get"] is sidestepped: arca run -s V=arca://x -- printenv V is a get. Declared [secrets] injection is unaffected — the declared surface is auditable config, not an ad-hoc grab. |
[serve] — the arca serve surface
| field | type | required | notes |
|---|---|---|---|
pdp | table | optional | The external policy decision point serve consults before every op that can materialize (get/put/rm/rotate/ list/check). Absent, no consult happens — the advisory posture only. |
[serve.pdp] — the external policy decision point
| field | type | required | notes |
|---|---|---|---|
exec | string | required | The exec driver command — run via sh -c once per decision, request JSON on stdin, verdict JSON on stdout. Trust root: the line authorizes shell exec; the child inherits only the arca-shell env allowlist. arca serve warns when this arrives via an implicit ./arca.toml — pin config with --config/$ARCA_CONFIG. |
allow_on_error | bool | optional | What an unreachable PDP means. false (default) fails closed — the op is denied; a policy engine that can't answer must not silently mean "allowed". true fails open — the op runs anyway and the audit event records the degraded verdict. |
timeout_ms | int | optional | Per-decision deadline in milliseconds — the child is killed and the consult counts as unreachable past it. A hung or flooding PDP must never freeze the serve loop; absent → 5000. |
[envs] route forms
Either a bare vault name or the table above:
toml
[envs]
dev = "local"
prod = { vault = "cloud" }Constraints
deny_unknown_fields: typos in field names fail the load.- Search order:
--config→$ARCA_CONFIG→./arca.toml→~/.config/arca/arca.toml. The file is optional — noarca.tomlanywhere just means defaults (local age vault,devenv). - Token values never live in the file —
token_envfields name the env var that carries them. arca schemaemits the JSON Schema for this shape;arca checkvalidates a real file end-to-end.