Crux Daemon · 5. Configuration reference
The Crux Daemon is configured entirely by environment variables, with an optional YAML file covering 26 keys. This chapter is the complete list. Read §5.1 before you read anything else: four properties of the configuration surface will bite you, and three of them are silent.
This chapter is reference. The traps are in §5.1 to §5.6; the tables are §5.9 onward.
5.0 In plain English
The daemon has no settings screen and no configuration wizard in its request path. Every dial it has is an environment variable, plus an optional YAML file covering 26 keys. This chapter is the full dial board: 393 variables, each with its type, its default, what it actually changes, and the code that reads it. Think of it less as a manual and more as a parts catalogue. Nobody reads it end to end; you come here to look one thing up.
Configuring by environment is a deliberate trade. It means the daemon deploys identically on a laptop, in a container and on a host with no config management, because the environment is the only input it needs. What you give up is a validation pass. There is no schema check that tells you a variable name was misspelled, and an unknown variable is simply an unknown variable: it sits in the environment doing nothing, and nothing complains.
You come here in one of two situations. Either you are setting the daemon up and need the correct name and default for something, in which case go to the topic tables from §5.9 onward. Or, far more often, you set a flag, restarted, and the behaviour did not change. That is the case §5.1 to §5.6 exists for, and it is worth reading those six sections once in full even when nothing is broken, because they describe failures that produce no error and no log line.
The one thing people get wrong, above every other trap in this chapter, is assuming that a boolean is a boolean. It is not. Nine mutually incompatible parsing rules are in use across the codebase, so yes enables some flags and silently leaves others off; CRUX_PASSPORT_REVOCATION=yes reads to a human as "revocation on" and actually turns it off. Use =1 to enable and =0 to disable, always, everywhere. It is the only pair of values that means the same thing under all nine rules.
Two more that catch people in the same way, both silent: a YAML file that fails to read or parse produces no error at all and is indistinguishable from having no file, and the default data directory is a relative path, so starting the daemon from a different working directory silently gives you a different, empty store. Set CORECRUXD_DATA_DIR to an absolute path before you do anything else.
5.1 Read this first: four things that fail silently
1. Booleans are parsed by nine mutually incompatible rules. A value like yes, on or True enables some flags and silently leaves others off. CRUX_PASSPORT_REVOCATION=yes reads to a human as "revocation on" and actually turns it off. The nine rules are enumerated in §5.5. 1 is the only value that works under every rule in this codebase. Use =1 to enable and =0 to disable, and nothing else.
2. Config-file read and parse failures are entirely silent. A YAML syntax error, a typo'd path, or a permission problem produces no log line and no error. The daemon boots with an empty file config and every value falls back to its default. A broken config.yaml looks exactly like "no config file" (config.rs:709).
3. An unset XDG_CONFIG_HOME disables file configuration outright. There is no ~/.config/crux/config.yaml fallback. If XDG_CONFIG_HOME is unset, common on macOS and many Linux desktops, the daemon reads no config file at all unless CORECRUXD_CONFIG_PATH is set explicitly (config.rs:728).
4. The default data_dir is the relative path ../CoreCruxData/v1. It resolves against the daemon's working directory (config.rs:838). Running corecruxd from two different directories gives you two different data directories, and the LOCK single-instance guard cannot catch it because they are different locks. Always set CORECRUXD_DATA_DIR to an absolute path.
Two more, less dangerous but equally silent: an unparseable host or port falls back to the default with no warning (config.rs:800), and RUST_LOG silently overrides CORECRUXD_LOG_LEVEL entirely (main.rs:2066).
5.2 How much of this surface is documented in the repository
| Bucket | Count |
|---|---|
Distinct environment variables read anywhere in crates/ | 393 |
, CORECRUXD_* | 306 |
, CRUX_* | 51 |
, CORECRUX_* | 15 |
, OS, toolchain and third-party (HOME, PATH, USER, HOSTNAME, XDG_*, CARGO*, VAULT_*, OTEL_*, RUST_LOG, OPENAI_API_KEY, LOG_FORMAT, CLAUDE_PROJECT_DIR, …) | 21 |
Compile-time only (env! / option_env!) | 4 |
| Test-only, every read site is test or example code | 14 |
Documented in config.example.env | 96 |
| Documented but read nowhere in code, stale | 3 |
Read in code but absent from config.example.env | 299 |
| YAML config-file keys | 26 across 6 sections |
| Distinct boolean-parsing rules | 9 |
The existing configuration documentation covers about 24% of the surface: config.example.env documents 96 of roughly 363 production runtime variables. Three variables it documents do not exist in the code at all, see §5.8.
All eight cargo feature flags across the four crates that declare them, corecrux-memory, corecrux-storage, corecruxctl and corecruxd, are off by default. On corecruxd alone the count is four (otel, wasm-extensions, dense-embed-model, hosted-surfaces); both figures appear in this documentation and they are different populations, not a contradiction. See chapter 3 §3.7 for the complete register.
5.3 The resolution model
corecruxd is environment-variable-first with an optional YAML overlay. The module doc states it plainly: "Daemon configuration: parses CORECRUXD_* environment variables into a typed Config at startup" (config.rs:6).
Order of resolution (config.rs:793): the YAML file is loaded first into a FileConfig, then every field resolves as env → file → hard-coded default. Env always wins.
Config-file discovery, configured_config_path() (config.rs:723):
CORECRUXD_CONFIG_PATHif set and non-blank, after path expansion (config.rs:724).- Else, only if
XDG_CONFIG_HOMEis set and non-blank,$XDG_CONFIG_HOME/crux/config.yaml(config.rs:728). - Else
None, no file is read.
Config-file failure modes, load_file_config() (config.rs:709):
| Situation | Behaviour | Location |
|---|---|---|
| No path resolved | Empty file config | config.rs:710 |
| File read, YAML parses | Used | config.rs:715 |
| File read, YAML malformed | Empty file config, the parse error is discarded | config.rs:716 |
| File not found | Empty file config | config.rs:718 |
| Any other read error, e.g. permissions | Empty file config, discarded | config.rs:719 |
There is one saving grace. Because daemon.auth_mode is a file key, a malformed YAML that was meant to supply it instead trips the "must be set explicitly" abort at main.rs:304, which at least fails closed, though with a message pointing at the env var rather than at your broken file.
Path expansion, expand_config_value (config.rs:776), substitutes exactly four tokens, in order: $XDG_STATE_HOME (only if set and non-empty), $XDG_CONFIG_HOME (same), $HOME, and a leading ~/. It is applied to data_dir, state_dir, the config path itself and the passport key path. It is not general shell expansion.
Two helper behaviours worth knowing: env_string (config.rs:734) filters out empty strings, so FOO= is identical to FOO being unset for every string-valued setting; and env_csv (config.rs:753) splits on commas, trims each part and drops empties.
5.4 Logging precedence
init_tracing builds its filter as (main.rs:2066):
let filter = tracing_subscriber::EnvFilter::try_from_default_env()
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new(level));
try_from_default_env() reads RUST_LOG. The precedence is therefore RUST_LOG > CORECRUXD_LOG_LEVEL > info. If RUST_LOG is set and valid it wins outright and CORECRUXD_LOG_LEVEL is ignored entirely.
The output format is selected by LOG_FORMAT, not by CORECRUX_LOG_FORMAT (main.rs:2068). CORECRUX_LOG_FORMAT is read by no code anywhere, yet it is set in the Dockerfile, the Helm chart, both compose files and config.example.env. JSON logging is silently off in every shipped manifest. This is defect B1 in chapter 16. Document and set LOG_FORMAT=json.
5.5 The nine boolean rules
Boolean environment variables in this workspace are parsed by nine mutually incompatible rules. This is the single biggest correctness hazard in the configuration surface.
| ID | Exact rule | Trimmed? | Case-insensitive? | Unset means | Defined at | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| T1 | `matches!(v, "1" \ | "true" \ | "TRUE" \ | "yes" \ | "YES")` | no | partial, only the listed spellings | false | config.rs:765 (bool_value) | ||
| T2 | v.trim() != "0" && !v.trim().eq_ignore_ascii_case("false") | yes | yes | true | config.rs:744 (env_default_on) | ||||||
| T3 | `matches!(v.trim(), "1" \ | "true" \ | "TRUE" \ | "yes" \ | "YES" \ | "on" \ | "ON")` | yes | no: On and True fail | false | auth.rs:139, auth_rails.rs:61 |
| T4 | `matches!(v.trim().to_lowercase(), "1" \ | "true" \ | "yes" \ | "on")` | yes | yes | false | agentgraph_kinds.rs:132, tools/facts.rs:26 | |||
| T5 | `!matches!(v.trim().to_ascii_lowercase(), "" \ | "0" \ | "false" \ | "off" \ | "no")`, anything else is on | yes | yes | false or true, varies per call site | activity.rs:81, traces.rs:75, ledger.rs:63 | ||
| T5b | As T5 but the off-set omits "no", so no is truthy | yes | yes | false | tools/reuse.rs:38, tools/engrams.rs:36, tools/autonomy.rs:46 | ||||||
| T6 | `v == "1" \ | \ | v.eq_ignore_ascii_case("true"), **yes and on` do not work** | no | only for true | false or true per site | dispatch.rs:116, server.rs:88, legal_holds.rs:34 | ||||
| T7 | Identical to T5, separate helper | yes | yes | false | workspace_scan_manifests.rs:31 | ||||||
| T8 | `matches!(v.trim().to_ascii_lowercase(), "1" \ | "true" \ | "yes" \ | "on")` | yes | yes | false | http/extensions.rs:45, studio_library.rs:90 | |||
| T9 | `matches!(v.trim().to_ascii_lowercase(), "1" \ | "true" \ | "on" \ | "yes")`, order differs only | yes | yes | false | incidents.rs:170 |
Three further one-off shapes exist:
matches!(v.as_deref(), Some("1") \| Some("true") \| Some("TRUE") \| Some("on")),yesdoes not work (provenance.rs:56).matches!(v.as_deref(), Ok("1" \| "on")),truedoes not work (snapshot_sync.rs:84, forCRUX_COMPACTION_SYNC).- An
"off"sentinel where any other value, including unset, means on, thecrux-hookfamily, e.g. session_start.rs:80.
The dangerous one is CRUX_PASSPORT_REVOCATION. It is default-on when unset, but once set only 1 or a case-insensitive true keeps it on, and it does not trim. =yes, =on, =enabled and =TRUE all silently disable revocation enforcement (dispatch.rs:115). A security control that fails open. See chapter 16 defect B6.
5.6 The no-trim cluster: a container-deployment hazard
Six boolean flags parse with no .trim(). A trailing newline or space, routine with systemd EnvironmentFile=, docker --env-file and Helm configMapKeyRef, makes them silently off, with no warning.
| Variable | Read at |
|---|---|
CORECRUXD_ALLOW_INSECURE_DEV_AUTH_BIND | main.rs:1959 |
CRUX_MCP_ALLOW_EMPTY_AGENT_REGISTRY | main.rs:1970 |
CORECRUXD_PUBLIC_PROBES_MINIMAL | health.rs:65 |
CORECRUXD_SYNC_ENABLED | health.rs:679, config.rs:1294 |
CORECRUXD_EMBEDDING_PROBE_ALLOW_LOCAL | console.rs:1850 |
CORECRUXD_ALLOW_WEAK_HS256_SECRET | auth.rs:358 |
A related case-sensitivity split: CORECRUXD_TS_IDENTITY_ENABLED=True is off (T3), while CORECRUXD_OBSERVE=True is on (T4).
5.7 Variables that are startup-fatal
| Variable | Failure mode | Guard |
|---|---|---|
CORECRUXD_AUTH_MODE | Refuses to boot when neither it nor daemon.auth_mode is set. A present-but-unparseable value aborts separately. | main.rs:304, main.rs:313 |
CORECRUXD_JWT_HS256_SECRET | Fatal under jwt_hs256. Also rejected below 32 bytes unless CORECRUXD_ALLOW_WEAK_HS256_SECRET is set. | auth.rs:238 |
CRUX_AGENT_TOKEN / CRUX_AGENT_TOKENS | Fail-closed: if either is set but any token violates the 32..=256-byte [A-Za-z0-9._~-] policy, startup aborts. Unset is fine. | agent.rs:74 |
CORECRUXD_EMBED_DELEGATE_URL / _TOKEN / _DIMENSIONS | Fatal as a set: once any of the three is present, an incomplete or ambiguous combination aborts with one of five distinct messages. | config.rs:609 |
VAULT_ADDR, VAULT_TOKEN | Hard error when the Vault-PKI C2PA X.509 signer is selected. Empty-after-trim counts as missing. In the witness path the same absence is caught, warned, and falls through to the in-process env key. | vault_pki_x509_signer.rs:147; non-fatal at witness_submit.rs:447 |
CORECRUXD_C2PA_LEAF_TTL_HOURS | Hard error if set but unparseable as u64. Unset is fine. | vault_pki_x509_signer.rs:183 |
CORECRUXD_WITNESS_VAULT_KEY | Error when the Vault-Transit witness signer is built, but caught and downgraded to a warning with fallback to CORECRUXD_WITNESS_SIGNING_KEY. Not fatal. | witness_submit.rs:200 |
CORECRUXCTL_ENV | CLI error if set to anything other than local, staging or production. | tooling_env.rs:44 |
CRUX_C2PA_VERIFY_PUBLIC_KEY_HEX | CLI error when corecruxctl output verify runs without --pub-key-hex. Must be exactly 64 hex chars. | output_verify.rs:54 |
CORECRUXD_EMBEDDING_URL | CLI error for corecruxctl ingest --embed. Optional in the daemon. | ingest.rs:599 |
CRUX_LLM_SHIM, CRUX_CLOUD_WITNESS | The shim and witness subcommands refuse to run unless set to 1 or true. | llm_shim/mod.rs:232 |
CORECRUXD_WORKSPACE_PATH | The workspace-scan surface is inert without it. Not fatal to boot. | workspace_scan.rs:274 |
CORECRUXD_SYNC_REMOTE_URL, CORECRUXD_SYNC_API_KEY | The MCP sync_* tools return "sync not configured". Not fatal to boot. | tools/sync.rs:24 |
CARGO_PKG_VERSION, CARGO_MANIFEST_DIR | Compile-time env!(), the build fails if absent. Always set by Cargo. | build.rs:51 |
Everything else in this chapter has a default and is safe to leave unset.
5.8 Documented but not read: three phantom knobs
| Variable | Documented at | Reality |
|---|---|---|
CORECRUX_LOG_FORMAT | config.example.env:153 | No such variable exists. The code reads LOG_FORMAT (main.rs:2068). The wrong name is also baked into the Dockerfile, both compose files, the quickstart README and the Helm chart, so JSON logging is silently off wherever those manifests are used. |
CORECRUXD_DEBUG_ERRORS | config.example.env:433 | Not read anywhere. Documented as "Include internal topology in error responses", the knob does not exist. |
CORECRUXD_SESSION_TTL_DEFAULT | config.example.env:436 | Not read anywhere. Documented as "Default session TTL in seconds", the knob does not exist. |
5.9 The YAML config file: every key
The file schema is exhaustively defined by FileConfig and its five sub-structs (config.rs:642-706). Every field is Option<T> and #[serde(default)], so unknown keys are ignored and missing keys are absent. Precedence is env var, then file key, then hard-coded default, for every row.
| YAML key | Type | Overriding env var | Default | Deserialised at |
|---|---|---|---|---|
daemon.instance_id | string | CORECRUXD_NODE_ID | none (derived) | config.rs:656, read :846 |
daemon.state_dir | string path | CORECRUXD_STATE_DIR | falls back to data_dir | config.rs:657, read :839 |
daemon.data_dir | string path | CORECRUXD_DATA_DIR | ../CoreCruxData/v1 | config.rs:658, read :834, undocumented in config.example.yaml |
daemon.listen_addr | string IP | CORECRUXD_HTTP_HOST / _GRPC_HOST / _MCP_HOST | 127.0.0.1 | config.rs:659 |
daemon.http_port | u16 | CORECRUXD_HTTP_PORT | 14800 | config.rs:660 |
daemon.grpc_port | u16 | CORECRUXD_GRPC_PORT | 4007 | config.rs:661 |
daemon.mcp_port | u16 | CORECRUXD_MCP_PORT | 14801 | config.rs:662 |
daemon.mcp_enabled | bool | CORECRUXD_MCP_ENABLED | true | config.rs:663 |
daemon.auth_mode | string | CORECRUXD_AUTH_MODE | none, startup-fatal | config.rs:664, read :876 |
passport.key_path | string path | CORECRUXD_PASSPORT_KEY_PATH | <state_dir>/passport.key | config.rs:670 |
passport.claim_on_startup | bool | CORECRUXD_PASSPORT_CLAIM_ON_STARTUP | true | config.rs:671 |
passport.claim_endpoint | string URL | CRUX_PASSPORT_CLAIM_ENDPOINT, then CORECRUXD_PASSPORT_CLAIM_ENDPOINT | https://passport.vaultcrux.com/v1/claim-anonymous | config.rs:672 |
content.manifest_path | string path | CORECRUXD_CONTENT_MANIFEST_PATH | none | config.rs:678 |
content.verify_signatures | bool | CORECRUXD_CONTENT_VERIFY_SIGNATURES | true | config.rs:679 |
router.refresh_interval_seconds | u64 | CORECRUXD_ROUTER_REFRESH_INTERVAL_SECONDS | 60, clamped 1..=86400 | config.rs:685 |
router.cache_ttl_seconds | u64 | CORECRUXD_ROUTER_CACHE_TTL_SECONDS | 60, clamped 1..=86400 | config.rs:686 |
router.fallback_policy | string | CORECRUXD_ROUTER_FALLBACK_POLICY | degrade_to_local | config.rs:687 |
enterprise.enabled | bool | CORECRUXD_ENTERPRISE_ENABLED | false | config.rs:693 |
enterprise.customer_id | string | CORECRUXD_ENTERPRISE_CUSTOMER_ID | "" | config.rs:694 |
enterprise.backend_id | string | CORECRUXD_ENTERPRISE_BACKEND_ID | "" | config.rs:695 |
enterprise.trust_root_kid | string | CORECRUXD_ENTERPRISE_TRUST_ROOT_KID | "" | config.rs:696 |
enterprise.trusted_issuer_kids | list of string | CORECRUXD_ENTERPRISE_TRUSTED_ISSUER_KIDS (CSV) | [] | config.rs:697 |
enterprise.airgap | bool | CORECRUXD_ENTERPRISE_AIRGAP | true | config.rs:698 |
enterprise.allow_vaultcrux_cross_sign | bool | CORECRUXD_ENTERPRISE_ALLOW_VAULTCRUX_CROSS_SIGN | false | config.rs:699 |
llm.endpoint | string URL | CORECRUXD_LLM_ENDPOINT | none | config.rs:705 |
llm.model | string | CORECRUXD_LLM_MODEL | none | config.rs:706 |
That is 26 keys against 393 environment variables. Any document presenting config.example.yaml as "the configuration file" without saying that roughly 93% of configuration is environment-only is misleading. Two further gaps in the shipped example: daemon.data_dir is absent from config.example.yaml even though it takes precedence over daemon.state_dir, and CORECRUXD_CONFIG_PATH is documented in neither example file.
One nuance on the auth-mode rule. auth_mode_raw is env_string("CORECRUXD_AUTH_MODE").or(file_config.daemon.auth_mode) (config.rs:876). So "CORECRUXD_AUTH_MODE has no default and the daemon refuses to start without it" is true but incomplete: setting daemon.auth_mode in the YAML file satisfies the requirement equally, and config.example.yaml:12 does exactly that.
Sources for §5.1 to §5.9
- crates/corecruxd/src/config.rs:793,
load_config - crates/corecruxd/src/config.rs:709,
load_file_config, the silent failures - crates/corecruxd/src/config.rs:723,
configured_config_path - crates/corecruxd/src/config.rs:642,
FileConfig - crates/corecruxd/src/config.rs:744,
env_default_on - crates/corecruxd/src/config.rs:765,
bool_value - crates/corecruxd/src/main.rs:2066,
RUST_LOGprecedence - crates/crux-mcp/src/dispatch.rs:115, the fail-open revocation flag
The reference tables follow in §5.10 onward. The Flag column gives the default state of a boolean feature flag; Parse cites a rule from §5.5.
5.10 Variables read from more than one place, with different behaviour
Each row is a live inconsistency, not a documentation nit. If you set one of these, know which consumer you are configuring.
| # | Variable | Divergence |
|---|---|---|
| 1 | CORECRUXD_FEATURE_AUDIT_EXPORT | Same default (off), incompatible parse rules: T6 gates the tool; a T3-like rule drives the custody scorecard. =yes makes the scorecard report audit_export_online: true while the tool is disabled. audit_export.rs:61 vs context_custody_audit.rs:113 |
| 2 | CORECRUXD_FEATURE_RECEIPT_VERIFY | Same default (off): T5 at the tool, a strict allow-list at the scorecard. =enabled turns the tool on while the scorecard reports off. receipt_verify.rs:52 |
| 3 | CORECRUXD_SYNC_REMOTE_URL | Three different fallbacks: hard error, None, and false. Two sites do not trim and one does, so " " reads as configured to the sync client and not configured to the scorecard. tools/sync.rs:24 |
| 4 | CORECRUXD_SYNC_API_KEY | Hard error at one site, a boolean "configured" at another; config.rs uses unwrap_or_default(), i.e. the empty string. config.rs:1298 |
| 5 | CORECRUXD_SYNC_ENABLED | T1 at both sites, untrimmed and case-sensitive. " 1" is false at both. config.rs:1294 |
| 6 | CORECRUXD_DATA_DIR | Three different defaults for the same variable: ../CoreCruxData/v1 after the YAML fallback chain in the daemon; the same literal in the MCP sync client but without the YAML fallback and without trimming; and no default at all in corecruxctl. config.rs:834 |
| 7 | CRUX_AGENT_TOKEN | Two consumers, two validations: a strict 32..=256-byte charset policy that aborts startup, versus "any non-blank trimmed string" accepted as an outbound bearer. agent.rs:79 vs loopback_auth.rs:226 |
| 8 | CORECRUXD_JWT_HS256_SECRET | Fatal if missing in the daemon's auth path; silently returns None and falls back to an opaque bearer in the MCP loopback minter. auth.rs:238 vs loopback_auth.rs:180 |
| 9 | CORECRUXD_ENGINE_BASE_URL / _API_KEY | The console proxy treats absence as "not configured"; the memory snapshot sync treats absence as a fail-closed gate together with CORECRUXD_ENGINE_TENANT_ID. Different trimming. engine_console.rs:240 vs snapshot_sync.rs:115 |
| 10 | VAULT_ADDR / VAULT_TOKEN | Read by two independent subsystems with the same names and the same fatal semantics but different error types and different companion variables (CORECRUXD_VAULT_PKI_MOUNT versus CORECRUXD_WITNESS_VAULT_MOUNT). A host configured for one is implicitly configured for the other. |
| 11 | Default-on flags parsed with T6 | CORECRUXD_FEATURE_SCOPED_FORGET, CRUX_PASSPORT_REVOCATION and CRUX_AGENT_CARD default on but use T6, so =yes, =on and =enabled silently disable them. The T5-based default-on flags (CORECRUXD_FEATURE_TOOL_TRACES, _MEMORY_PANEL, _FRESHNESS, _CONSOLIDATION) keep those same strings on. Opposite behaviour, same-looking flag family. |
| 12 | CORECRUXD_QUERY_TEXT_SEARCH versus its siblings | is_query_feature_enabled special-cases this one name to the default-on helper (T2) and applies T6 to every other name it is passed. One function, two semantics, selected by string comparison. http/mod.rs:1878 |
| 13 | CORECRUXD_PASSPORT_KEY_PATH versus CRUX_PASSPORT_KEY_PATH | Two names for one concept. The daemon reads only CORECRUXD_*; corecruxctl and the hooks check CRUX_* first. Setting only CRUX_PASSPORT_KEY_PATH makes the CLI and the daemon disagree about which key is in use. config.rs:887 |
| 14 | CORECRUXD_AGENTGRAPH | Advertised but never read. route_auth.rs:528 declares it as the feature gate for /v1/orchestrators and /v1/punchcards, but the real gates are CORECRUXD_ORCHESTRATORS and CORECRUXD_PUNCHCARD. Every other feature-env label in that file resolves to a real variable; this one alone names a variable that does nothing. |
| 15 | CORECRUXD_REPLICATION_AUTH_BEARER | Security-relevant. main.rs:2005 treats it as presence-only and reports "not configured" in readiness when unset, but grpc.rs:860 substitutes the hardcoded literal replication:write and sends it as a real bearer. Operators reading /readyz believe replication auth is unconfigured while a guessable static credential is on the wire. |
| 16 | CORECRUXD_SYNC_REMOTE_URL (fourth site) | health.rs:682 does not trim; admin.rs:2509 does. A whitespace-only value reads as configured in /readyz and not configured in the admin privacy report. |
| 17 | CORECRUXD_EMBEDDING_URL | console.rs:151 does not trim when reporting the active endpoint; console.rs:1856 trims and parses for the probe-origin allowlist. A whitespace-padded URL is reported as active but fails its own SSRF exemption. |
| 18 | CORECRUXD_DATA_DIR (fourth site) | activity.rs:598 reads it independently of the config chain: unset, or a create_dir_all failure, silently leaves the activity journal in memory only, no durable audit log, no error. |
| 19 | CORECRUXD_HTTP_ACCEPT_AGENT_TOKENS | Read through two separate truthy helpers with currently identical semantics that can drift independently. auth.rs:147 vs infra.rs:69 |
5.11 Ports, planes, process identity
| Name | Type | Default | Flag | Parse | Effect | Read at |
|---|---|---|---|---|---|---|
CORECRUXD_HTTP_HOST | IpAddr | 127.0.0.1: unparseable falls back to loopback, never errors | - | , | HTTP API bind address | config.rs:796 |
CORECRUXD_HTTP_PORT | u16 | 14800 | - | , | HTTP API port, serving /healthz, /readyz, /metrics | config.rs:801 |
CORECRUXD_GRPC_HOST | IpAddr | 127.0.0.1 | - | , | gRPC bind address | config.rs:807 |
CORECRUXD_GRPC_PORT | u16 | 4007 | - | , | gRPC port | config.rs:812 |
CORECRUXD_MCP_HOST | IpAddr | 127.0.0.1 | - | , | MCP bind address | config.rs:817 |
CORECRUXD_MCP_PORT | u16 | 14801 | - | , | Built-in MCP server port, JSON-RPC over Streamable HTTP | config.rs:822 |
CORECRUXD_MCP_ENABLED | bool | true | ON | T1 | Disable the built-in MCP server entirely | config.rs:827 |
CORECRUXD_CONSOLE_ENABLED | bool | true | ON | T1 | Serve the embedded console SPA | config.rs:830 |
CORECRUXD_SERVICE | string | corecruxd | - | , | Service name in logs and metrics | config.rs:844 |
CORECRUXD_CLUSTER_ID | string | dev | - | , | Cluster identifier | config.rs:845 |
CORECRUXD_NODE_ID | string | derived | - | , | Override the derived node id | config.rs:846 |
CORECRUX_NODE_ID | string | falls back to HOSTNAME, then unknown-node | - | , | Node id for corecruxctl storage operations | storage.rs:680 |
CORECRUXD_LOG_LEVEL | string | info | - | , | Tracing level. Completely overridden by RUST_LOG when that is set | config.rs:843 |
RUST_LOG | string | unset | - | EnvFilter directive syntax | Read implicitly by EnvFilter::try_from_default_env(); takes full precedence over CORECRUXD_LOG_LEVEL. Undocumented in the repository | main.rs:2066 |
LOG_FORMAT | string | "" (human-readable) | - | eq_ignore_ascii_case("json") | Tracing output format. The manifests all say CORECRUX_LOG_FORMAT; that name is never read | main.rs:2068 |
CORECRUXD_CONFIG_PATH | path | $XDG_CONFIG_HOME/crux/config.yaml, else no file | - | , | Explicit YAML config path | config.rs:724 |
CORECRUXD_IO_BACKEND | string | cpu | - | , | IO backend selection | config.rs:952 |
CORECRUXD_OPERATING_MODE / CRUX_OPERATING_MODE | enum | OperatingMode::default() | - | OperatingMode::parse | Reported product posture; CORECRUXD_* wins | config.rs:941 |
CORECRUXD_ENABLED_PRO_SERVICES / CRUX_ENABLED_PRO_SERVICES | CSV | [] | - | CSV, blanks dropped | Declared entitlements | config.rs:946 |
CORECRUXD_DEV_SPLIT_SHARDS | u32 | 4 | - | , | Dev-mode shard split count | config.rs:854 |
CORECRUXD_ROUTING_RELOAD_INTERVAL_MS | u64 | 1000 | - | , | Routing table reload cadence | config.rs:847 |
CORECRUXD_ROUTING_STRICT_CLIENT_VERSION | bool | false | OFF | T1 inline | Reject clients on version skew | config.rs:851 |
CORECRUXD_ROUTER_REFRESH_INTERVAL_SECONDS | u64 | 60, clamped 1..=86400 | - | , | Router refresh cadence | config.rs:903 |
CORECRUXD_ROUTER_CACHE_TTL_SECONDS | u64 | 60, clamped 1..=86400 | - | , | Router cache TTL | config.rs:909 |
CORECRUXD_ROUTER_FALLBACK_POLICY | string | degrade_to_local | - | , | Behaviour when the router is unreachable | config.rs:915 |
CORECRUXD_PUBLIC_PROBES_MINIMAL | bool | false | OFF | T1 inline, untrimmed | Strip routing, valve and check detail from unauthenticated /healthz and /readyz | health.rs:65 |
USER | string | local | - | , | Local passport owner name | session.rs:110 |
HOSTNAME | string | reads /etc/hostname, then unknown-node | - | , | Host identity for config bundles and node id | config_bundle.rs:42 |
5.12 Auth, identity, access control
| Name | Type | Default | Flag | Parse | Effect | Read at | |
|---|---|---|---|---|---|---|---|
CORECRUXD_AUTH_MODE | enum | none, startup-fatal | - | AuthMode::parse; an unknown value is also fatal | off / dev_scopes / jwt_hs256 / jwt_jwks | config.rs:876 | |
CORECRUXD_JWT_HS256_SECRET | secret | none, fatal in jwt_hs256 | - | at least 32 bytes unless overridden | HS256 verification key; also mints MCP loopback JWTs | auth.rs:238 | |
CORECRUXD_ALLOW_WEAK_HS256_SECRET | bool | false | OFF | T1, untrimmed | Permit an HS256 secret shorter than 32 bytes | auth.rs:358 | |
CORECRUXD_JWT_ISS | string | none | - | , | Expected and emitted iss claim | auth.rs:241 | |
CORECRUXD_JWT_AUD | string | none | - | , | Expected and emitted aud claim | auth.rs:242 | |
CORECRUXD_JWT_ALGS | CSV | default set; an invalid value is fatal | - | parse_jwt_algs | Allowed JWT signature algorithms | auth.rs:258 | |
CORECRUXD_JWT_JWKS_JSON, alias CORECRUXD_JWKS_JSON | JSON string | none | - | first non-error wins | Inline JWKS document | auth.rs:272 | |
CORECRUXD_JWT_JWKS_PATH, alias CORECRUXD_JWKS_PATH | path | none | - | first non-error wins | JWKS file on disk | auth.rs:275 | |
CORECRUXD_JWT_JWKS_URL, alias CORECRUXD_JWKS_URL | URL | none | - | first non-error wins | JWKS endpoint | auth.rs:278 | |
CORECRUXD_JWT_OIDC_DISCOVERY_URL, alias CORECRUXD_OIDC_DISCOVERY_URL | URL | none | - | first non-error wins | OIDC discovery for JWKS resolution | auth.rs:281 | |
CORECRUXD_JWT_JWKS_MIN_REFRESH_SECONDS | u64 | 30 | - | , | JWKS refresh floor | auth.rs:260 | |
CORECRUXD_HTTP_ACCEPT_AGENT_TOKENS | bool | false | OFF | T3 | Accept MCP agent tokens on the HTTP API under a JWT mode | auth.rs:147 | |
CORECRUXD_AGENT_TOKEN_HTTP_SCOPES | space or comma list | admin:read admin:write facts:write query:read sessions:read sessions:write | - | parse_scopes; an empty result falls back to the default | Scopes granted to an HTTP-accepted agent token. The default includes admin:write | auth.rs:157 | |
CORECRUXD_AGENT_TOKEN_HTTP_TENANT | string | *, all tenants | - | , | Tenant binding for HTTP-accepted agent tokens | auth.rs:162 | |
CRUX_AGENT_TOKEN | secret | none, MCP auth disabled | - | 32..=256 bytes, [A-Za-z0-9._~-]; a violation aborts startup | Single-agent MCP bearer, agent name default | agent.rs:79 | |
CRUX_AGENT_TOKENS | name:token,… | none | - | same policy per token; any bad entry aborts startup | Multi-agent MCP token registry | agent.rs:74 | |
CRUX_MCP_ALLOW_EMPTY_AGENT_REGISTRY | bool | false | OFF | T1, untrimmed | Dev and test only. Boot with MCP auth disabled even when a token variable is set but invalid | main.rs:1970 | |
CORECRUXD_ALLOW_INSECURE_DEV_AUTH_BIND | bool | false | OFF | T1, untrimmed | Allow a dev auth mode, or MCP with no agent token, to bind a non-loopback address | main.rs:1959 | |
CORECRUXD_ROUTE_AUTH | enum | shadow: any unrecognised value, including unset | - | trimmed and lowercased; off and enforce are explicit | Per-route auth contract enforcement posture | route_auth.rs:579 | |
CORECRUXD_TENANT_WRITE_STAMP | enum | Off (fail-safe) | OFF | trimmed and lowercased; 1/true/on/enforce mean on, shadow/audit mean shadow, everything else means off | Stamp the tenant id on writes | auth.rs:979 | |
CORECRUXD_TS_IDENTITY_ENABLED | bool | false, routes 404 | OFF | T3 | Tailscale identity rail: /v1/auth/whoami, /v1/auth/tailscale/token | auth_rails.rs:185 | |
CORECRUXD_TS_IDENTITY_ALLOWLIST | `login=tenant:scopeA\ | scopeB,…` | ""; nobody allowlisted | - | parse_ts_allowlist; malformed entries skipped, logins lowercased | Authoritative tenant and scope mapping for tailnet logins | auth_rails.rs:190 |
CORECRUXD_TS_TRUSTED_PROXY_CIDRS | CSV CIDR | [], loopback always trusted | - | parse_cidr per entry | Extra peers permitted to present identity headers | auth_rails.rs:160 | |
CORECRUXD_DEVICE_GRANT_ENABLED | bool | false, routes 404 | OFF | T3 | RFC 8628 device-authorization rail | auth_device.rs:209 | |
CRUX_MCP_RESOURCE_URL | URL | none, OAuth resource metadata disabled | OFF | trimmed non-empty | This daemon's public MCP resource URL (RFC 9728) | oauth.rs:51 | |
CRUX_MCP_AUTH_SERVER | URL | https://api.vaultcrux.com | - | trimmed non-empty | Authorization Server base URL | oauth.rs:55 | |
CRUX_MCP_INTROSPECT_CLIENT_ID | string | none, introspection disabled | OFF | non-empty | RFC 7662 introspection client id | oauth.rs:118 | |
CRUX_MCP_INTROSPECT_CLIENT_SECRET | secret | none, introspection disabled | OFF | non-empty | RFC 7662 introspection client secret | oauth.rs:119 | |
CRUX_MCP_INTROSPECT_URL | URL | <auth server>/v1/auth/introspect | - | non-empty | Override the introspection endpoint | oauth.rs:121 | |
CRUX_MCP_OAUTH_TENANT | string | work | - | non-empty | Tenant that hosted-client OAuth identities map to | oauth.rs:313 | |
CRUX_MCP_REQUIRE_RESOURCE_AUD | bool | false | OFF | eq_ignore_ascii_case("true"), 1 does not work | Enforce the OAuth resource aud check | oauth.rs:320 | |
CORECRUX_LOOPBACK_TOKEN | secret | none, then CRUX_AGENT_TOKEN is tried | - | trimmed non-empty | First-choice opaque bearer for loopback HTTP calls | loopback_auth.rs:226 | |
CRUX_MCP_HANDOFF_SECRET | secret | a random 32-byte seed, rotating per process | - | any value, BLAKE3-hashed | Stable handoff-bundle signing key | dispatch.rs:371 | |
CRUX_PASSPORT_REVOCATION | bool | true | ON | T6: =yes and =on disable it | Revoked passports reduced to read-only | dispatch.rs:116 | |
CRUX_AGENT_CARD | bool | true | ON | T6: =yes and =on disable it | Expose /.well-known/agent-card for A2A discovery | server.rs:88 | |
CORECRUXD_AGENT_PASSPORTS | bool | false | OFF | T1 | Stamp resolved passport ids as the fact actor | config.rs:960 | |
CRUX_AGENT_PASSPORTS | agent:passport[:tenant],… | built-in default map | - | comma-split; an empty parse result falls back to the default | Agent to passport and tenant mapping | agent_passport.rs:139 | |
CORECRUXD_FEATURE_PASSPORT_MINT_REQUESTS | bool | false | OFF | T1 | Passport mint request plus operator approve and reject surface; adds the 119th MCP tool | config.rs:961 | |
CORECRUXD_PASSPORT_KEY_PATH | path | <state_dir>/passport.key | - | $HOME, ~ and XDG expanded | The daemon passport private key | config.rs:887 | |
CRUX_PASSPORT_KEY_PATH | path | falls through to CORECRUXD_PASSPORT_KEY_PATH, then <CORECRUXD_DATA_DIR>/passport.key | - | , | CLI and hook-side passport key override, checked first, see §5.10 row 13 | compaction_sync.rs:183 | |
CORECRUXD_PASSPORT_CLAIM_ON_STARTUP | bool | true | ON | T1 | Claim an anonymous passport at boot, the one outbound call in a default configuration | config.rs:890 | |
CRUX_PASSPORT_CLAIM_ENDPOINT, then CORECRUXD_PASSPORT_CLAIM_ENDPOINT | URL | https://passport.vaultcrux.com/v1/claim-anonymous | - | CRUX_* wins | Passport claim endpoint | config.rs:893 | |
CRUX_PASSPORT_ID | string | operator:anonymous | - | trimmed non-empty | Actor id stamped on hook-side captures | observe_capture.rs:355 | |
CORECRUXD_SEED_DEFAULT_PASSPORTS | bool | false | OFF | T4 inline | Seed the built-in passport set at boot | main.rs:1015 | |
CORECRUXD_IDENTITY_LINKS | bool | false | OFF | T1 | /v1/identity/links* CRUD and the resolver extension | config.rs:1375 | |
CORECRUXD_FEATURE_IDENTITY_CONTINUITY | bool | false | OFF | T6 | Identity split, merge and link-device tools | identity.rs:67 |
5.13 Storage, data directory, append lane, compaction
| Name | Type | Default | Flag | Parse | Effect | Read at |
|---|---|---|---|---|---|---|
CORECRUXD_DATA_DIR | path | ../CoreCruxData/v1 after the YAML fallback chain | - | $HOME, ~ and XDG expanded | Segments, indexes, journals, control state. Three divergent read sites, see §5.10 rows 6 and 18 | config.rs:834 |
CORECRUXD_STATE_DIR | path | falls back to data_dir | - | expanded | Control and state directory | config.rs:839 |
XDG_STATE_HOME | path | not substituted if unset | - | , | $XDG_STATE_HOME expansion in config paths | config.rs:778 |
XDG_CONFIG_HOME | path | no config file is loaded if unset | - | , | Config path resolution and $XDG_CONFIG_HOME expansion | config.rs:728 |
HOME | path | no $HOME or ~ expansion if unset | - | , | Path expansion; hook and CLI config discovery | config.rs:784 |
CORECRUXD_BUILD_CCXI | bool | false | OFF | T1 inline | Build .ccxi companion indexes at seal time, required for BM25 | config.rs:954 |
CORECRUXD_STORE_LOCK_STRATEGY | enum | Sharded | - | mutex / rwlock / sharded, plus upper-case variants | Store lock implementation | config.rs:1024 |
CORECRUXD_APPEND_LANE_ENABLED | bool | true | ON | T1 inline via is_none_or, any non-listed value disables | Dedicated append lane | config.rs:1029 |
CORECRUXD_APPEND_LANE_SCOPE | enum | Global | - | global / shard | Append-lane granularity | config.rs:1032 |
CORECRUXD_APPEND_GROUP_COMMIT_BATCHES | usize | 16, minimum 1 | - | , | Group-commit batch count | config.rs:1239 |
CORECRUXD_APPEND_GROUP_COMMIT_MAX_DELAY_MS | u64 | 0, batch-count boundary only | - | , | Bounded group-commit delay | config.rs:1246 |
CORECRUXD_TAIL_CACHE_ENABLED | bool | true | ON | T1 inline via is_none_or | Tail read cache | config.rs:1037 |
CORECRUXD_ENABLE_DIRECTORY_COMPACTION | bool | false | OFF | T1 inline | Directory LSM compaction | config.rs:1253 |
CORECRUXD_DIR_L0_MAX_RUNS | usize | 8 | - | , | L0 run count before compaction | config.rs:1256 |
CORECRUXD_COLD_SCAN_MAX_SEGMENTS | usize | 256 | - | , | Cold-scan segment cap | config.rs:1235 |
CORECRUXD_MAX_EVENTS_PER_BATCH | usize | 1024 | - | , | Ingest batch event cap | config.rs:1215 |
CORECRUXD_MAX_BATCH_BYTES | usize | 16777216 (16 MB) | - | , | Ingest batch byte cap | config.rs:1219 |
CORECRUXD_MAX_EVENT_ID_BYTES | usize | 128 | - | , | Maximum event-id length | config.rs:1223 |
CORECRUXD_IDEM_HOT_CAPACITY_ENTRIES | usize | 100000 | - | , | Idempotency hot-cache size | config.rs:1227 |
CORECRUXD_EVENT_ID_HASH_PREFIX_LEN | usize | 16 | - | , | Event-id hash prefix length | config.rs:1231 |
CORECRUXD_ADMIN_FORCE_SEAL | bool | false | OFF | T1 inline | Permit force-sealing head segments via admin actions | config.rs:975 |
CORECRUXD_FACT_PERSISTENCE | bool | true | ON | T1 inline via is_none_or | JSONL persistence for the fact and session stores. Setting it off makes every write volatile | config.rs:1261 |
CORECRUXD_RETENTION_DAYS | u32 | none, retention off | - | must be above 0, else treated as unset | compact-facts deletion-eligibility window | config.rs:980 |
CORECRUXD_FORGET_RECOVERY_WINDOW_DAYS | i64 | 7 | - | untrimmed parse, floored at 1 | Soft-delete recovery window before purge | forget.rs:80 |
CORECRUXD_EPHEMERAL_GC | bool | false | OFF | T1 | GC stale daemon-minted bookkeeping facts. Read once at boot | config.rs:1327 |
CORECRUXD_PROJECTIONS_ENABLED | bool | false | OFF | T1 inline | Living Objects projections | config.rs:963 |
CORECRUXD_PROJECTIONS_BATCH_FRAMES | u32 | 1024 | - | , | Projection batch size | config.rs:966 |
CORECRUXD_PROJECTIONS_TICK_INTERVAL_MS | u64 | 1000 | - | , | Projection tick cadence | config.rs:970 |
CORECRUXD_SCRUB_SCHEDULER_ENABLED | bool | false | OFF | T1 inline | Background scrub scheduler | config.rs:1074 |
CORECRUXD_SCRUB_INTERVAL_SECS | u64 | 300, clamped 10..=86400 | - | , | Scrub cadence | config.rs:1077 |
CORECRUXD_SCRUB_SCOPE | string | recent | - | , | Scrub scope | config.rs:1082 |
CORECRUXD_SCRUB_MODE | string | sampled | - | , | Scrub mode | config.rs:1083 |
CORECRUXD_SCRUB_SAMPLE_RATE | f64 | 0.25, clamped 0.0..=1.0 | - | , | Scrub sampling rate | config.rs:1084 |
CORECRUXD_OPERATOR_ACTION_MAX_PENDING | usize | 128, minimum 1 | - | , | Operator action queue depth | config.rs:1063 |
CORECRUXD_OPERATOR_ACTION_TIMEOUT_SECS | u64 | 900, clamped 5..=86400 | - | , | Operator action timeout | config.rs:1068 |
CORECRUX_STORAGE_FAILPOINT | string | none | - | exact string equality against the failpoint name | Fault-injection hook, compiled in for non-test builds | corecrux-storage/src/lib.rs:1982 |
CORECRUXD_SOURCE_ROOTS | CSV | /sources,/src | - | comma-split, trimmed | Allowed source roots for plane-layer sync | plane_layer_sync.rs:73 |
5.14 Ingress hardening, backpressure, capacity guard
All of these read 0 as "disabled or unbounded", so an emergency rollback needs no redeploy (config.rs:93). Unparseable values silently fall back to the default.
| Name | Type | Default | Read at |
|---|---|---|---|
CORECRUXD_MAX_REQUEST_BODY_BYTES | usize | 16777216 (16 MiB) | config.rs:265 |
CORECRUXD_SHUTDOWN_DRAIN_SECS | u64 | 30; 0 drains forever | config.rs:266 |
CORECRUXD_MAX_INFLIGHT | usize | 1024; 0 means no cap | config.rs:267 |
CORECRUXD_RATE_LIMIT_RPS | u64 | 300; 0 disables | config.rs:268 |
CORECRUXD_RATE_LIMIT_BURST | u64 | 600, clamped up to rate_limit_rps | config.rs:269 |
CORECRUXD_RATE_LIMIT_EXEMPT_CIDRS | CSV CIDR | 127.0.0.0/8,::1/128; an empty string means no exemptions | config.rs:270 |
CORECRUXD_TRUSTED_PROXY_CIDRS | CSV CIDR | [], forwarded headers are ignored until set | config.rs:271 |
CORECRUXD_GRPC_KEEPALIVE_INTERVAL_SECS | u64 | 30; 0 disables pings | config.rs:272 |
CORECRUXD_GRPC_KEEPALIVE_TIMEOUT_SECS | u64 | 10 | config.rs:273 |
CORECRUXD_GRPC_MAX_CONCURRENT_STREAMS | u32 | 1024; 0 is unbounded | config.rs:274 |
CORECRUXD_BACKPRESSURE_HIGH_WATERMARK_RATIO | f64 | 0.90, clamped 0.01..=0.99 | config.rs:1044 |
CORECRUXD_BACKPRESSURE_LOW_WATERMARK_RATIO | f64 | 0.80, clamped 0.0..=0.98, forced below the high watermark | config.rs:1048 |
CORECRUXD_BACKPRESSURE_RETRY_AFTER_MS | u32 | 250, clamped 1..=60000 | config.rs:1057 |
CORECRUXD_CAPACITY_GUARD_ENABLED | bool | true | config.rs:1089 |
CORECRUXD_CAPACITY_GUARD_INTERVAL_SECS | u64 | 30, clamped 10..=3600 | config.rs:1092 |
CORECRUXD_CAPACITY_WARNING_FREE_RATIO | f64 | 0.20, clamped 0.01..=0.95, then raised to at least critical and emergency | config.rs:1097 |
CORECRUXD_CAPACITY_CRITICAL_FREE_RATIO | f64 | 0.10, clamped 0.01..=0.90, re-ordered against the others | config.rs:1102 |
CORECRUXD_CAPACITY_EMERGENCY_FREE_RATIO | f64 | 0.10; this is the /readyz gate threshold | config.rs:1107 |
CORECRUXD_CAPACITY_RESUME_FREE_RATIO | f64 | 0.20, clamped 0.02..=0.99, forced above emergency | config.rs:1112 |
CORECRUXD_READ_RETRY_FAILED_READYZ_THRESHOLD | u64 | 3; 0 disables the gate | config.rs:1040 |
CORECRUXD_MAX_OBSERVATION_PAYLOAD_BYTES | usize | 1 MiB, floor 64 KiB. Read once into a LazyLock, a later change has no effect | observations.rs:48 |
5.15 Sync, replication, update checks
| Name | Type | Default | Flag | Parse | Effect | Read at | |
|---|---|---|---|---|---|---|---|
CORECRUXD_SYNC_ENABLED | bool | false | OFF | T1 inline, untrimmed at both sites | Background pull and push sync loop; also reported in /readyz and /v1/version | config.rs:1294 | |
CORECRUXD_SYNC_REMOTE_URL | URL | "" | - | unwrap_or_default(): no trim, no validation | Remote base URL. Four divergent read sites | config.rs:1297 | |
CORECRUXD_SYNC_API_KEY | secret | "" | - | unwrap_or_default() | Bearer for the remote sync target | config.rs:1298 | |
CORECRUXD_SYNC_INTERVAL_SECS | u64 | 300, minimum 10 | - | , | Sync cadence | config.rs:1299 | |
CORECRUXD_SYNC_MUTUAL_AUTH | bool | false | OFF | 1 or case-insensitive true, yes does not work | Require issuer-signed Ed25519 peer handshakes | config.rs:1304 | |
CORECRUXD_SYNC_PEER_TRUST_ROOT | hex | none | - | exactly 64 hex chars; anything else silently becomes none | Issuer Ed25519 trust root for peer tokens | config.rs:1307 | |
CORECRUXD_SYNC_DELEGATION_ENFORCE | bool | false | OFF | 1 or case-insensitive true | Accept recipient-bound v1.1 delegation tokens at the sync boundary | config.rs:1310 | |
CORECRUXD_SYNC_PEER_SIGNING_KEY | hex seed | none | - | hex; invalid means warn and fall back to bearer only | Peer handshake signing key, must be paired with the token | main.rs:175 | |
CORECRUXD_SYNC_PEER_TOKEN | JSON | none | - | canonical capability-token JSON | Peer capability token | main.rs:176 | |
CORECRUXD_SYNC_PRIVATE_PREFIXES | CSV | the built-in prefix set only | - | comma-split, trimmed, blanks dropped | Extra never-synced fact prefixes | corecrux-memory/src/sync.rs:876 | |
CORECRUXD_ALWAYS_PRIVATE_PREFIXES | CSV | the default private prefixes only | - | comma-split, trimmed | Extra always-private fact prefixes | fact_privacy.rs:179 | |
CORECRUXD_SHARE_PREFIXES_OVERRIDE | CSV | {}, no shareable prefixes | - | comma-split, trimmed | Replace the shareable-prefix set | fact_privacy.rs:185 | |
CORECRUXD_COMMIT_LEVEL | enum | LocalCommit | - | local / local_commit / local-commit versus replicated and friends | Commit durability level | config.rs:858 | |
CORECRUXD_FOLLOWER_READS_ENABLED | bool | true only if commit_level == ReplicatedCommit, else false | varies | T1 inline | Serve reads from followers | config.rs:863 | |
CORECRUXD_REPLICATED_COMMIT_TIMEOUT_MS | u64 | 5000, clamped 100..=120000 | - | , | Replicated-commit timeout | config.rs:867 | |
CORECRUXD_REPLICATED_COMMIT_REQUIRE_ALL_FOLLOWERS | bool | true | ON | T1 inline via is_none_or | Require every follower to acknowledge | config.rs:872 | |
CORECRUXD_REPLICATION_AUTH_BEARER | secret | the hardcoded literal replication:write in the gRPC path; presence-only in the readiness report, see §5.10 row 15 | - | trimmed non-empty; a bearer prefix is stripped case-insensitively | Bearer presented on replication segment pushes | grpc.rs:860 | |
CORECRUXD_REPLAY_BATCH_MAX_EVENTS | u32 | 64, minimum 1 | - | , | Replay batch event cap | config.rs:1006 | |
CORECRUXD_REPLAY_BATCH_MAX_BYTES | u32 | 262144, minimum 1024 | - | , | Replay batch byte cap | config.rs:1011 | |
CORECRUXD_REPLAY_MANY_MAX_READS | u32 | 64, minimum 1 | - | , | replay_many read cap | config.rs:1016 | |
CORECRUXD_REPLAY_USE_BATCHED_RPC_DEFAULT | bool | true | ON | T1 inline via is_none_or | Default to the batched replay RPC | config.rs:1021 | |
CORECRUXD_UPDATE_CHECK_ENABLED | bool | true | ON | T1 inline via is_none_or | Background git update check for /v1/version and the MCP update_status tool | config.rs:1313 | |
CORECRUXD_UPDATE_CHECK_REMOTE | string | origin | - | , | Git remote to compare against | config.rs:1316 | |
CORECRUXD_UPDATE_CHECK_REF | string | main | - | , | Tracking branch | config.rs:1317 | |
CORECRUXD_UPDATE_CHECK_INTERVAL_SECS | u64 | 3600, clamped 60..=86400 | - | , | Update-check cadence | config.rs:1318 | |
CORECRUXD_UPDATE_CHECK_REPO_DIR | path | none, the working directory | - | empty paths filtered out | Explicit repository root | config.rs:1323 | |
CRUX_COMPACTION_SYNC | bool | false | OFF | **`matches!(v, "1" \ | "on"): true` does not work** | Opt-in compaction-snapshot sync | snapshot_sync.rs:84 |
CORECRUXD_ENGINE_BASE_URL | URL | none, the gate is closed | - | trimmed non-empty, trailing / stripped | Engine base URL for the console proxy and snapshot sync | engine_console.rs:240 | |
CORECRUXD_ENGINE_API_KEY | secret | none, the gate is closed | - | trimmed non-empty | Engine API key | engine_console.rs:247 | |
CORECRUXD_ENGINE_TENANT_ID | string | none, the snapshot-sync gate is closed | - | trimmed non-empty | Tenant id for snapshot sync | snapshot_sync.rs:117 | |
CORECRUXD_ENGINE_SEARCH_TENANT | string | wikicrux, a deployment-specific tenant baked in as the default | - | trimmed non-empty | Tenant used by the console engine-search proxy | engine_console.rs:232 |
5.16 Retrieval, memory, embeddings
| Name | Type | Default | Flag | Parse | Effect | Read at |
|---|---|---|---|---|---|---|
CORECRUXD_QUERY_TEXT_SEARCH | bool | true | ON | T2, only 0 and false disable | Local CPU BM25 text-search route; 404 when off | query.rs:445 |
CORECRUXD_QUERY_GRAPH_EXPAND | bool | false | OFF | T6 | Graph-expansion queries | query.rs:157 |
CORECRUXD_QUERY_TIME_RANGE | bool | false | OFF | T6 | Time-range queries | query.rs:283 |
CORECRUXD_EMBEDDING_URL | URL | none, keyword-only unless the local embedder is on | - | non-empty, untrimmed in config, trimmed and parsed for the probe allowlist | OpenAI-compatible embedding endpoint; also the origin exempted from the probe SSRF guard | config.rs:1266 |
CORECRUXD_EMBEDDING_MODEL | string | nomic-embed-text in config and CLI | - | non-empty | Model requested from the embedding service | config.rs:1267 |
CORECRUXD_EMBEDDING_PROBE_ALLOW_LOCAL | bool | false | OFF | T1 inline, untrimmed | Let the console embedding probe reach private, loopback, link-local and metadata targets, an SSRF guard override | console.rs:1850 |
CORECRUXD_LOCAL_EMBEDDER | bool | true | ON | T2 | Use the zero-dependency LocalHashEmbedder when no external embedding URL is set | config.rs:1280 |
CORECRUXD_DENSE_MODEL | string | none | - | non-empty | fastembed selects the feature-gated ONNX embedder; needs --features dense-embed-model | config.rs:1281 |
CORECRUXD_COMPUTE_PROVIDER | bool | false | OFF | T1 | Execute /v1/compute/embed work for peers. Mutually exclusive with delegation | config.rs:1265 |
CORECRUXD_EMBED_DELEGATE_URL | URL | none | - | trimmed non-empty; its presence makes the whole delegation set mandatory | Daemon-to-daemon embedding delegation target | config.rs:1268 |
CORECRUXD_EMBED_DELEGATE_TOKEN | secret | none | - | trimmed non-empty; Debug prints [REDACTED] | Delegation bearer, the only redaction-aware secret in Config | config.rs:1271 |
CORECRUXD_EMBED_DELEGATE_DIMENSIONS | usize | none | - | unparseable deliberately becomes 0 so validation fails closed | Vector dimensionality assertion | config.rs:1275 |
CORECRUXD_SEMANTIC_DEDUP | bool | false | OFF | T1 inline | Store-time semantic near-duplicate flagging; it never drops a write | config.rs:1283 |
CORECRUXD_SEMANTIC_DEDUP_THRESHOLD | f32 | 0.95, read only when dedup is on | - | , | Cosine threshold for the dedup flag | config.rs:1287 |
CORECRUXD_MEMORY_SALIENCE | bool | false | OFF | T4 | Record per-fact access counts on recall so hot facts decay slower | tools/facts.rs:26 |
CORECRUXD_DECAY_VOLATILE_HOURS | i64 | policy default; values at or below 0 ignored | - | , | Staleness horizon for volatile facts | decay.rs:126 |
CORECRUXD_DECAY_MEDIUM_DAYS | i64 | policy default | - | , | Staleness horizon for medium-stability facts | decay.rs:127 |
CORECRUXD_DECAY_STABLE_DAYS | i64 | policy default | - | , | Staleness horizon for stable facts | decay.rs:128 |
CORECRUXD_CONSOLIDATION_SCHEDULER | bool | false | OFF | T1 | Periodic contradiction-candidate detection, surfaces only, never resolves | config.rs:1328 |
CORECRUXD_CONSOLIDATION_SCHEDULER_INTERVAL_SECS | u64 | 3600, clamped 60..=86400 | - | , | Consolidation review cadence | config.rs:1329 |
CORECRUXD_CONTEXT_SURFACE | bool | false, 404 | OFF | T1 | Provider-neutral /v1/context bundle surface | config.rs:1342 |
CORECRUXD_AUTO_CAPTURE | bool | false, 404 | OFF | T1 | Gated auto-capture /v1/memory/* | config.rs:1343 |
CORECRUXD_LOCAL_INGEST | bool | true | ON | T2 | Local CPU prose-ingest door /v1/local/ingest | config.rs:1344 |
CORECRUXD_ASSEMBLY_CACHE | bool | false | OFF | T1 | Assembly cache for /v1/context bundles | config.rs:1361 |
CRUX_MEMORY_IMPORT | bool | false | OFF | T1 in the daemon; v == "1" exactly in the CLI | POST /v1/memory/import | config.rs:1374 |
CORECRUXD_SESSION_TOKEN_BUDGET | u64 | none, no limit; 0 also means no limit | - | trimmed parse | Per-session token budget; drives budget_pct | token_accounting.rs:95 |
CRUX_OUTPUT_HOLDOUT | f64 | 0.0 | OFF | trimmed parse, clamped 0.0..=1.0 | Fraction of requests diverted to the unshaped control arm | holdout.rs:38 |
CORECRUXD_LLM_ENDPOINT | URL | none | - | non-empty | Local LLM endpoint | config.rs:949 |
CORECRUXD_LLM_MODEL | string | none | - | non-empty | Local LLM model name | config.rs:950 |
OPENAI_API_KEY | secret | none | - | trimmed non-empty | Bearer for the embedding endpoint in corecruxctl ingest --embed | ingest.rs:608 |
5.17 Observability, redaction, OpenTelemetry
| Name | Type | Default | Flag | Parse | Effect | Read at | |||
|---|---|---|---|---|---|---|---|---|---|
CORECRUXD_REDACT | enum | audit: count, do not mutate | - | on / off / audit; unknown values fall back to audit | Sink-boundary log redaction mode | redact.rs:68 | |||
CORECRUXD_REDACT_EXTRA_PATTERNS | patterns | "" | - | ;;-separated id=regex; invalid entries warn and drop | Extra redaction patterns | redact.rs:220 | |||
CORECRUXD_OBSERVE_REDACT | enum | on: anything unrecognised, including unset | - | trimmed and lowercased; off and audit explicit | Lane-scoped redaction for /v1/observe/*, a stricter default than CORECRUXD_REDACT | observe_audit.rs:241 | |||
CORECRUXD_OBSERVE | bool | false | OFF | T4 | /v1/observe/* audit-chain surface | agentgraph_kinds.rs:140 | |||
CORECRUXD_ORCHESTRATORS | bool | false | OFF | T4 | /v1/orchestrators/* surface | agentgraph_kinds.rs:145 | |||
CORECRUXD_PUNCHCARD | enum | Off | OFF | trimmed and lowercased; advisory / enforce, anything else means off | Punchcard lease enforcement posture | agentgraph_kinds.rs:162 | |||
CORECRUXD_AGENTGRAPH | - | never read | - | , | Named in the route-auth contract for /v1/orchestrators and /v1/punchcards but read nowhere, see §5.10 row 14 | route_auth.rs:528 | |||
CORECRUXD_OBS_RETENTION_DAYS | i64 | none, keep forever; values at or below 0 also disable | - | parse, must be above 0 | Hourly observation archival horizon | main.rs:1223 | |||
CORECRUXD_FEATURE_ACTIVITY_LOG | bool | false | OFF | T5 | Signed replayable activity log /v1/activity | activity.rs:81 | |||
CORECRUXD_FEATURE_ACTIVITY_LOG_TTL_SECS | u64 | 31536000 (365 days) | - | trimmed parse; unparseable falls back to the default | Activity retention horizon | activity.rs:93 | |||
CORECRUXD_FEATURE_ACTIVITY_SIGN | bool | false | OFF | T5 | Co-sign each appended turn | activity.rs:256 | |||
CORECRUXD_FEATURE_TOOL_TRACES | bool | true | ON | T5 | In-memory per-passport tool-trace ring | traces.rs:75 | |||
CORECRUXD_FEATURE_TOOL_TRACES_TTL_SECS | u64 | 3600 | - | trimmed parse | Trace retention horizon | traces.rs:87 | |||
CORECRUXD_FEATURE_TOOL_LEDGER | bool | false | OFF | T5 | Durable agent.tool_invocation.v1 ledger observations | ledger.rs:75 | |||
CORECRUXD_TOOL_LEDGER_RAW_ARGS | bool | false | OFF | T5 | Include raw tool arguments, not just args_hash, local debug only | ledger.rs:79 | |||
CORECRUXD_FEATURE_OTEL_SPANS | bool | false | OFF | T5 | OpenTelemetry GenAI-semconv events per MCP tool dispatch | otel.rs:40 | |||
OTEL_EXPORTER_OTLP_ENDPOINT | URL | none, no exporter | - | , | OTLP span exporter endpoint. Only compiled with --features otel; a bad endpoint fails silently | main.rs:2085 | |||
CORECRUXD_FEATURE_STATUS_FEED | bool | false | OFF | T5 | Live work-board feed /v1/status-feed | status_feed.rs:41 | |||
CORECRUXD_FEATURE_INCIDENTS | bool | false | OFF | T9 | Incident reconstruction cases and certified exports | incidents.rs:170 | |||
CORECRUXD_FEATURE_LEGAL_HOLD | bool | false | OFF | T6 | Legal-hold placement and release, plus retention enforcement | legal_holds.rs:34 | |||
CORECRUXD_FEATURE_PROVENANCE_API | bool | false | OFF | `Some("1"\ | "true"\ | "TRUE"\ | "on"), **yes` does not work** | Provenance API surface; routes are mounted only when on, so they hard-404 otherwise, before any body is read | provenance.rs:56 |
CRUX_SELF_OBSERVE | bool | false | OFF | `matches!(v.to_lowercase(), "1"\ | "true"\ | "yes"): **on` does not work**, untrimmed | Self-observation lane | crux-observe/src/config.rs:13 | |
CORECRUXD_REPO_WATCH | bool | false | OFF | T7-shaped inline | Filesystem repo watcher | repo_watch.rs:24 | |||
CORECRUXD_REPO_WATCH_POLL | bool | false | OFF | T7-shaped inline | Polling fallback for the repo watcher | repo_watch.rs:31 |
5.18 Extensions and the WASM host
| Name | Type | Default | Flag | Parse | Effect | Read at |
|---|---|---|---|---|---|---|
CORECRUXD_EXTENSIONS_TIMEOUT_SECONDS | u64 | struct default; unparseable silently ignored | - | , | Outbound extension call timeout | extension_outbound.rs:131 |
CORECRUXD_EXTENSIONS_MAX_REQUEST_BYTES | usize | struct default | - | , | Outbound request size cap | extension_outbound.rs:136 |
CORECRUXD_EXTENSIONS_MAX_RESPONSE_BYTES | usize | struct default | - | , | Outbound response size cap | extension_outbound.rs:141 |
CORECRUXD_EXTENSIONS_DEFAULT_RATE_PER_MIN | u32 | struct default | - | , | Default per-extension rate limit | extension_outbound.rs:146 |
CORECRUXD_EXTENSIONS_ALLOW_PLAIN_HTTP | bool | false | OFF | T8 | Permit http:// extension endpoints | extension_outbound.rs:151 |
CORECRUXD_EXTENSIONS_ALLOW_UNSIGNED | bool | false | OFF | T8 | Accept unsigned extension bundles, development only | http/extensions.rs:45 |
CORECRUXD_WASM_FUEL_DEFAULT | u64 | 1000000 | - | unparseable falls back | Wasmtime fuel budget per call | wasm_host.rs:92 |
CORECRUXD_WASM_MEMORY_BYTES_DEFAULT | u64 | 16000000 | - | , | WASM linear-memory cap | wasm_host.rs:93 |
CORECRUXD_WASM_WALL_MS_DEFAULT | u64 ms | 1000 | - | , | Wall-clock cap per WASM call | wasm_host.rs:94 |
CORECRUXD_WASM_EPOCH_TICK_MS | u64 ms | 10 | - | , | Wasmtime epoch interruption tick | wasm_host.rs:95 |
CORECRUXD_STUDIO_ALLOW_UNSIGNED | bool | false | OFF | T8 | Accept unsigned Studio templates, development only | studio_library.rs:90 |
CORECRUXD_STUDIO_SIGNING_KEY_HEX | hex seed | none, bare-mirror state; malformed is an error | - | 32-byte hex seed | Operator signing key for Studio packs | studio_pack.rs:628 |
CORECRUXD_RESULT_ENVELOPE_KEYS | CSV | [], no trusted platform keys | - | comma-split | Pinned trusted platform verification keys | result_envelope.rs:54 |
5.19 Integrations, console, upstream proxies
| Name | Type | Default | Flag | Parse | Effect | Read at |
|---|---|---|---|---|---|---|
CORECRUXD_INTEGRATIONS_ENABLED | bool | true | ON | T1 inline via is_none_or | The declarative integration library | config.rs:1377 |
CORECRUXD_INTEGRATIONS_SAFE_MODE | bool | false | OFF | T1 inline | Restrict integration capabilities | config.rs:1380 |
CORECRUXD_INTEGRATIONS_ALLOW_EXECUTABLE_HELPERS | bool | false | OFF | T1 inline | Permit integration packs to run executables | config.rs:1383 |
CORECRUXD_CONSOLE_DEV_PATH | path | none, bundled assets | - | trimmed non-empty | Serve console assets from disk, for development | console.rs:126 |
CORECRUXD_CONSOLE_ALLOWED_ORIGINS | CSV origins | a built-in deployment-specific list; an empty-after-trim value also falls back to it | - | comma-split | Console CORS allowlist. Replaced a permissive CORS layer | console.rs:273 |
CORECRUXD_CORECRUX_BASE_URL, then CORECRUXD_CORECRUX_URL, then CORECRUX_BASE_URL | URL | none, the proxy errors | - | first non-empty after trim and trailing-/ strip | Upstream operator proxy for console lane-weight controls | console.rs:1228 |
CORECRUXD_CORECRUX_GRAPH_BASE_URL, then CORECRUX_GRAPH_BASE_URL | URL | none, the proxy errors | - | first non-empty after trim | Graph mediation proxy; drives the console_link_graph capability | console.rs:761 |
CORECRUXD_CORECRUX_ADMIN_TOKEN, then CORECRUX_ADMIN_TOKEN | secret | none | - | trimmed non-empty | Bearer forwarded to the upstream admin API | console.rs:1390 |
CORECRUXD_CORECRUX_GRAPH_TOKEN, then CORECRUX_GRAPH_TOKEN | secret | none | - | trimmed non-empty | Bearer forwarded to the upstream graph API | console.rs:782 |
CORECRUXD_CORECRUX_PASSPORT_ID, then CORECRUX_PASSPORT_ID | string | none | - | trimmed non-empty | Passport id forwarded upstream | console.rs:1398 |
CORECRUXD_GPU1_BASE_URL, then CRUX_GPU1_BASE_URL | URL | none, the client is not constructed and the routes are inert | - | trimmed non-empty | Rerank dataplane base URL. Needs --features hosted-surfaces | gpu1.rs:961 |
CORECRUXD_GPU1_API_KEY, then CRUX_GPU1_API_KEY | secret | none | - | trimmed non-empty | Rerank dataplane API key | gpu1.rs:966 |
CORECRUXD_GITHUB_SYNC_INTERVAL_SECS | u64 | 900 (15 min) | - | no minimum clamp: 0 is accepted, unlike the witness and sync loops | GitHub integration poll cadence | main.rs:1499 |
CORECRUXD_VAULT_WATCH_ROOTS | colon-separated absolute paths | "", the watcher is inactive | - | splits on :, not ,, unlike every other list variable here. Non-absolute or unreadable entries are rejected and reported | Directories the file-watcher pack monitors; also requires an installed file-watcher pack | vault_watcher.rs:194 |
CORECRUXD_VAULT_WATCH_INTERVAL_SECS | u64 | 300; 0 is rejected and falls back | - | , | Watch poll cadence | vault_watcher.rs:262 |
CORECRUXD_VAULT_WATCH_TENANT | string | the default tenant | - | , | Tenant for watcher-ingested content | vault_watcher.rs:239 |
CORECRUXD_VAULT_WATCH_CORPUS | string | the default corpus | - | , | Corpus for watcher-ingested content | vault_watcher.rs:240 |
CORECRUXD_APPROVALS_SLACK_WEBHOOK_URL | URL | none: a silent no-op, never panics | - | unset or blank-after-trim returns early | Slack notification for approval requests | approvals.rs:191 |
CORECRUXD_OPENAI_SHIM | bool | false | OFF | T1 | OpenAI function-calling shim over the MCP tool surface | config.rs:1376 |
CORECRUXD_TOOL_SURFACE | enum | full: any unrecognised value also means full, so it never silently shrinks | - | trimmed and lowercased; minimal / dynamic | Size of the advertised tools/list surface | surface.rs:96 |
CRUX_MCP_SSE_MAX_SESSIONS | usize | 1024; 0 means unlimited | - | , | Global SSE session cap | sse.rs:54 |
CRUX_MCP_SSE_MAX_SESSIONS_PER_OWNER | usize | 64; 0 means unlimited | - | , | Per-owner SSE session cap | sse.rs:55 |
CRUX_MCP_URL | URL | http://127.0.0.1:14801/mcp | - | , | Target for the corecruxd mcp-stdio bridge | mcp_stdio.rs:141 |
CORECRUXD_HTTP_URL | URL | http://127.0.0.1:14800 | - | , | Daemon base URL for corecruxctl subcommands | corecruxctl/src/extensions.rs:158 |
CRUX_HTTP_URL | URL | http://127.0.0.1:14800 | - | trailing / normalised | Daemon base URL for the hook client | daemon_client.rs:30 |
5.20 Receipts, witness, C2PA, audit export
| Name | Type | Default | Flag | Parse | Effect | Read at |
|---|---|---|---|---|---|---|
CORECRUXD_RECEIPTS_VERIFY_ENABLED | bool | true | ON | T1 inline via is_none_or | Receipt signature-verification projection | config.rs:985 |
CORECRUXD_RECEIPTS_RECOMPUTE_CANDIDATE_DIGEST | bool | false | OFF | T1 inline | Recompute candidate digests during verification | config.rs:988 |
CORECRUXD_RECEIPTS_KEYRING_PATH | path | none | - | no trim, no empty filter, a trailing space becomes part of the path | Pinned receipt verification keyring file | config.rs:991 |
CORECRUXD_RECEIPTS_KEYRING_JSON | JSON string | none | - | no trim | Inline receipt verification keyring | config.rs:992 |
CORECRUXD_WITNESS_ENABLED | bool | false | OFF | T1 | Transparency-log witnessing | config.rs:993 |
CORECRUXD_WITNESS_PROVIDER | string | disabled | - | non-empty | Witness provider, e.g. rekor | config.rs:994 |
CORECRUXD_WITNESS_TIMEOUT_MS | u64 | 5000, clamped 100..=120000 | - | , | Witness submit timeout | config.rs:995 |
CORECRUXD_WITNESS_INTERVAL_SECS | u64 | 300, minimum 1 | - | , | Background witness anchoring cadence | main.rs:1335 |
CORECRUXD_REKOR_URL | URL | none | - | non-empty | Rekor endpoint | config.rs:1000 |
CORECRUXD_REKOR_PUBLIC_KEY_PATH | path | none | - | non-empty | Rekor verification key | config.rs:1001 |
CORECRUXD_TSA_ENABLED | bool | false | OFF | T1 | RFC 3161 timestamping | config.rs:1002 |
CORECRUXD_TSA_URL | URL | none | - | non-empty | TSA endpoint | config.rs:1003 |
CORECRUXD_TSA_ROOT_CERT_PATH | path | none | - | non-empty | TSA root certificate | config.rs:1004 |
CORECRUXD_TSA_POLICY_OID | string | none | - | non-empty | TSA policy OID | config.rs:1005 |
CORECRUXD_WITNESS_SIGNING_KEY | base64 secret | none, no env key signer | - | trimmed; blank means none; standard base64 | Witness signing key; the env path is the default | witness_submit.rs:425 |
VAULT_ADDR | URL | none, hard error in both Vault paths | - | trimmed; blank means missing | Vault address | vault_pki_x509_signer.rs:147 |
VAULT_TOKEN | secret | none, hard error | - | trimmed; blank means missing | Vault token | vault_pki_x509_signer.rs:154 |
VAULT_CACERT | path | none | - | trimmed; blank means none | Vault CA bundle | vault_pki_x509_signer.rs:161 |
CORECRUXD_VAULT_PKI_MOUNT | string | the default PKI mount | - | trimmed, / stripped | Vault PKI mount path | vault_pki_x509_signer.rs:169 |
CORECRUXD_WITNESS_VAULT_MOUNT | string | transit | - | trimmed non-empty | Vault Transit mount for the witness signer | witness_submit.rs:201 |
CORECRUXD_WITNESS_VAULT_KEY | string | none: hard error when the Transit signer is built, but caught and downgraded | - | non-empty | Vault Transit key name | witness_submit.rs:200 |
CORECRUX_C2PA_SIGNER | enum | none, falls through to the legacy dual-flag pair | - | trimmed and lowercased; in_process / vault; an unknown value means in-process plus a warning | Canonical single-flag C2PA signer selector | c2pa_signer_selector.rs:105 |
CORECRUXD_FEATURE_C2PA_OUTPUT | bool | false | OFF | T5 | The output_attest C2PA tool | output_attest.rs:98 |
CORECRUXD_FEATURE_C2PA_X509_SIGNER | bool | false | OFF | T5 | Legacy dual-flag gate 1 for the Vault-PKI X.509 signer | output_attest.rs:111 |
CORECRUXD_C2PA_SIGNER_BACKEND | string | legacy Ed25519 | - | trimmed and lowercased; must equal vault-pki-p256 | Legacy dual-flag gate 2 | output_attest.rs:122 |
CORECRUXD_C2PA_SIGNING_KEY_B64 | base64 secret | falls back to CORECRUXD_WRITE_CONFIRMATION_SIGNING_KEY_B64 | - | only used when paired with CORECRUXD_C2PA_KEY_ID, both non-blank; four base64 variants tried; at least 32 bytes | C2PA manifest signing key | output_attest.rs:178 |
CORECRUXD_C2PA_KEY_ID | string | falls back to CORECRUXD_WRITE_CONFIRMATION_KEY_ID | - | must be paired as above | C2PA manifest key id | output_attest.rs:178 |
CORECRUXD_C2PA_LEAF_KEY_PATH | path | the default leaf key path | - | , | Vault-PKI leaf private key | vault_pki_x509_signer.rs:174 |
CORECRUXD_C2PA_LEAF_CERT_PATH | path | the default leaf cert path | - | , | Vault-PKI leaf certificate | vault_pki_x509_signer.rs:177 |
CORECRUXD_C2PA_ROOT_ANCHOR_PATH | path | the default anchor path | - | , | Vault-PKI root trust anchor | vault_pki_x509_signer.rs:180 |
CORECRUXD_C2PA_LEAF_TTL_HOURS | u64 | the default TTL; set-but-unparseable is a hard error | - | trimmed parse | Leaf certificate TTL | vault_pki_x509_signer.rs:183 |
CORECRUXD_WRITE_CONFIRMATION_SIGNING_KEY_B64 | base64 secret | none, signing unavailable | - | trimmed non-empty; standard base64 | CROWN write-confirmation signer, and the C2PA fallback | grpc.rs:1060 |
CORECRUXD_WRITE_CONFIRMATION_KEY_ID | string | local-env-ed25519 in the gRPC path; default-c2pa in the C2PA fallback, two different defaults | - | trimmed non-empty | Write-confirmation key id | grpc.rs:1079 |
CORECRUXD_FEATURE_AUDIT_EXPORT | bool | false | OFF | T6 at the tool, T3-like at the scorecard, see §5.10 row 1 | Signed audit-bundle export | audit_export.rs:61 |
CORECRUXD_AUDIT_EXPORT_DIR | path | the system temp dir plus crux-audit-export | - | blank-after-trim falls back | Where bundle artefacts are written | audit_export.rs:85 |
CORECRUXD_AUDIT_EXPORT_SIGNING_KEY_B64 | base64 secret | falls back to a persistent key auto-generated at <data_dir>/audit-export-signing.key, mode 0600 | - | trimmed; four base64 variants | Audit-bundle signing key | audit_signing_key.rs:98 |
CORECRUXD_AUDIT_EXPORT_KEY_ID | string | "" | - | unwrap_or_default() | Signer key id in the bundle manifest | audit_signing_key.rs:72 |
CORECRUXD_FEATURE_RECEIPT_VERIFY | bool | false | OFF | T5 at the tool, strict at the scorecard, see §5.10 row 2 | The receipt_verify MCP tool | receipt_verify.rs:52 |
CORECRUXD_STREAM_RECEIPTS | bool | false | OFF | T1 | Stream and context receipt wiring, plus cloud-witness envelope ingestion | config.rs:1345 |
CRUX_C2PA_VERIFY_PUBLIC_KEY_HEX | hex | none, a CLI error unless --pub-key-hex is passed | - | exactly 64 hex chars | Verifying key for corecruxctl output verify | output_verify.rs:54 |
5.21 Cost, credit, quota, usage receipts, coordination
| Name | Type | Default | Flag | Parse | Effect | Read at |
|---|---|---|---|---|---|---|
CORECRUXD_FEATURE_COST_LENS | bool | false | OFF | T5 | The cost lens. When off there are zero on-disk writes for it | cost.rs:38 |
CORECRUXD_CREDIT_METER | bool | false | OFF | T1 | Credit-burn rail for seeded comped wallets | config.rs:1373 |
CORECRUXD_QUOTA | bool | false | OFF | T1 | Per-surface request quota | config.rs:1362 |
CORECRUXD_QUOTA_HOSTED_SURFACES | CSV paths | []; everything is local compute | - | comma-split, trimmed | Path prefixes classified as quota-limited | config.rs:1363 |
CORECRUXD_FEATURE_USAGE_RECEIPTS | bool | false | OFF | T1 | Local signed metadata-only usage pings | config.rs:1346 |
CORECRUXD_USAGE_RECEIPTS_SUBMIT | bool | false | OFF | T1 | The only sanctioned outbound path. Enables the usage-ping submitter | config.rs:1352 |
CORECRUXD_USAGE_RECEIPTS_ENDPOINT | URL | none, no hardcoded endpoint | - | trimmed non-empty | Usage-ping destination | config.rs:1353 |
CORECRUXD_USAGE_RECEIPTS_CONSENT_AT | timestamp | none | - | parse_consent_at | Recorded operator consent time | config.rs:1358 |
CORECRUXD_HANDOFF_OBSERVATIONS | bool | false | OFF | T1 in config; T5 in the MCP handoff path | Signed handoff observations with vendor attribution | config.rs:1347 |
CORECRUXD_COORD | bool | true | ON | T1, an explicit 0 disables | Multi-agent coordination plane /v1/coord/* | config.rs:1336 |
CORECRUXD_COORD_PRESENCE_TTL_SECS | u64 | 900, clamped from 60 to the coordination maximum | - | , | Presence liveness horizon | config.rs:1337 |
5.22 Workspace scan, code graph, ExecPlans
| Name | Type | Default | Flag | Parse | Effect | Read at |
|---|---|---|---|---|---|---|
CORECRUXD_WORKSPACE_PATH | path | none, the scanner returns NotConfigured | - | non-blank | Root the workspace scanner runs against | workspace_scan.rs:274 |
CORECRUXD_AST_SCAN | bool | false | OFF | T7-shaped inline | AST-level scanning | workspace_scan.rs:293 |
CORECRUXD_EXTERNAL_DEPS | bool | false | OFF | T7 | Attach external dependency manifests to the scan | workspace_scan_manifests.rs:39 |
CORECRUXD_POLYGLOT_V2 | bool | false | OFF | T7 | Adds JavaScript, JSX and Go to the code map | workspace_scan_polyglot.rs:76 |
CORECRUXD_POLYGLOT_V3 | bool | false | OFF | T7 | Adds Svelte, Java, C, C++, C#, Ruby, Swift and PHP | workspace_scan_polyglot.rs:80 |
CORECRUXD_CODEGRAPH_EDGES | bool | false | OFF | T7 | Emit code-graph edges | repo_codegraph.rs:88 |
CORECRUXD_CODEGRAPH_EXTERNAL | bool | false | OFF | T7 | Include external symbols in the code graph | repo_codegraph.rs:92 |
CORECRUXD_CODEGRAPH_FUSION | bool | false | OFF | T7-shaped inline | Fuse code-graph signal into retrieval | codegraph_fusion.rs:33 |
CRUX_EXECPLANS_ROOT | path | none: the ExecPlan projection returns an empty list, not an error | - | non-blank | Directory of *.md ExecPlans projected into /v1/work | work_execplans.rs:1130 |
CRUX_OPEN_DECISIONS_PATH | path | none: open_decisions stays empty | - | non-blank | Open-decisions registry path | work_execplans.rs:1390 |
CORECRUXD_FEATURE_DRAFTING_STATE | bool | false | OFF | feature_flag_enabled | Expose the drafting ExecPlan state | work_execplans.rs:116 |
CORECRUXD_FEATURE_NEXT_READY_MILESTONE | bool | false | OFF | feature_flag_enabled | Expose next_ready_milestone on work items | work_execplans.rs:121 |
Nine additional code-map languages ship in every stock binary behind CORECRUXD_POLYGLOT_V2 and _V3. The tree-sitter grammars are unconditional dependencies, so enabling them costs nothing at build time. The default set is Rust, TypeScript, TSX, Python and Vue.
5.23 Remaining MCP tool feature flags
| Name | Type | Default | Flag | Parse | Effect | Read at | ||||
|---|---|---|---|---|---|---|---|---|---|---|
CORECRUXD_FEATURE_MEMORY_PANEL | bool | true | ON | T5 | The memory_view and memory-panel surface | tools/memory.rs:72 | ||||
CORECRUXD_FEATURE_FRESHNESS | bool | true | ON | T5 | Freshness and decay, plus memory_reverify | freshness.rs:59 | ||||
CORECRUXD_FEATURE_CONSOLIDATION | bool | true | ON | T5 | The memory-consolidation surface | consolidation.rs:54 | ||||
CORECRUXD_FEATURE_SCOPED_FORGET | bool | true | ON | T6: =yes disables it | memory_forget | forget.rs:74 | ||||
CORECRUXD_FEATURE_AUDIT_ENVELOPE | bool | false | OFF | T5 | Per-turn audit envelope on tool responses | envelope.rs:105 | ||||
CORECRUXD_FEATURE_MEMORY_ACK | bool | false | OFF | T5 | memory_acknowledge_use and memories_used[] | memory_use.rs:94 | ||||
CORECRUXD_FEATURE_MEMORY_ACK_INLINE | bool | false | OFF | T5 | Inline memory-ack annotation in the hook output | memory_ack_inline.rs:40 | ||||
CORECRUXD_FEATURE_APPROVAL_QUEUE | bool | false | OFF | T5 | Human-approval queue surface | approvals.rs:118 | ||||
CORECRUXD_FEATURE_ARTEFACTS | bool | false | OFF | T5 | The artefacts tool family | artefacts.rs:60 | ||||
CORECRUXD_FEATURE_AUTONOMY_CONTRACT | bool | false | OFF | T5b: no is truthy | The autonomy_contract tool | autonomy.rs:46 | ||||
CORECRUXD_FEATURE_REUSE_CHECK | bool | false | OFF | T5b: no is truthy | The reuse_check tool | reuse.rs:38 | ||||
CORECRUXD_FEATURE_ENGRAM_MCP | bool | false | OFF | T5b: no is truthy | The engram MCP tool surface | engrams.rs:36 | ||||
CRUX_CONTEXT_CUSTODY_AUDIT | bool | false | OFF | `1\ | true\ | TRUE\ | yes\ | YES`, trimmed, case-sensitive | check_config_audit and the context-custody scorecard | context_custody_audit.rs:53 |
5.24 The Claude-hook family
These use an off sentinel: unset, or any value other than the exact string off, leaves the hook enabled. Two members have the opposite polarity, and they are marked.
| Name | Type | Default | Flag | Parse | Effect | Read at | |||
|---|---|---|---|---|---|---|---|---|---|
CRUX_HOOK_SESSION_START | string | enabled | ON | == "off" disables | SessionStart hook, the boot banner | session_start.rs:80 | |||
CRUX_HOOK_COORD | string | enabled | ON | != "off" enables | Live-sessions section of the boot banner | session_start.rs:145 | |||
CRUX_HOOK_WIZARD_CHECK | string | enabled | ON | != "off" enables | Bundled-profile drift check in the banner | session_start.rs:172 | |||
CRUX_HOOK_CONFIG_AUDIT | string | enabled | ON | == "off" disables | Unaudited-config warning in the banner | config_audit.rs:162 | |||
CRUX_HOOK_PRE_COMPACT | string | enabled | ON | == "off" disables | PreCompact hook | pre_compact.rs:35 | |||
CRUX_HOOK_CONTEXT_MONITOR | string | enabled | ON | == "off" disables | Loop and context-pressure warnings | context_monitor.rs:24 | |||
CRUX_HOOK_CODE_CONTEXT | string | disabled | OFF | `matches!(v, "1"\ | "true"\ | "on"\ | "yes")`, untrimmed and case-sensitive. Opposite polarity to its siblings | PreToolUse code-context injection | code_context.rs:39 |
CRUX_HOOK_OBSERVE_CAPTURE | bool | disabled | OFF | T4 | Audit capture writes to the daemon; pair with CORECRUXD_OBSERVE=1 | observe_capture.rs:34 | |||
CRUX_EXECPLAN_SLUG | string | falls back to .crux/active-execplan | - | non-blank | Pins the ExecPlan scope for file-mod observations | observe_filemod.rs:71 | |||
CRUX_MILESTONE | string | falls back to .crux/active-execplan | - | non-blank | Pins the milestone scope | observe_filemod.rs:72 | |||
CLAUDE_PROJECT_DIR | path | skipped if unset | - | , | Project root whose settings files are hashed for the config audit | config_audit.rs:37 | |||
CRUX_LLM_SHIM | bool | disabled, the subcommand refuses to run | OFF | 1 or case-insensitive true | The experimental LLM shim | llm_shim/mod.rs:232 | |||
CRUX_CLOUD_WITNESS | bool | disabled, the subcommand refuses to run | OFF | 1 or case-insensitive true | Cloud-witness mode | llm_shim/mod.rs:243 | |||
CRUX_CLOUD_WITNESS_SESSION_TOKEN | secret | none, no session auth | - | non-empty; BLAKE3-hashed, constant-time compared | Session auth token for the cloud witness | llm_shim/mod.rs:119 | |||
CRUX_CLOUD_WITNESS_TEST_UPSTREAM | URL | none | - | validated; only consulted when already permitted | Insecure test upstream override | llm_shim/mod.rs:258 | |||
CARGO_HOME | path | $HOME/.local/bin is tried first | - | , | $CARGO_HOME/bin/corecruxctl discovery | hooks_bridge.rs:44 | |||
PATH | path list | - | , | split_paths | crux-hook binary discovery | crux-config-wizard/src/hooks_install.rs:149 |
5.25 The corecruxctl CLI and compile-time variables
| Name | Type | Default | Effect | Read at |
|---|---|---|---|---|
CORECRUXCTL_ENV | enum | local | Tooling environment; local / staging / production. An invalid value is an error. Non-local requires ops evidence | tooling_env.rs:44 |
CORECRUXD_BINARY | path | a derived default | Daemon binary used by the integration-test harness | crux-integration-tests/src/lib.rs:265 |
CORECRUXD_STARTUP_TIMEOUT_SECS | u64 | 10 | Per-attempt daemon boot timeout for the harness | crux-integration-tests/src/lib.rs:91 |
CARGO_PKG_VERSION | compile-time | the build fails if absent | Server version, agent-card version, client_version, the default C2PA claim generator | dispatch.rs:394 |
CARGO_MANIFEST_DIR | compile-time | the build fails if absent | Fixture and proto path resolution in build scripts and tests | corecruxd/build.rs:51 |
CORECRUX_GIT_SHA | build-time env | falls back to git rev-parse, then unknown | Baked into --version; a 40-char CI sha is truncated to 7 | corecruxd/build.rs:21 |
5.26 Test-only variables
Every read site of these is inside test or example code. They must not appear in an operator's environment.
| Name | Purpose | Read at |
|---|---|---|
CORECRUX_SOAK_SECS | Soak-test duration, default 2 | corecrux-storage/src/tests.rs:968 |
CORECRUX_SOAK_MAX_EVENTS | Soak-test event cap, default 50000 | corecrux-storage/src/tests.rs:972 |
CORECRUX_SOAK_STREAMS | Soak-test stream count, default 16 | corecrux-storage/src/tests.rs:976 |
CORECRUX_SOAK_LOG_EVERY | Soak-test log cadence, default 5000 | corecrux-storage/src/tests.rs:980 |
CORECRUX_SOAK_EQ_CHECK_EVERY | Soak-test equality-check cadence, default 1024 | corecrux-storage/src/tests.rs:984 |
CRUX_LIVE_REKOR_SEED | Varies the head digest across live Rekor staging runs to avoid duplicate-entry conflicts | witness_submit.rs:938 |
CRUX_BENCH_COMMIT | Commit sha stamped into token-bench records | token_bench.rs:274 |
CRUX_BENCH_RUN_ID | Run id stamped into token-bench records | token_bench.rs:275 |
CRUX_C2PA_DUMP_DIR | Dump C2PA leaf, body and signature for third-party verification | vault_c2pa_m4_integration.rs:102 |
C2PATOOL_BIN | Path to c2patool for the interop leg | vault_c2pa_m4_evidence.rs:148 |
C2PA_M4_SUMMARY_OUT | Machine-readable evidence summary output path | vault_c2pa_m4_evidence.rs:304 |
VAULT_C2PA_ROOT_PEM | Root PEM for the evidence test; the test fails if absent | vault_c2pa_m4_evidence.rs:147 |
CORECRUXD_QUERY_GRAPH_EXPAND_TEST_FAKE_ENV | A deliberately non-existent name, proving the opt-in default is off | http/tests.rs:4254 |
CORECRUXD_QUERY_TIME_RANGE_TEST_FAKE_ENV | The same, for time-range queries | http/tests.rs:4255 |
CORECRUXD_TEST_DEFAULT_ON | Exercises env_default_on | config.rs:1881 |
CORECRUXD_TS_TEST_FLAG_X | Exercises env_flag_enabled truthy values | auth_rails.rs:382 |
__TEST_GATE_ENABLED__ | Exercises is_query_feature_enabled | http/tests.rs:4474 |
CARGO | Path to the cargo binary for re-invoking an example | token_bench_determinism.rs:20 |
CARGO_BIN_EXE_corecruxctl | Cargo-provided path to the built CLI | corecruxctl integration tests |
CRUX_BANNER_CARD appears only as an assertion string in profile.rs:237, checking that the bundled profile text documents the switch. It is not read as an environment variable anywhere.
5.27 Strings that look like environment variables but are not
Recorded so you do not chase them.
FUSION_RRF_LANE_WEIGHTSandFEATURE_FUSION_RRF(console.rs:291) are tenant and global settings-overlay map keys, not environment.- The strings at route_auth.rs:358 and eight sibling lines are documentation labels passed to
RouteAuthContract::gated(...). The real reads live inconfig.rs.CORECRUXD_AGENTGRAPHat route_auth.rs:528 is the one label with no corresponding read. "CORECRUXD_TRUSTED_PROXY_CIDRS"and"CORECRUXD_RATE_LIMIT_EXEMPT_CIDRS"at ingress.rs:232 are error-message labels; the values arrive fromConfig, not from the environment.IO_READ_FAILED,SEGMENT_CORRUPTand theDRIFT_*family at corecrux-types/src/lib.rs:38 are error and drift codes.- The
AKIA…strings scattered through the redaction tests are fixtures.
5.28 Secret handling
Three facts an operator should know before putting secrets in this environment.
- Only one secret is redaction-aware.
CORECRUXD_EMBED_DELEGATE_TOKENis wrapped inRedactedSecret, whoseDebugimplementation prints[REDACTED](config.rs:307). Every other secret inConfigis a plainStringand will appear verbatim in aDebugdump, notablysync_api_keyandreceipts_keyring_json. CORECRUXD_SYNC_API_KEYandCORECRUXD_SYNC_REMOTE_URLuseunwrap_or_default(), so an unset value becomes"", indistinguishable from a deliberately blank one.CORECRUXD_RECEIPTS_KEYRING_PATHand_JSONare read with no trimming and no empty-string filter (config.rs:991); a stray trailing space becomes part of the path.
Separately: the daemon passport key encrypts stored third-party integration credentials via a derived subkey (main.rs:856). Losing or rotating the passport key makes stored integration tokens undecryptable. Treat it as a backup-critical secret, see chapter 6 §6.4.
5.29 A practical operator subset
Of the 393 variables, a typical deployment sets fewer than twenty. This is the working set, and none of it is a substitute for the tables above.
| Variable | Why you set it |
|---|---|
CORECRUXD_AUTH_MODE | Mandatory. The daemon will not start without it |
CORECRUXD_DATA_DIR | Because the default is relative |
CORECRUXD_HTTP_HOST / _PORT | If you are not on loopback |
CORECRUXD_ALLOW_INSECURE_DEV_AUTH_BIND | Only with off or dev_scopes on a non-loopback bind, and only knowingly |
CORECRUXD_JWT_HS256_SECRET or the JWKS set | With a JWT auth mode |
CRUX_AGENT_TOKEN / CRUX_AGENT_TOKENS | To authenticate the MCP plane |
LOG_FORMAT=json | For a structured-log pipeline. Not CORECRUX_LOG_FORMAT |
RUST_LOG or CORECRUXD_LOG_LEVEL | Log verbosity |
CORECRUXD_REDACT=on | If you ship logs off-box; the default only counts |
CORECRUXD_PASSPORT_CLAIM_ON_STARTUP=0 | For an air-gapped or privacy-sensitive deployment |
CORECRUXD_ROUTE_AUTH=enforce | To make the route-auth middleware actually block |
CORECRUXD_CAPACITY_EMERGENCY_FREE_RATIO | To tune the readiness disk gate |
CORECRUXD_OBS_RETENTION_DAYS | Observations are retained forever by default |
CORECRUXD_EPHEMERAL_GC=1 | To reclaim bookkeeping facts |
CORECRUXD_BUILD_CCXI=1 | To build BM25 companion indexes at seal time |

