Skip to content

Config — arca.toml ​

Top level ​

fieldtyperequirednotes
vaults{name: vault}optionalNamed 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}optionalThe declared secret surface: env-var name → arca:// ref. Bounds what run/env may inject — least privilege, no ambient vault dump.
deploy{name: target}optionalNamed deploy targets — write-only sinks (arca deploy pushes a stored value in; nothing ever reads one back).
guardrailstableoptionalAdvisory op guardrails — accident prevention for standalone use, honestly not a policy boundary (a locally claimed actor is spoofable by construction).
servetableoptionalThe 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 ​

fieldtyperequirednotes
kindstringoptionalBackend kind — "age" (built-in, local file) or "cf" (self-hosted Cloudflare Worker + D1, arca-vault-cf).
pathstringoptionalVault file path override (age impl; ~ is not expanded — write the path in full).
identitystringoptionalAge 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).
recipientslistoptionalExtra age recipients to encrypt to, beyond the identity's public key (age1… strings).
urlstringoptionalWorker base URL (cf impl), e.g. https://arca-vault.you.workers.dev.
token_envstringoptionalName of the env var holding the bearer token (cf impl) — the token name lives in config, the token value only in the process env.
tokensBTreeMap<Env, Ref>optionalPer-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 &lt;ref-path&gt;, ts, sig — the ref path is the wire token_id. Token refs live in config, never token values.
private_refsbooloptionalOpt-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.
cacheCacheScopeoptionalRead-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/&lt;name&gt;.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_secsintoptionalCache 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) ​

fieldtyperequirednotes
vaultstringrequiredVault name in [vaults] (or the implicit local).

[deploy.NAME] — a write-only push target ​

fieldtyperequirednotes
kindstringoptionalTarget kind — "cf-secrets-store" (Cloudflare account Secrets Store, arca-deploy-cf).
account_idstringoptionalCloudflare account id (cf-secrets-store).
store_idstringoptionalSecrets Store id (cf-secrets-store).
token_envstringoptionalName of the env var holding the API token — never the token itself (cf-secrets-store defaults to CLOUDFLARE_API_TOKEN).
base_urlstringoptionalAPI base URL override — for tests, gateways, and self-hosted proxies. Defaults to https://api.cloudflare.com/client/v4.

[guardrails] — advisory op table ​

fieldtyperequirednotes
default`"allow""deny"`optional
allowop listoptionalOps always allowed.
denyop listoptionalOps always refused — deny wins over allow.
deny_adhocbooloptionalRefuse -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 ​

fieldtyperequirednotes
pdptableoptionalThe 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 ​

fieldtyperequirednotes
execstringrequiredThe 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_errorbooloptionalWhat 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_msintoptionalPer-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 — no arca.toml anywhere just means defaults (local age vault, dev env).
  • Token values never live in the file — token_env fields name the env var that carries them.
  • arca schema emits the JSON Schema for this shape; arca check validates a real file end-to-end.