Crux Daemon · 15. Coordination, cost, export and audit
Everything in this chapter is advisory. The coordination plane warns but never blocks; the cost lens measures tokens and knows nothing about money; export is real but two of its four sections are empty; the config audit records a hash and fails open when the daemon is unreachable. Each mechanism is genuinely useful for what it is. None of them is a control, and none should be relied on as one.
This chapter is reference. Identity and the controls that do enforce are chapter 14; the flags named here are listed in chapter 5; verified defects are in chapter 16; and the set's router is chapter 0.
15.0 In plain English
This chapter collects four features that share one property: they make something visible without making it obligatory. The coordination plane is the clearest case. Run two agent sessions against the same repository and neither can see the other; each will happily edit files the other has half-finished. The coordination plane fixes the seeing, not the colliding. A session announces what it is working on and which paths it expects to touch, the daemon compares that against every other live session's announcement, and it tells you where you overlap. The right analogy is the "someone else is editing this" indicator in a shared document, not a file lock. It shows you the collision; it does not prevent it.
The cost lens is a meter. It counts context tokens carried in and out, so you can see which sessions and which retrieval calls are consuming your budget. Export writes the daemon's state out into a single portable file so it can be moved or inspected elsewhere. The config audit takes a hash of the running configuration so you can tell later whether it changed.
Why build advisory tools rather than enforcing ones? Because the thing being coordinated lives outside the daemon. The daemon does not own your filesystem, and the moment a warning becomes a block, a stale announcement from a session that crashed an hour ago stops real work. Advisory keeps the failure mode benign: the worst an incorrect warning can do is prompt a human to check.
You will touch this chapter when more than one agent works the same tree at once, which is the situation coordination exists for; when you want to know where your token budget went, which is §15.2; and when you are moving a daemon's state between hosts or handing a bundle to somebody else, which is §15.3.
The thing people get wrong is reading advisory as enforcement, and the four features each have their own version of it. The coordination plane's edit enforcement is client-side, so it holds only for clients that choose to honour it, and §15.1 explains why that is materially weaker than it sounds. The cost lens knows about tokens and nothing about money: there is no price table anywhere in it, so it cannot answer "what did this session cost in pounds" and never will without one. Export is real, but two of its four sections are stubbed, and the round trip is not lossless. The config audit fails open, so an unreachable daemon produces a pass rather than an alarm. Each is useful for what it is. None of them is a control, and none should be relied on as one.
15.1 The coordination plane
Status: FLAG CORECRUXD_COORD, default true. Set at config.rs:1336 as env_bool("CORECRUXD_COORD").unwrap_or(true), matching the module doc at coord.rs:35. An explicit CORECRUXD_COORD=0 disables it.
Storage
Everything is facts, born private. Intents live at __coord__::{project_id}::{session_id_hex} under key intent (coord.rs:30). Re-announcing supersedes via the normal (entity, key) version chain, and expiry is read-time via expires_at_unix_ms, so no sweeper is needed (coord.rs:32). __coord__:: is in DEFAULT_PRIVATE_PREFIXES (fact_privacy.rs:123), so intents never sync to a remote.
write_intent (coord.rs:101) constructs the fact with private: false and then relies on fact_privacy::enforce_global (coord.rs:117) to force it private via the reserved prefix, belt and braces, and a good illustration of how the born-private policy is meant to be used.
TTLs
| Constant | Value | Line |
|---|---|---|
DEFAULT_PRESENCE_TTL_SECS | 900 (15 minutes) | coord.rs:46 |
DEFAULT_INTENT_TTL_SECS | 14,400 (4 hours) | coord.rs:51 |
MAX_TTL_SECS | 86,400 (24 hours, a hard cap) | coord.rs:55 |
The hard cap exists "so a typo'd ttl_seconds can't pin a stale row on the board for a month". ttl_seconds: 0 clears an intent immediately (coord.rs:50), which is the clean way to exit.
CoordIntent
Fields (coord.rs:67): project_id, session_id_hex, passport_id, optional execplan_slug, optional milestone, optional deploy_target, paths: Vec<String>, optional note, announced_at_unix_ms and expires_at_unix_ms. is_live(now) is now < expires_at_unix_ms (coord.rs:93).
Note the field comment on paths at coord.rs:83: "Informational, enforceable leases are punchcards." The daemon says it about itself.
list_intents (coord.rs:125) queries by entity prefix with top_k: 500, runs dedup_latest to take the highest version per (entity, key), and includes expired intents so audit readers can see stale rows; the active view filters with is_live (coord.rs:122).
Overlap detection
paths_overlap (coord.rs:156) is component-aware prefix containment, not a raw string prefix:
let a = a.trim_end_matches('/');
let b = b.trim_end_matches('/');
if a.is_empty() || b.is_empty() { return false; }
if a == b { return true; }
let (shorter, longer) = if a.len() < b.len() { (a, b) } else { (b, a) };
longer.starts_with(shorter) && longer.as_bytes().get(shorter.len()) == Some(&b'/')
So src/work covers src/work/item.rs but not src/work.rs, and src/work.rs does not overlap src/worker.rs. A raw prefix match would wrongly flag both. Tests at coord.rs:581.
lease_resource_path (coord.rs:171) strips a punchcard scheme (file://, tree://) down to a bare path for comparison; an unknown scheme passes through unchanged.
find_overlaps (coord.rs:197) compares the announced intent against live peer intents and held leases, skipping self and leases held by the announcing passport. It emits OverlapWarning { peer_session_id_hex, peer_passport_id, kind, theirs, yours } (coord.rs:183) with kind in execplan, intent_path or lease, plus a deploy_target warning when two live peers declare the same deploy target (coord.rs:219). Every warning is documented as "Never blocking, coordination signal only" (coord.rs:180).
Punchcard leases
CORECRUXD_PUNCHCARD is tri-state, off, advisory or enforce, parsed at agentgraph_kinds.rs:161. Anything unrecognised, and an unset variable, is off (agentgraph_kinds.rs:166). When off, every punchcard route returns a disabled response (punchcards.rs:70).
Acquisition behaviour when a different holder already has the lease:
| Mode | Behaviour |
|---|---|
off | routes are disabled entirely |
advisory | reports the conflict but still grants a possibly-overlapping lease, "writers are never denied" (punchcards.rs:419) |
enforce | HTTP 409 with {held_by, punchcard_id, expires_at_unix_ms} (punchcards.rs:422) |
A re-acquire by the same holder is re-entrant and returns {punchcard, reentrant: true}. check_punchcard (punchcards.rs:597) is the hook-facing probe; when the surface is disabled it reports {enforce: false, held_by_other: false}, which the hook reads as ALLOW.
Edit enforcement is client-side, which is materially weaker
The MCP tool description states the mechanism outright (punchcards.rs:34):
Returns
{ held_by_other, enforce, holder_passport, resource, expires_at_unix_ms }. The PreToolUse hook calls this before an edit and denies only whenheld_by_other && enforce.
Three consequences, and the third is the one that matters:
- The daemon does enforce one thing server-side: in
enforcemode it refuses to grant a conflicting lease, with a 409. - The daemon does not block any read or write to the leased resource. Nothing on the server intercepts a file operation, because the daemon does not perform your file operations.
- The actual edit denial is performed by a client-side hook, the Claude Code
PreToolUsehook incrates/crux-claude-hooks. A client that does not run the hook, a client that runs a modified hook, or any direct HTTP or MCP caller, is entirely unaffected by any lease.
A client-side check is a coordination convention, not an access control. It prevents accidents between cooperating agents. It prevents nothing at all against a caller that declines to cooperate, and it must never be cited as a safety property of the daemon.
Combined with the CORECRUXD_PUNCHCARD=off default, the accurate summary is: in the shipped default configuration the coordination plane is entirely advisory. Overlaps and leases are signals, and nothing on the server prevents two sessions writing the same file.
15.2 The cost lens
Status: FLAG CORECRUXD_FEATURE_COST_LENS, default OFF for the daemon storage and read endpoints. The analyser and CLI are shipped and unflagged.
It measures tokens. There is no currency in the model.
There is no price table and no monetary field anywhere in the cost lens. A repository-wide search for usd, price, dollar, cost_per, per_million or cents across crates/crux-cost/, corecruxd/src/cost.rs, cost_attribution.rs, http/cost.rs and corecruxctl/src/cost.rs returns nothing, and CostReport (report.rs:34) has no monetary field.
"Cost" here means carried context tokens. If you are looking for "what did this session cost in dollars", the daemon cannot tell you; it does not know your rate card, and it never sees one.
How it is measured
The crate doc is explicit (crux-cost/lib.rs:8): measure from the transcript's real message.usage; the chars-over-four estimate is used only to apportion the measured spend across blocks. That is the opposite direction from the MCP token estimates in chapter 11, and the two must never be quoted as the same number.
- Ground truth:
Measured { input, output, cache_read, cache_creation }(report.rs:121), withcontext_read() = cache_read + cache_creation + input(report.rs:135). - Extraction:
parse_usagereadsinput_tokens,output_tokens,cache_read_input_tokensandcache_creation_input_tokens, with a fallback for the nestedcache_creationshape (transcript.rs:295). - Apportionment: a block entering at turn
ein ak-turn segment costsest_tokens × (k − e)(attribution.rs:6), and the residual is forced into asession_prefixbucket so buckets reconcile exactly to the measured total (attribution.rs:113). - Privacy: only 80 characters of preview per block are retained, and thinking previews are redacted (transcript.rs:16), asserted by a
thinking_text_never_surfacestest (crux-cost/lib.rs:151). - The transcript format is acknowledged as undocumented and drifting, and is parsed fail-soft (transcript.rs:8).
Headline (report.rs:99) carries assistant_turns, tasks, segments, context_tokens_per_turn (the headline metric), cache_read_to_output_ratio, measured_context_total and prefix_pct. The "levers" are threshold rules rather than a model: prefix ≥ 40% (levers.rs:28), tool_result ≥ 20%, tool_use_args ≥ 15%, assistant_thinking ≥ 15%, cache-read to output ≥ 20.
What it is bound to
- The producer is entirely client-side.
corecruxctl session costparses the operator's local transcript, and "the daemon never sees the transcript" (corecruxd/cost.rs:6). Discovery walks the local Claude Code projects directory (corecruxctl/cost.rs:57). - Storage key is
(tenant_id, session_id)(corecruxd/cost.rs:102), with an explicit resolution order of the requestsession_id, thenreport.session_id, then the source filename (http/cost.rs:74). - Passport is recorded as
actor_passport(corecruxd/cost.rs:61) or the__anon__sentinel. Attribution metadata, not an enforcement key. - Work item and ExecPlan attribution is a read-time join, not a binding (cost_attribution.rs:6). Precise
method = "link"applies when the report carriesexecplan_slugs, splitting burn evenly across N plans; otherwise a coarsemethod = "window"overlap credits all temporally overlapping plans. The module records its own measured coarseness: "~186 multi-day sessions credited 753/~934 plans" (cost_attribution.rs:36). Read awindow-method number as a rough indication, never as an itemised bill. - It is bound to no quota, no budget enforcement and no billing. Nothing in the cost lens blocks, throttles or charges.
The flag
CORECRUXD_FEATURE_COST_LENS is not in config.rs; it is read straight from process env in corecruxd/cost.rs:30, where an unset value, "", 0, false, off or no all mean off. When off, both POST and GET /v1/cost/report return 404 "cost lens disabled" (http/cost.rs:35) and the journal at <data_dir>/cost/reports.jsonl is never armed (corecruxd/cost.rs:218).
When on, the read path enforces a mandatory token_budget and trims top_blocks until the report fits (http/cost.rs:122), one of the few surfaces where the budget is required rather than optional.
15.3 Export and custody
.cruxpack is a single uncompressed JSON file
Not a tar, not a zip, not a directory: serde_json::to_vec(&pack) written straight to the --out path and then sync_all() (memory_pack.rs:139). Schema tag "crux.cruxpack.v1" (cruxpack.rs:43). Expect it to be large and to compress well; it is not compressed for you.
CruxPack (cruxpack.rs:191) is {schema_version, manifest, sections, blake3_content_hash, passport_signature}. The content hash is blake3:<64-hex> over canonical JSON of {manifest, sections} (cruxpack.rs:214).
PackManifest (cruxpack.rs:131) carries daemon_install_fpr (a BLAKE3 of the install UUID, never the raw UUID), passport_fpr, public_key_hex, the field that makes the pack self-certifying, tenant_id, exported_at, since, chain_head, counts, included_private and tool.
PackSignature (cruxpack.rs:180) is Ed25519 over the decoded 32-byte BLAKE3 hash, hash-then-sign (cruxpack.rs:390), using the exporting daemon's passport.key via a closure, so the memory crate never touches private key material.
The trust model is stated candidly in the source (cruxpack.rs:462): "No network access, no PKI: the pack is self-certifying to a fingerprint; whether to trust that fingerprint is the caller's decision."
Two of the four sections are stubbed
PackSections (cruxpack.rs:169) declares facts, sessions, entities and receipts.
entities and receipts are schema-reserved and always empty in v1, build_pack_sections hard-codes Vec::new() for both (cruxpack.rs:350). STUBBED. The substrate graph and the receipt chain do not travel in a .cruxpack. If you export expecting your receipts to come with you, they will not, export them separately as an audit bundle.
Exclusion rules
Implemented in build_pack_sections (cruxpack.rs:297):
deleted == trueis excluded unconditionally (cruxpack.rs:301). No flag overrides it, andverify_packhard-rejects any pack carrying a deleted fact withDeletedFactsPresent(cruxpack.rs:489).private == trueis excluded unlessinclude_private(cruxpack.rs:315).- A reserved born-private prefix is excluded unless
include_private;CRUXPACK_RESERVED_PREFIXESis a 39-entry list (cruxpack.rs:62). stored_at < sinceis excluded when--sinceis given.- Sessions whose id starts with
__are always excluded, with no opt-in (cruxpack.rs:326); sessions travel at all only wheninclude_sessions, which defaults to true.
include_private is not a bare flag. The CLI requires the operator to type the literal phrase include private (memory_pack.rs:33) after being shown a per-prefix scan of exactly what would be copied (memory_pack.rs:78); declining aborts before anything is written. That is a good pattern and worth copying elsewhere.
Exports are deterministic: facts sorted by (entity, key, version, fact_id) and sessions by id, so two exports of the same store are byte-identical (cruxpack.rs:292).
Verification is strict; the round trip is not lossless
verify_pack (cruxpack.rs:450) applies seven hard rejects in order: a schema gate; counts against section lengths; no deleted facts; private-consistency (private or reserved facts present with included_private == false is treated as tampering); recompute-and-compare of the content hash; self-certification, where the derived fingerprint must equal the manifest fingerprint; and finally Ed25519 verification over the 32-byte hash.
plan_import (cruxpack.rs:589) applies a tenant gate with no override in v1. What is lost on the way in:
| Behaviour | Detail |
|---|---|
source_receipt is overwritten | every imported fact gets cruxpack:<blake3_content_hash> (cruxpack.rs:648); the original receipt linkage survives only inside the pack file |
actor may be remapped | via principal_map (cruxpack.rs:643) |
fact_id, version, stored_at, supersedes are not carried | StoreFact has no such fields; the receiver mints new ones (cruxpack.rs:652) |
| Imports never overwrite | a colliding live (entity, key) lands as a new version and is counted in plan.collisions (cruxpack.rs:634) |
| Existing sessions are skipped, not restored | cruxpack.rs:665 |
| Re-import is idempotent | matched on source_receipt plus entity, key and value (cruxpack.rs:604) |
Application goes through FactStore::try_store_bulk, "the journaled, receipted bulk path; never a raw filesystem write" (cruxpack.rs:584).
HTTP import is flag-gated off. POST /v1/memory/import returns 404 "memory import disabled (set CRUX_MEMORY_IMPORT=1)" (memory_import.rs:80); the default is false (config.rs:1374). The CLI mirrors the gate. There is no HTTP export route for .cruxpack at all, export is CLI-only.
context export: the composed bundle
corecruxctl context export composes a bundle directory, not an archive, containing memory.cruxpack, audit-bundle.tar.zst and context-manifest.json (export.rs:21). The manifest (export.rs:194) records schema crux.context_export.v1, both component BLAKE3 hashes, counts, an embedded offline audit-verify report, and a signature block.
The signed message is a deterministic newline-joined string rather than the JSON (export.rs:122), BLAKE3-hashed then Ed25519-signed with the algorithm tag "ed25519-over-blake3(signing_input)". context verify rebuilds the signing input from the manifest's own recorded fields, re-hashes both components, re-verifies the cruxpack and re-runs audit-verify, fully offline (export.rs:290).
audit_export_bundle
Format is tar.zst at bundle_format_version: 3 (audit_bundle_v1.rs:6). Member filenames are exported constants so third-party tooling can tar -tf (audit_bundle_v1.rs:74): manifest.json, events.jsonl, receipts.cbor, and optionally witness_proofs.jsonl, omitted entirely when there are no witnessed heads, so witness-free bundles stay byte-identical to pre-witness bundles.
Receipt bodies are not included. receipts.cbor is only a {fact_id, receipt_id} cross-reference list (audit_bundle_v1.rs:145).
Verification, key resolution and the independent Python verifier are documented in chapter 13 §13.10, the audit bundle is the strongest artefact in that chapter and this one.
MCP gating: CORECRUXD_FEATURE_AUDIT_EXPORT, default OFF (audit_export.rs:47), returning METHOD_NOT_FOUND when unset. token_budget is mandatory (audit_export.rs:117), and reserved prefixes are stripped unless the caller both requests include_reserved and is authenticated (audit_export.rs:152).
15.4 context_custody_audit: read it as a statement about the architecture
Status: FLAG CRUX_CONTEXT_CUSTODY_AUDIT, default OFF (context_custody_audit.rs:37).
The tool scores the daemon against a "race to context" exit test. Being precise about what it measures matters, because the number it produces looks computed and is largely not.
Inputs. CustodyInputs has exactly seven fields (context_custody_audit.rs:85), gathered at context_custody_audit.rs:104: revocation_enforced (a runtime bool off the context), agent_card_enabled (an env resolver), receipt_verify_enabled (CORECRUXD_FEATURE_RECEIPT_VERIFY), audit_export_online (CORECRUXD_FEATURE_AUDIT_EXPORT), router_present (ctx.rcx_router.is_some()), sync_remote_configured (CORECRUXD_SYNC_REMOTE_URL non-empty) and fact_count (context_custody_audit.rs:309).
That is four environment reads, two context values and an integer. No file is opened, no export is attempted, no pack is built or verified, no receipt is checked, and no sync state is probed.
Outputs. build_scorecard (context_custody_audit.rs:134) emits 10 axes. Exactly three of them respond to runtime flag state:
| Axis | Verdict source | Line |
|---|---|---|
| CHECK | ternary on receipt_verify_enabled: strong or partial | :158 |
| REVOKE | ternary on revocation_enforced: strong or partial | :192 |
| ROUTE | ternary on router_present: strong or partial | :210 |
| SEE | constant "strong" | :136 |
| DO | constant "strong" | :143 |
| REMEMBER | constant "strong" | :149 |
| EXPORT | constant "strong" | :177 |
| INSPECT | constant "strong" | :186 |
| KEEP-LOCAL | constant "strong" | :220 |
| PROVE | constant "strong" | :238 |
The remaining inputs, agent_card_enabled, audit_export_online, sync_remote_configured, fact_count, affect only the human-readable evidence strings and the trust_posture.recommendations list, never a verdict.
The headline lock_in_risk is structurally always 1. It starts at 1 and adds +2 if EXPORT is not "strong", +1 if KEEP-LOCAL is not "strong", and +1 if ROUTE is "none" (context_custody_audit.rs:252). But EXPORT and KEEP-LOCAL are hardcoded "strong" literals, and ROUTE is a two-way ternary that yields "strong" or "partial", "none" is never produced by any code path. All three increments are therefore dead. Both tests confirm it, including the case with every flag off (context_custody_audit.rs:355). lock_in_label is consequently always "trivial to leave". trust_posture.standing_gap is likewise a hardcoded string (context_custody_audit.rs:291).
Reading it fairly. The code's own comments argue a defensible design position: EXPORT is "structurally strong: the offline path … is always available regardless of flags" (:174), and ROUTE reasons that "even with no hosted router, the substrate is model-agnostic by construction … so absence of a router is partial, never a lock-in" (:208). Those are claims about the architecture rather than about your process, and as architectural claims they are consistent with what §15.3 documents: CLI export genuinely does work regardless of flags, and private facts genuinely never sync. The module doc is also candid that the tool "is a pure read: it reads runtime flags and McpContext capability presence" (:19).
And still: a constant is not a measurement. lock_in_risk: 1 is the same number on a daemon with every capability enabled and a daemon with none, and no configuration you can apply will change it. Read the scorecard as a statement about how the architecture is designed, not as a result computed from your daemon. Seven of the ten verdicts will say "strong" whatever you do; the three that vary, CHECK, REVOKE, ROUTE, are the only part of the output that tells you anything about the process you are running. Do not put lock_in_risk in front of a risk reviewer as an assessment of your deployment.
15.5 Config audit
Status: SHIPPED, advisory only. The MCP pair is unflagged and always dispatchable; the client hook is on by default with a literal-off opt-out; nothing is enforced and the failure mode is open.
What is hashed
SHA-256, not BLAKE3, a deliberate contrast with the rest of the codebase, which is BLAKE3-first. It is computed client-side by the hook, streamed in 8 KiB chunks (config_audit.rs:21, config_audit.rs:65). A missing file yields Ok(None) and is skipped silently (config_audit.rs:67); only a genuine I/O failure prints to stderr. Correctness is pinned by a known-input test (config_audit.rs:182).
Inputs are the whole-file contents of a fixed, hardcoded probe list of at most eight paths (config_audit.rs:26), the settings files, the MCP config and the memory file, at both user and project level, de-duplicated by path.
No environment variables are hashed. No daemon configuration is hashed. No MCP server binary or tool schema is hashed. The unit of audit is the byte content of those files, and the daemon never reads them; it only ever sees the hex digests the client sends (config_audit.rs:96).
The sign-off model
Who signs off: whoever calls audit_config and supplies an auditor string. That field is free text, "passport id, email, or free-text identifier" (mod.rs:1329), taken verbatim from the argument and stored as-is (audit.rs:56). It is not derived from, checked against, or bound to the calling passport; the handler never touches ctx.agent. Anyone who can call the tool can sign off as anyone.
Where it is stored: one fact under entity __ops::config-audit (audit.rs:24), key sha256:<full-64-hex> (audit.rs:27), value a JSON AuditRecord { path, auditor, note?, audited_at } (audit.rs:33). It is written private: false, but __ops:: is a born-private prefix so enforce_global flips it, and it is consequently excluded from .cruxpack export by default.
The hash is the identity; the path is advisory (audit.rs:10). One fact covers every path and every machine that produced identical content.
What "checked" means: check_config_audit (audit.rs:101) loads every fact under __ops::config-audit, keeps the highest-version record per hash, and reports each submitted {path, sha256} as audited or unaudited. So "checked" means only "this 64-hex string has previously been posted to this daemon by someone claiming to be an auditor." There is no signature, no receipt, no approval workflow and no evidence that anyone read anything. Input validation on the hash is strict, exactly 64 ASCII hex characters (audit.rs:223).
On drift: the bytes change, so the hash changes, so the path reappears in unaudited at the next SessionStart. Re-auditing the same hash is idempotent and updates the record as a new version. There is no revocation, an old approved hash stays approved forever, so reverting a file to a previously-signed-off state silently returns to "audited" with no signal. If you are using this to detect tampering, note that a rollback to a known-good-and-signed configuration is indistinguishable from never having changed.
Advisory, and fail-open
The module states it: "Warn-only by design: unaudited paths are surfaced via additionalContext, never block the session" (config_audit.rs:12).
session_start_warning()returnsNone, silently disabling itself, whenCRUX_HOOK_CONFIG_AUDITis exactly the string"off"(config_audit.rs:161). That is the only value that disables it, the check is== Ok("off"), so0,falseandnodo not turn it off. The feature is on by default with a single-string opt-out, which inverts the flag convention used elsewhere in the repository.- On any error, daemon down, no auth, network failure,
unaudited_via_daemonreturns an empty vector, that is, it fails open to "everything is fine" (config_audit.rs:106). Acapability_not_permittedresponse is swallowed without printing, because it fires every session start for free and local-tier tokens (config_audit.rs:109). - The consumer pushes a text section into the SessionStart output tagged
Stability::Volatile(session_start.rs:162). Nothing branches on it. At most 8 paths are listed with 16-character hash prefixes and an "… and N more" tail.
A silent green here means one of two things: your configuration is audited, or the daemon could not be reached. The output does not distinguish them.
15.6 Status summary
| Capability | Status |
|---|---|
| Coordination plane: presence, intents, overlap detection | FLAG CORECRUXD_COORD, default true; SHIPPED |
CORECRUXD_COORD_PRESENCE_TTL_SECS | default 900, clamped 60..=86400 |
| Punchcard leases | FLAG CORECRUXD_PUNCHCARD, default off; advisory grants with a warning; enforce 409s on lease acquisition only |
| Edit-time enforcement | Client-side hook, not server-enforced; a non-cooperating client is unaffected |
| Cost analyser and CLI | SHIPPED, unflagged, client-side |
| Cost storage and read endpoints | FLAG CORECRUXD_FEATURE_COST_LENS, default off; 404 when off |
| Currency or pricing in the cost lens | Not present, no monetary field anywhere |
| Cost-to-ExecPlan attribution | SHIPPED as a read-time join; window method credits all overlapping plans |
.cruxpack build, sign, verify, import-plan | SHIPPED; one uncompressed JSON file |
PackSections.entities / .receipts | STUBBED, always empty in v1 |
HTTP .cruxpack import | FLAG CRUX_MEMORY_IMPORT, default false (404 when off) |
HTTP .cruxpack export | Not present, CLI only |
context export / context verify | SHIPPED, unflagged, fully offline |
audit_export_bundle (MCP) | FLAG CORECRUXD_FEATURE_AUDIT_EXPORT, default off; mandatory token_budget |
context_custody_audit | FLAG CRUX_CONTEXT_CUSTODY_AUDIT, default off; 3 of 10 axes vary with runtime state, lock_in_risk is structurally always 1 |
| Config audit (MCP pair) | SHIPPED, unflagged |
| Config audit (client hook) | On by default; only the literal CRUX_HOOK_CONFIG_AUDIT=off disables it |
| Config-audit enforcement | Not present: warn-only, no signature, no passport binding, no revocation, fails open |
Sources
- crates/corecruxd/src/config.rs:1336,
CORECRUXD_COORDdefault true - crates/corecruxd/src/coord.rs:156,
paths_overlap - crates/corecruxd/src/coord.rs:180, "Never blocking, coordination signal only"
- crates/corecruxd/src/agentgraph_kinds.rs:161, the tri-state punchcard flag, defaulting off
- crates/crux-mcp/src/tools/punchcards.rs:34, the client-side hook contract
- crates/crux-cost/src/report.rs:34,
CostReport, no monetary field - crates/corecruxd/src/cost.rs:6, "the daemon never sees the transcript"
- crates/corecrux-memory/src/cruxpack.rs:350, the stubbed
entitiesandreceiptssections - crates/corecruxctl/src/memory_pack.rs:33, the literal
include privateconfirmation phrase - crates/crux-mcp/src/tools/context_custody_audit.rs:252, the
lock_in_riskarithmetic - crates/crux-mcp/src/tools/audit.rs:56, the unvalidated
auditorfield - crates/crux-claude-hooks/src/config_audit.rs:106, the fail-open error path

