Skip to main content
Version: v5.6.1

Settings reference — the per-key dictionary

Included from Basic tier

This page lists every key the Go server reads, per authority, with its type, units, default, permitted values, precedence and whether a change is live or needs a restart. The configuration model (documents, versions, convergence) is opschain docs settings; the config.yaml key catalog is opschain docs config and is not restated here.

Liveness vocabulary used throughout:

  • live (≤1 min) — read through the authentication stack's TTL snapshot of the stored global settings; an edit bites within a minute, no restart.
  • live (per read) — read from the database on each request, run creation or sweep; an edit bites on the next read.
  • restart — config.yaml, keys.env and the process environment are read once by opschain server start (or opschain runner); changing them requires restarting that process.

Stored global settings (the SystemConfiguration document)​

Edited with opschain admin settings show | prune and PATCH /api/settings/{id}; every key not listed here (and not a kept git_remote.periodic_fetch_interval key) is legacy and pruneable (opschain docs cli/admin-settings-prune).

Identity and tokens — live (≤1 min)​

KeyType / unitsDefaultPermitted valuesRead for
enable_basic_authbooltruetrue/falseWhether HTTP basic credentials are accepted (token auth is unaffected). Overridden by config.yaml enable_basic_auth, which OPSCHAIN_ENABLE_BASIC_AUTH beats.
token.secret_keystring, secret—non-emptyStill resolved and required at boot — OPSCHAIN_TOKEN_SECRET_KEY (environment, then keys.env) wins over the stored value, a disagreement is announced at boot — but the v1 JWT lane it signed is retired: no token is minted or verified against it any more. Native session tokens sign on a dedicated stored key (auth_signing_keys).
token.access_expiryint, minutes15 (the native session lane's default; the pre-cutover 4 h default retired with the v1 token routes)> 0 (0/absent = default)Access-token lifetime on the v2 session lane; a stored value overrides the 15-minute default, clamped to the session's absolute expiry.
token.refresh_expiryint, minutes10080 (7 d)> 0 (0/absent = default)How far each refresh rotation extends the session's refresh token, clamped to the session's absolute expiry.
token.session_absolute_expiryint, minutes43200 (30 d)> 0 (0/absent = default)The absolute session bound: refresh rotation never extends a session — or an access token minted on it — past login time plus this.
token.enable_cookiesbooltruetrue/falseWhether the v2 AuthService (and the federated sign-in callback) may hand a browser its refresh token in the HttpOnly opschain_refresh cookie rather than the response body.

Scalars tolerate both JSON types and env-seeded strings (240, "240", false, "false").

The product_name setting is retired: the product name is fixed (OpsChain). New session tokens stamp the fixed iss claim, and token verification never reads iss (aud is the fixed audience vocabulary — api, admin, … — not derived from the product name), so tokens minted under a previously customised value keep validating. A stored key is ignored and pruneable (opschain admin settings prune).

The retired ldap.* subtree​

The ldap.* settings (the stored subtree, the config.yaml ldap: block and the OPSCHAIN_LDAP_* environment overlay) were removed completely: a directory is a kind: ldap identity provider connection — per-instance configuration, an encrypted bind credential, a test verb and per-connection health (opschain docs identity). On the first boot after the upgrade, any remaining ldap.* values are resolved one last time (stored < file < env, bind password ladder included) and seeded into that connection, and the stored block is stripped; the retired auth_strategy/auth.providers chain selectors are read only by that seed (to carry over whether the directory lane was enabled) and are pruneable afterwards (opschain admin settings prune strips them). They no longer order the sign-in surface either: the login page renders enabled connections by the per-connection display_order (ascending, key ascending login-surface amendment), edited through the IdentityProviderService admin verbs beside display_name, and the identity settings section no longer surfaces the selectors.

Instance facts — live (per read)​

KeyType / unitsDefaultPermitted valuesRead for
maintenance_modestring enumdisabled (off)disabled | enabled | superuser_override; a legacy boolean is tolerated; anything but absent/null/disabled reads as onDisplay only: the /api/info maintenance_mode? attribute and the v2 GetInfo boot read. The Go server enforces nothing from it (opschain docs maintenance-windows). Not pruneable: pruning would silently clear the displayed flag.
bannersJSON array[]served verbatim/api/info banners / v2 GetInfo banners_json — the GUI's banner strip.
instance_infoJSON object{}served verbatim/api/info instance_info / v2 GetInfo instance_info_json — free-form instance labelling.
licencestring—the uploaded legacy licence file/api/info licence_info. Deliberately never pruneable.
chains_max_window_daysint, days90> 0 (≤ 0/absent = default)The chain explorer's maximum index window; a wider since/filter window is refused with a named error.
repo_folderstring.opschaina folder name inside the template repositoryRoots the git-committed properties/workflows walk and the runner's repo layer. Node-level settings documents override it leaf-most; change-level overrides are a recorded gap.
git_remote.periodic_fetch_intervalint, seconds900> 0The periodic-fetch interval a project git remote inherits when it does not set its own (meta.default_periodic_fetch_interval); a project settings document overrides the global value.

Notification retention — live (per hourly sweep; typed write)​

KeyType / unitsDefaultPermitted valuesRead for
notifications.feed_retention_daysint, days901–3650, clamped on read; tunable on the Enterprise tier onlyAge at which a notification is archived out of every feed (it survives as delivery evidence).
notifications.evidence_retention_daysint, days4001–3650, and never below the feed value (clamped up); Enterprise onlyAge at which the row is deleted outright.

The tier split: Basic is fixed at 30/90 — the stored keys are ignored. The typed write path (the notification governance admin surface) refuses evidence < feed and out-of-range values up front; the sweeper re-clamps defensively against hand-edited documents.

Agent governance registry — live (per read; typed write)​

Two policy keys are registry-held settings: they live in the agent-release registry, not in config.yaml and not in any settings document, and are written only through their typed admin verbs (AgentReleaseService.SetAgentReleaseStages / RenameAgentReleaseStage, EnvironmentService.UpdateEnvironment) so they are validated by name on every change and audited. Neither key is accepted in config.yaml or a PATCHed settings document. Both are read into the compiled trust snapshot, so a decision never reads the database.

KeyType / unitsDefaultPermitted valuesRead for
agents.release_stagesordered list of {name, governed}[{dev,false},{test,false},{prod,true}]≥ 2 rungs; names lowercase alphanumeric with -/_, unique, never retired; a change that removes or reorders an occupied rung, or strands a floor or grant condition, is refused by nameThe estate's release stage ladder: promotion order, which rungs are funnel-held, and the ranks every floor and grant condition compare by (opschain admin agent-release stages, rename-stage; opschain docs agent-releases).
agents.release_stage_floorstring, per environment— (no floor)a rung of agents.release_stages; "" clearsThe release stage an agent's enrolled release must hold to act under that environment; an agent without a release is refused while a floor is set (opschain nodes update <env> --release-stage-floor; opschain docs resources/environment).

Node-level settings (any node's document, converged)​

Resolved down the target path at a frozen moment (enqueue or run creation) — live per new run; running work keeps the values it was frozen with. Full semantics in opschain docs settings.

KeyType / unitsDefaultPermitted valuesResolution
runner.groupstring— (unconstrained)a registered runner-group nameChange metadata wins wholesale per field over node settings, leaf-most node wins; the global document is not consulted (the SystemConfiguration node is not an ancestor of any project). Frozen at enqueue.
runner.selectorsmap: string → string or list—registered attribute keys/values; refused at change create and settings PATCH otherwiseSame ladder; selector keys merge individually across layers.
runner.execution_scopestring— (derived: see opschain docs settings)run | step; anything else refused at change create and settings PATCH; an invalid stored value is ignored with a noticeSame ladder.
runner.max_parallel_stepsint1 (serial)≥ 1; a negative value is refused at change create, and a negative stored value is ignored with a notice at enqueue (0 = unset)Same ladder; applies to run-scoped runs only, clamped by the runner's own declared capacity.
orchestration.retries.attemptsint, total attempts— (no automatic retries)1–100; an out-of-range layer is skipped with a noticeglobal → project → environment → asset, nearest layer winning per field, frozen at run creation; a step's own retries: is most specific.
orchestration.retries.backoffduration string (30s, 2m)0≥ 0; a malformed layer is skipped with a noticeSame ladder.
orchestration.fan_out_limitint50 (engine default)≥ 1; out-of-range/malformed layer skipped with a noticeglobal → project → environment → asset, frozen at run creation; a for_each: expansion past it fails the step loudly, naming the supplying level.
orchestration.change_depth_limitint, chain hops5 (engine default)≥ 1; out-of-range/malformed layer skipped with a noticeglobal → project → environment → asset against the parent run's target path, read when the change: step is reached.
repo_folderstringthe global value, else .opschaina folder nameLeaf-most non-empty node value wins over the global.
requires_approval_fromapproval entries—retired and ignoredNever enforced by this server; stripped from every served layer. Convert stored entries to approval policies with opschain approval-policies convert-settings-approvers (see opschain docs settings).

Note the asymmetry the ladders above spell out: the orchestration.* subtree does read the global document as its base layer; the runner block does not.

Operator environment variables​

Server process (opschain server start) — restart to change​

VariableType / unitsEffect
OPSCHAIN_HOMEpathThe OpsChain home (config, keys, blobs, AGE store).
OPSCHAIN_TOKEN_SECRET_KEYstring, secretThe token secret (see token.secret_key — still required, though the v1 JWT lane it signed is retired). Environment wins over the same-named keys.env entry, which wins over the stored token.secret_key.
OPSCHAIN_PRIMARY_KEYstring, secretActiveRecord-encryption primary key (keys.env twin) — decrypts encrypted stored documents.
OPSCHAIN_KEY_DERIVATION_SALTstring, secretActiveRecord-encryption key-derivation salt (keys.env twin).
OPSCHAIN_DETERMINISTIC_KEYstring, secretProvisioned into keys.env for upstream parity; feeds only the deterministic encryption scheme, which no adopted column uses.
OPSCHAIN_ENABLE_BASIC_AUTHboolTop of the basic-auth ladder: beats config.yaml enable_basic_auth, which beats the stored setting. An unparseable value is ignored.
OPSCHAIN_LDAP_* (incl. _PASSWORD, _BASE_DN)retiredSeed input only: read once by the upgrade's boot seed into the kind: ldap connection, then ignored — remove them.
OPSCHAIN_BOOTSTRAP_ADMIN_PASSWORDstring, secretFirst-boot admin password for unattended installs. Environment only — never a config.yaml key.
OPSCHAIN_SERVER_ADMIN_TOKENstring, secretStatic admin bearer guarding the admin service on local-lane compositions only (the --admin-token flag wins over it; default off). A full-auth server refuses it with the typed ERROR_REASON_ADMIN_TOKEN_RETIRED answer and prints a boot notice.
OPSCHAIN_CLUSTER_NAMEstringThe cluster name the server reports (v2 GetInfo, fleet surfaces).
OPSCHAIN_MASTER_KEYage identity, secretThe AGE secret-store master key — wins over the key file (which must be 0600) and the OS keychain.
OPSCHAIN_TRANSPORTABLE_KEY_PATHpathFile holding the transportable encryption key, below config.yaml vault.transportable_key/transportable_key_path and above ~/.limepoint/localKey (ENVIRONMINT_KEY_PATH is its undocumented MintPress-interop fallback, only applicable to existing MintPress customers and those using the MintPress SDK or the packs:mintpress feature).
OPSCHAIN_SKIP_MIGRATION_VERIFYboolEmergency escape hatch: 1/true reports boot-time migration-ledger findings loudly on stderr instead of refusing to boot.
OPSCHAIN_VAULT_*retiredSeed input only: read once by the upgrade's boot seed — each config.yaml vault: provider key overriding its env twin — into the SecretsProvider connection, then ignored with a boot notice; remove them. The runtime vault configuration (and the OPSCHAIN_VAULT_* set injected into action-step runners) comes from the enabled provider (opschain admin secrets providers).
PGHOST / PGPORT / PGUSER / PGPASSWORD / PGDATABASE / PGSSLMODElibpq standardFill in parameters absent from the store DSN, so database credentials stay out of config.yaml.

keys.env ($OPSCHAIN_HOME/server/keys.env, 0600, written by opschain server configure) holds the four OPSCHAIN_* key-material entries; a same-named process environment variable always wins over its keys.env entry. Local mode (opschain … --local) reads neither: its SQLite store encrypts sensitive step outputs and the property/settings layers with its own generated keyset, $OPSCHAIN_HOME/local/keys.env (OPSCHAIN_PRIMARY_KEY + OPSCHAIN_KEY_DERIVATION_SALT, created on first use, 0600) — see opschain docs storage, "Local mode".

Runner daemon (opschain runner) — restart to change​

VariableType / unitsDefaultEffect
OPSCHAIN_RUNNER_MAX_PARALLEL_STEPSint0 (undeclared — follow the server's cap)The runner's declared step capacity; the --max-parallel-steps flag wins; unset, non-numeric or < 1 resolves to undeclared.
OPSCHAIN_RUNNER_POLL_TIMEOUTduration string70sLong-poll timeout for job acquisition; a malformed value falls back.
OPSCHAIN_RUNNER_RENEW_INTERVALduration string60sLease renew cadence; a malformed value falls back.
OPSCHAIN_RUNNER_ENV_PASSTHROUGHcomma-separated names—Host environment variables passed through to steps; the --env-passthrough flag wins.
OPSCHAIN_MINTPRESS_SDKpathdiscoveryExplicit path to the mintpress-sdk binary, overriding discovery (clean absence = no MintModel actions).

CLI client​

VariableEffect
OPSCHAIN_SERVERThe server target when no --server flag or active context names one.
OPSCHAIN_ADMIN_TOKENAdmin bearer for opschain admin … surfaces (below the --auth-token flag and your stored login, above the token stored by opschain admin login). On a full-auth server it must carry a real credential — typically a service-account API key; the server's static admin token is refused there.
OPSCHAIN_TTYalways/never forces or suppresses terminal rendering (otherwise real TTY detection; TERM=dumb forces plain).
OPSCHAIN_HOMEAs above — also the CLI's contexts/credentials home.

Injected, not operator-set​

These appear in step/runner environments because the server put them there; setting them by hand does nothing useful and may break a step: OPSCHAIN_API_URL, OPSCHAIN_STEP_TOKEN, OPSCHAIN_TRACE_ID, OPSCHAIN_PROPERTIES, OPSCHAIN_EVENTS, OPSCHAIN_OUTPUT, OPSCHAIN_OUTPUT_SENSITIVE, OPSCHAIN_DRY_RUN, OPSCHAIN_PACKS_DIR, OPSCHAIN_GIT_ASKPASS_USER/_SECRET, OPSCHAIN_CONTEXT_SCHEMA_VERSION, OPSCHAIN_WORKER_STEP_ID, the OPSCHAIN_MINTMODEL_* render-lane variables, and the projected OPSCHAIN_VAULT_* set.

config.yaml​

Deploy-authoritative, strict-parsed, read once at server start — restart to change anything in it. The full key catalog with types and defaults is opschain docs config; it also spells out exactly which keys have flag twins (listen, store, tls_cert, tls_key) and which have environment overrides (the ladders above).

Precedence ladders at a glance​

ConcernLadder (lowest → highest)
Token secretstored token.secret_key → keys.env OPSCHAIN_TOKEN_SECRET_KEY → environment OPSCHAIN_TOKEN_SECRET_KEY
Basic authstored enable_basic_auth → config.yaml enable_basic_auth → OPSCHAIN_ENABLE_BASIC_AUTH
Vaultthe enabled SecretsProvider connection (the retired OPSCHAIN_VAULT_* → vault: ladder is seed input only)
listen / store / TLSconfig.yaml → flag
runner placementnode settings (leaf-most; no global layer) → change metadata (per field)
orchestration.*engine default → global → project → environment → asset (→ the step's own declaration, for retries)
repo_foldercompiled .opschain → global → node documents (leaf-most)
Agent release stagethe ladder agents.release_stages (registry) → the enrolment floor agents.release_stage (config.yaml) → the environment floor agents.release_stage_floor (registry, per environment) → the grant's release_stage condition — each a stricter gate, none overriding another

An overlay never blanks a lower value — it wins only where it is set.

Known gaps (flagged for follow-up, deliberately not fixed here)​

  • The GUI settings JSON schemas are Rails-era: they still offer pruned legacy keys (pod_per_change_step, image_reuse, pod_templates, …) and know nothing of the current Go keys (orchestration.*, runner.execution_scope, runner.max_parallel_steps, notifications.*). The settings editor's suggestions therefore do not match this page.
  • repo_folder override comments contradict the code and opschain docs settings: PGSource.GlobalRepoFolder's comment calls node/change-level overrides a recorded gap, but node-level overrides are applied (serve/entrygate.go resolveRepoFolder, leaf-most wins) — only the change-level override remains a real gap.
  • opschain docs settings — the configuration model: documents, versions, convergence and inheritance.
  • opschain docs config — the deploy-authoritative config.yaml catalog.
  • opschain docs identity — the authentication stack these ladders configure.
  • opschain docs cli/admin-settings-prune — stripping legacy stored keys.
  • opschain docs fleet-queue and opschain docs dispatch — how the runner block places and pins work.