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

ConstantValueLine
DEFAULT_PRESENCE_TTL_SECS900 (15 minutes)coord.rs:46
DEFAULT_INTENT_TTL_SECS14,400 (4 hours)coord.rs:51
MAX_TTL_SECS86,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:

ModeBehaviour
offroutes are disabled entirely
advisoryreports the conflict but still grants a possibly-overlapping lease, "writers are never denied" (punchcards.rs:419)
enforceHTTP 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 when held_by_other && enforce.

Three consequences, and the third is the one that matters:

  • The daemon does enforce one thing server-side: in enforce mode 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 PreToolUse hook in crates/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), with context_read() = cache_read + cache_creation + input (report.rs:135).
  • Extraction: parse_usage reads input_tokens, output_tokens, cache_read_input_tokens and cache_creation_input_tokens, with a fallback for the nested cache_creation shape (transcript.rs:295).
  • Apportionment: a block entering at turn e in a k-turn segment costs est_tokens × (k − e) (attribution.rs:6), and the residual is forced into a session_prefix bucket 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_surfaces test (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 cost parses 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 request session_id, then report.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 carries execplan_slugs, splitting burn evenly across N plans; otherwise a coarse method = "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 a window-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):

  1. deleted == true is excluded unconditionally (cruxpack.rs:301). No flag overrides it, and verify_pack hard-rejects any pack carrying a deleted fact with DeletedFactsPresent (cruxpack.rs:489).
  2. private == true is excluded unless include_private (cruxpack.rs:315).
  3. A reserved born-private prefix is excluded unless include_private; CRUXPACK_RESERVED_PREFIXES is a 39-entry list (cruxpack.rs:62).
  4. stored_at < since is excluded when --since is given.
  5. Sessions whose id starts with __ are always excluded, with no opt-in (cruxpack.rs:326); sessions travel at all only when include_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:

BehaviourDetail
source_receipt is overwrittenevery imported fact gets cruxpack:<blake3_content_hash> (cruxpack.rs:648); the original receipt linkage survives only inside the pack file
actor may be remappedvia principal_map (cruxpack.rs:643)
fact_id, version, stored_at, supersedes are not carriedStoreFact has no such fields; the receiver mints new ones (cruxpack.rs:652)
Imports never overwritea colliding live (entity, key) lands as a new version and is counted in plan.collisions (cruxpack.rs:634)
Existing sessions are skipped, not restoredcruxpack.rs:665
Re-import is idempotentmatched 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:

AxisVerdict sourceLine
CHECKternary on receipt_verify_enabled: strong or partial:158
REVOKEternary on revocation_enforced: strong or partial:192
ROUTEternary on router_present: strong or partial:210
SEEconstant "strong":136
DOconstant "strong":143
REMEMBERconstant "strong":149
EXPORTconstant "strong":177
INSPECTconstant "strong":186
KEEP-LOCALconstant "strong":220
PROVEconstant "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() returns None, silently disabling itself, when CRUX_HOOK_CONFIG_AUDIT is exactly the string "off" (config_audit.rs:161). That is the only value that disables it, the check is == Ok("off"), so 0, false and no do 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_daemon returns an empty vector, that is, it fails open to "everything is fine" (config_audit.rs:106). A capability_not_permitted response 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

CapabilityStatus
Coordination plane: presence, intents, overlap detectionFLAG CORECRUXD_COORD, default true; SHIPPED
CORECRUXD_COORD_PRESENCE_TTL_SECSdefault 900, clamped 60..=86400
Punchcard leasesFLAG CORECRUXD_PUNCHCARD, default off; advisory grants with a warning; enforce 409s on lease acquisition only
Edit-time enforcementClient-side hook, not server-enforced; a non-cooperating client is unaffected
Cost analyser and CLISHIPPED, unflagged, client-side
Cost storage and read endpointsFLAG CORECRUXD_FEATURE_COST_LENS, default off; 404 when off
Currency or pricing in the cost lensNot present, no monetary field anywhere
Cost-to-ExecPlan attributionSHIPPED as a read-time join; window method credits all overlapping plans
.cruxpack build, sign, verify, import-planSHIPPED; one uncompressed JSON file
PackSections.entities / .receiptsSTUBBED, always empty in v1
HTTP .cruxpack importFLAG CRUX_MEMORY_IMPORT, default false (404 when off)
HTTP .cruxpack exportNot present, CLI only
context export / context verifySHIPPED, unflagged, fully offline
audit_export_bundle (MCP)FLAG CORECRUXD_FEATURE_AUDIT_EXPORT, default off; mandatory token_budget
context_custody_auditFLAG 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 enforcementNot present: warn-only, no signature, no passport binding, no revocation, fails open

Sources