Operations · 4. Memory and Trust
Memory is where you look at what the daemon knows. Trust is where you look at whether you can rely on it. This chapter is reference. Each screen leads with what it is for and why you would open it, then the exhaustive control list.
4.1 Memory › Facts: the whole visible store
Open this when you want to answer "did that get written, and when". It is the durable record: every fact the daemon can currently see, paged, searchable, and rewindable to any point in the past.
This screen is not the section-model renderer everything else uses. It is hand-built, because it needs server-side pagination, server-side search and a per-row dereference of the full untruncated value (render.js:10588).
The toolbar
| Control | Type | Default | What it does | Query parameter |
|---|---|---|---|---|
| search | search box | empty | Server-side search across entity, key and value. 250 ms debounce, then a full reload from page one | q |
| as of | datetime-local | empty | The ingest-time machine. Shows the store as it was at that instant. A tag appears in the count line when set | as_of_unix_ms |
| superseded | toggle | on | Include facts retired by a cross-entity supersede | include_superseded=0 when off |
| reserved __\* | toggle | off | Include daemon-reserved entities: coordination announces, extension grants, session bindings, legal holds | include_reserved=1 when on |
Turn superseded off when you want only what currently resolves. Turn reserved on when you are debugging coordination, punchcards or extension grants; those are all facts under reserved prefixes, not separate files (daemon chapter 1 §1.8).
Clicking a reserved-prefix chip turns the reserved toggle on for you, because a prefix filter for __x:: with reserved facts hidden would return nothing (render.js:10779).
The count line, and the census
The count line reads, for example:
100 shown of 4,812 visible · 5,026 stored (98 private + 116 reserved hidden)
Those numbers are not estimates. The stored figure and the private/reserved split are derived from two limit=1 probes against the same route, one with reserved off, one with reserved on, so the split comes from the daemon's own response fields (render.js:10672). With a search or prefix active, "visible" becomes "matches".
Prefix chips
Below the count, up to 12 chips, one per entity prefix present in the loaded rows, each with its count, plus an all chip. Clicking one applies a server-side entity_prefix filter and reloads; it is not a client-side hide.
Groups are collapsible <details>; the four largest open by default and your open/closed choice survives paging (render.js:10760). Groups carry a colour tint by prefix: execplan accent, bench ok, incident critical, design trust, session warn (render.js:10566).
A row, and what expanding it does
A row shows key, entity, badges and a stored-at timestamp, over a truncated value. Two badges matter:
| Badge | Means |
|---|---|
superseded | Retired by another fact. Its superseded_by id is in the tooltip |
N ch | The value was truncated at N characters. Open the row for the full text |
Clicking or pressing Enter expands the row, which fetches the full fact by id and renders every field: fact_id, entity, key, actor, confidence, horizon_class, tokens, version, stored_at, and superseded_by where present, then the complete value, pretty-printed if it parses as JSON (render.js:10711). If the dereference fails, the drawer says so with the HTTP status and falls back to the row's truncated value rather than showing nothing.
Paging
| Limit | Value | Behaviour |
|---|---|---|
| Page size | 100 rows | Server-side cursor pagination |
| DOM cap | 2,000 rows | Past this, paging stops and the page says: narrow with search or a prefix chip |
| Infinite scroll | on | A sentinel 500px below the fold triggers the next page |
A Load more button also appears, showing the remaining count when the daemon reports a total.
The degraded path
On a daemon without the listing route, a 404 on the first page flips the whole surface to the recent-window feed with a warning banner saying exactly that, and no server paging or search (render.js:10837). The banner is not decoration, the numbers you see afterwards are a window, not the store.
4.2 Memory › Memory: the recent window, per tenant
Open this when you want a quick read on which tenants are active. It is the last 50 facts, grouped by tenant, over GET /v1/console/facts?top_k=50 (pages.js:208).
| Control | Default | What it does |
|---|---|---|
| Filter tenants… | empty | Client-side filter over the rendered rows |
| hide system tenants | on | Hides tenants whose id starts with __, __agent::, __ops::, __bootstrap__:: and siblings, which carry daemon internals |
Each tenant expands to its eight most recent facts as key/value rows. This is a summary surface; Facts (§4.1) is the authority.
4.3 Memory › Tenants: and the AMR defaults panel
Open this to see which memory stores exist and how retrieval is routed for each. Adaptive Manifest Routing (AMR) picks retrieval lanes per query; this screen is where the default lane policy lives (pages.js:228).
The header controls
| Control | Where | Default | What it does |
|---|---|---|---|
| ⚙ cog | Tenants card header, right | - | Reveals the AMR defaults card above the list. It starts hidden |
| hide system tenants | Tenants card header, right | on | View filter over the list |
| Filter tenants… | First row of the list | empty | Client-side filter |
The AMR defaults panel
Set the lane policy once; tenants inherit unless pinned. The panel opens with a subscription line stating the current entitlement, then the lane controls (pages.js:115):
| Control | Type | Default | What the lane is |
|---|---|---|---|
| automatic, let AMR choose lanes | toggle | on | Recommended. AMR reads the lane manifest and fuses the lanes that earn their tokens, per query |
| lexical (BM25) | info row | always on | Free, local. Not a toggle; it cannot be turned off |
| dense lane | toggle | off | Semantic similarity over embeddings: meaning, not spelling. Bring-your-own-embedder or managed |
| graph lane | toggle | off | Entity links walked at query time |
| entity lane | toggle | off | Who/what-keyed recall: ask about a person, get their dossier |
| event lane | toggle | off | Time-anchored recall: what happened, when, in what order |
| nav lane | toggle | off | Summary-tree descent for corpora too large to scan |
| verbatim lane | toggle | on | Exact-quote recall without duplicating content. Free, local |
| Apply defaults to all tenants | button | - | See below |
Expanding a tenant gives the same lane list, prefixed by a use AMR defaults toggle (on) that pins or inherits, and a Collaborate with team row marked as a paid-plan capability.
Apply defaults to all tenants is STUBBED, and the source says why: there is no bulk route. Only a per-tenant category PATCH exists, and "all" would be an unbounded client loop over every tenant, outside the curated single-call mutation model (pages.js:1672).
That means, plainly: the lane toggles on this screen are display controls. They show the policy; they do not write it from here.
4.4 Memory › Documents
Open this to see what corpora the daemon has read. Tenants expand to their documents and chunk counts, with an ingest form beneath (pages.js:1215).
| Control | Type | Default | Status |
|---|---|---|---|
| Filter tenants / documents… | search | empty | Client-side |
Choose folder… | button | - | STUBBED, a browser picker that would fill the prefix |
| source path / glob | text, mono | empty | Operator-only |
| doc prefix | text, mono | empty | Operator-only |
| target tenant | select | default | Operator-only |
| chunking profile | select | default · 512 tok | Also markdown-aware, code-aware |
| extract entities (NER) | toggle | on | Operator-only |
| Scan path | button | - | SHIPPED, live. POST /v1/workspace/scan |
| Queue ingest | button | - | STUBBED |
Queue ingest is gated for a stated reason: the only real route is a synchronous local-ingest that needs a documents[] payload, while this control models "queue a path for the agent to pick up". The shapes do not match and there is no path-to-documents bridge to ground it (pages.js:1670). Ingest from the CLI or MCP instead.
4.5 Memory › Review: contradictions and consolidation
Open this when two agents have written opposing facts and you need to pick a winner. Three cards (pages.js:476).
Review queue
Surfaced runs from the consolidation scheduler, over GET /v1/console/review/queue?limit=50. The card states the scheduler's state explicitly and distinguishes two empty cases, which is the whole value of the panel:
| State | Message |
|---|---|
| Scheduler on, store clean | scheduler is on and the store is currently clean, no contradiction or expiry proposals |
| Scheduler off | enable CORECRUXD_CONSOLIDATION_SCHEDULER=1 to surface contradiction + expiry proposals; live contradictions are shown below in the meantime |
Each surfaced run expands to its surfaced-at time, contradiction count, expiry-proposal count, then one row per contradiction (entity, key, the two polarities, the fact ids) and one per expiry proposal (reason, entity, key, confidence, fact id).
Live contradictions
A read-only live pass that runs regardless of the scheduler, so the screen is useful with the flag off. Each row: entity and key, the reason, the two polarities, the fact ids, and the clashing values.
Consolidation
The form that resolves one. Every field is operator-only.
| Field | Type | Default |
|---|---|---|
| entity | text, mono | empty |
| key | text, mono | empty |
| canonical value | textarea, 3 rows | empty |
| target fact ids | textarea, 3 rows, mono | empty |
| protected fact ids | textarea, 2 rows, mono | empty |
| confidence | text, mono | 0.8 |
| protect floor | text, mono | 0.99 |
| Consolidate facts | danger button | - |
Consolidate facts is SHIPPED and live, and it is destructive. It shows a confirmation naming the entity, the key and the exact count of target facts that will stop resolving before it fires (render.js:754):
Writes a canonical fact for
<entity>·<key>and SUPERSEDES the N listed target fact(s); they stop resolving. Fact-store mutation. Proceed?
Facts above the protect floor are rejected by the daemon.
4.6 Memory › Lane weights (operator only)
Open this to change how retrieval ranks results. The whole page is operator-only; a customer sees a note explaining that forward-facing consoles hide operator deep machinery (pages.js:1414, render.js:2648).
Three cards (pages.js:704).
Scope
| Control | Type | Default | What it does |
|---|---|---|---|
| tenant | select | empty (global) | Global defaults, or a discovered tenant |
| custom tenant | text, mono | empty | A tenant id the select does not list |
| enable RRF fusion | toggle | reflects the live value | Whether reciprocal-rank fusion is on for this scope |
| reason | text | empty | An operator note recorded with the change |
Load lane weights | button | - | Reads the CoreCrux global or tenant boost overlay |
| Apply lane weights | button | - | SHIPPED, live, destructive |
Presets
| Control | Default | What it does |
|---|---|---|
| preset | select, empty | baseline, lexical, dense, graph |
Stage preset | button | Fills the weights form only. Nothing is written |
| Reset lane weights | danger button | SHIPPED, live, destructive |
Weights
Ten non-negative multipliers, seeded from the live overlay when one loads (pages.js:138):
| Lane | Default |
|---|---|
| BM25 lexical | 1 |
| Dense / cosine | 1 |
| Sparse | 1 |
| HyDE | 1 |
| Topology | 0 |
| Vernacular | 0 |
| Indexing | 0 |
| Trait expansion | 0 |
| Navtree | 0 |
| Events | 0 |
Both writes confirm first, and both confirmations name their blast radius (render.js:760):
Writes FUSION_RRF_LANE_WEIGHTS to CoreCrux for
<scope>, changes retrieval ranking for that scope. Proceed?
Clears the lane-weight overlay (global scope), retrieval reverts to CoreCrux defaults for every tenant that inherited it. Proceed?
The reset clears only the lane-weight overlay keys for the scope, not the whole overlay.
4.7 Memory › Global (Professional mode only)
Shared surfaces that outlive a session (pages.js:1065). One live card and three honest notes.
| Card | Status |
|---|---|
| Engrams | Live over GET /v1/engrams. Filterable; each engram expands to kind and summary |
| Bench | STUBBED, the ScoreCrux leaderboard is an external surface; this daemon has no bench endpoint |
| Sites | STUBBED, no hypernym-sites endpoint on this build |
| Fact store | A pointer card: the fact store's home is Memory › Facts |
4.8 Trust › Receipts: the CROWN listing
Open this to answer "is there a record of that, and does it verify".
A live listing over GET /v1/receipts/list, newest first (render.js:12125).
| Control | Default | What it does |
|---|---|---|
| search | empty | Client-side across observation id, principal, kind, session, signer and receipt id. 200 ms debounce |
| kind chips | all | Up to 12, from the daemon's own kind_counts. Single-select |
| Load older | - | Cursor pagination, 50 per page |
A row carries the observation kind (colour-toned), the principal, a session short-id, the timestamp, the signature algorithm and signer short-id, the body hash, the chain sequence, and one of two badges:
| Badge | Means |
|---|---|
CROWN body ✓ | The full body, signature and verification are dereferenceable here |
envelope only | The body lives in the hosted-tier dataplane. This daemon holds the signed envelope and nothing more |
Expanding a fetchable row pulls three endpoints and renders the daemon's verification verdict verbatim, including the raw JSON (render.js:12240). The verdict shows green only when signature_valid is true and error_code is OK.
The console never computes "valid" itself. It is a transport for the daemon's answer.
An envelope-only row explains itself in one paragraph: a CPU-only daemon holds no dataplane pool, so the body is not dereferenceable here.
The help card at the bottom is the honest boundary. It states that offline verification is corecruxctl inspect-receipt <id> or corecruxctl evidence <id> --keyring <path>, which check the Ed25519 signature without the daemon, and names the bundle export route.
4.9 Trust › Gates: the Article 14 approval queue
Open this when an agent has asked for permission. This is the canonical human go/no-go queue (render.js:12313).
Each pending gate is an always-open card showing the work id, a GATED badge, its age, the requested action and target state, the requesting passport, the action id and status, plus a link into the relation graph.
| Control | Posture | What it does |
|---|---|---|
| Approve | Operator only | POST /v1/work/gate/{actionId}/approve, attributed to your bound passport |
| Reject | Operator only | The matching reject route |
Both refuse without a bound passport, with the Article 14 message. On success the card reports the receipt short-id and the list reloads. In customer posture the buttons are replaced by a sentence saying approvals are operator-gated.
The empty state is the documentation
When the queue is clear, the page does not just say "none". It explains what a gate is, how one is created, and what resolving it produces (render.js:12367):
| Row | Content |
|---|---|
| producer | Work-gate policy on a state transition |
| endpoint | GET /v1/work/gate/pending, and the approve/reject pair |
| requested_action | update_state, the only gated action today, plus a target state |
| resolution | A CROWN ad_ga_* receipt attributed to the approving passport |
It then prints the blocker taxonomy, needs_info versus needs_approval, and runs a client-side join over /v1/work listing every blocked item carrying blocker_kind = needs_approval. Those are the items a gate would be owed for. That join is the most useful thing on the page when the queue is empty.
Withhold all
A separate control on the section-model variant of this page. SHIPPED, live, destructive, and it is not a batch route; there is none. It reads the pending list and loops a reject over every one (render.js:774). Its confirmation says so:
Rejects ALL currently-pending gated transitions (keeps every one from proceeding), each attributed to your passport. Bulk action across every pending gate. Proceed?
4.10 Trust › Pending mints (operator only)
Open this when an agent has asked for a passport. It is the same shape as Gates: an operator decision, attributed (pages.js:454).
The Bound approver panel
This is where you bind the passport every gated write is attributed to, and it is the first thing to do on a new browser (render.js:853).
| Control | Default | What it does |
|---|---|---|
| current approver | - | Shows the bound id, or No approver bound, bind one to accept/reject (Art.14) |
| Approver passport | - | A select populated from GET /v1/passports. If the daemon returns none, it degrades to a free-text input and says why |
| Bind | disabled until the list loads | Writes the id to localStorage under crux-console-bound-passport |
| Clear | disabled when unbound | Removes it |
The binding is browser-local, shared by mint decisions and work-gate approvals. It is a client identity selection, never a fabricated value.
A mint request card
| Field | Default | Notes | ||
|---|---|---|---|---|
| reason | - | Read-only, from the request | ||
| requested category | - | Read-only; not supplied when absent | ||
| Category | pre-filled from the request when it is one of personal \ | work \ | public | Required. Accept refuses without it |
| Name (optional) | empty | A display name | ||
| Accept | - | Mints; on success reports the minted category and refreshes | ||
| Reject | - | Rejects and refreshes |
Both refuse without a bound passport: Bind a passport to accept, mint decisions must be attributed (Art. 14).
The card header shows the requester, the request's age in words, and the requesting passport.
When the feature is off
A 404 renders Feature disabled, passport mint requests are not enabled on this daemon. The flag is CORECRUXD_FEATURE_PASSPORT_MINT_REQUESTS, default off (config.rs:961).
4.11 Trust › Passport
Open this to see who the daemon thinks exists. A filterable list over GET /v1/passports (pages.js:253).
Each passport expands to id, name, owner, position, company, category, reputation tier, receipt count and notes, only the fields that are populated.
New passport
A + in the card header reveals the mint form below the list.
| Field | Type | Default | Notes |
|---|---|---|---|
| id | text, mono | empty | Lowercase, digits, - or _ |
| category | select | work | Also personal, public |
| name | text | empty | Display name |
| owner | text | empty | Who owns or manages it |
| position | text | empty | Role or title |
| company | text | empty | Organisation |
| notes | textarea, 2 rows | empty | - |
| Create passport | button | - | SHIPPED, live. POST /v1/passports. No confirmation, additive |
4.12 Trust › Identity: candidate links
Open this to see whether two identities have been proposed as the same principal. The rule is one sentence: inference proposes, consent disposes (render.js:12438).
A candidate never resolves on its own. The principal resolver ignores it until an operator confirms.
The help panel states the whole pipeline in grounded terms:
| Row | Content |
|---|---|
| producer | POST /v1/identity/candidates/propose, the only shipped producer |
| input · bindings | Two distinct passports co-occurring in one tenant and project within the temporal window |
| input · observations | Distinct signing identities co-occurring in one session |
| confirm | POST …/{id}/confirm with the cross-signature proof, minting a resolving cross-signed link |
| reject | POST …/{id}/reject: keeps the audit trail, never resolves |
| revoke | POST /v1/identity/links/{id}/revoke, retires a confirmed link |
| flag | CORECRUXD_IDENTITY_LINKS=1; all /v1/identity/* 404 when off |
Controls
| Control | Posture | What it does |
|---|---|---|
| Seed candidates | Operator only; disabled with a stated reason otherwise | Runs both proposers. Reports created N (examined M) with a per-source breakdown (render.js:12468) |
| Confirm form | Operator only, on a proposed candidate | Six fields: local passport id (pre-filled personal-default), remote fingerprint (pre-filled from the observed subject), remote public key hex, created-at, sig local, sig remote |
| Confirm candidate | - | SHIPPED, live, destructive. Confirms only if the daemon verifies both signatures |
Confirmation warns first:
Creates the resolving identity link for candidate
<id>(local<a>↔ remote<b>), only if both signatures verify server-side. Irreversible resolution. Proceed?
Reject is not a console control. The page says so and gives the exact route.
Candidate rows are colour-toned by status: confirmed ok, rejected critical, proposed trust. A 404 renders a warning naming the flag.
4.13 Trust › Mediation
Open this to find out whether a hosted engine is wired in, and what it would give you. The page branches on exactly three real states (render.js:12578).
| Response | Card | Says |
|---|---|---|
| 404 | CE posture | Engine mediation is not configured. It names CORECRUXD_ENGINE_BASE_URL and its optional API key, lists the three proxied read routes, and states plainly that this daemon holds no engine state; it proxies, it does not run the engine |
| 502 | Configured but unavailable | The base URL is set but the proxied read failed. It notes that the upstream body, headers and API key are never forwarded; this is the terse 502 posture, and tells you to check the URL, the key and engine health |
| 200 | Mediated summary | mediated, engine_reachable, engine_latency_ms, fetched_at_unix_ms, then the proxied summary verbatim |
No dead controls are rendered. The unconfigured state is a card of text, not a form that would do nothing.
4.14 Failure states across these two destinations
| What you see | What it is |
|---|---|
| Facts falls back with a warning banner | Older daemon: no /v1/facts/list. You are seeing a recent window |
A fact's value ends in … with an N ch badge | Truncated in the list. Expand the row for the full text |
| Review says "scheduler off" | CORECRUXD_CONSOLIDATION_SCHEDULER is off. Live contradictions below still work |
Lane weights shows unavailable · <status> | The CoreCrux overlay proxy did not answer |
| A gate approve says "Bind a passport first" | No bound approver. Trust › Pending mints, Bound approver panel |
| Identity is a warning banner | CORECRUXD_IDENTITY_LINKS is off |
Receipts shows only envelope only rows | Expected on a CPU-only daemon. Only local ad_ga_* gate-approval receipts are dereferenceable |
| Mediation shows the CE posture card | No engine base URL configured. This is the default |
Sources
- crates/corecruxd/console/v2/render.js:10588,
renderFactsBrowser - crates/corecruxd/console/v2/render.js:12125,
renderReceiptsBrowser - crates/corecruxd/console/v2/render.js:12313,
renderGatesBoard - crates/corecruxd/console/v2/render.js:12438,
renderIdentityBrowser - crates/corecruxd/console/v2/render.js:12578,
renderMediationPosture - crates/corecruxd/console/v2/render.js:853, the bound-approver control
- crates/corecruxd/console/v2/render.js:959, the mint-request card
- crates/corecruxd/console/v2/pages.js:107, the AMR lane registry
- crates/corecruxd/console/v2/pages.js:138, the ten RRF lane weights
- crates/corecruxd/console/v2/pages.js:1667, the grounded reasons for each still-gated control

