ARPIA Docs

Cerebro

Persistent institutional memory, exposed over MCP.

Updated October 26, 2026

1. What Cerebro is#

Cerebro is a knowledge layer that both people and AI agents read from and write to. It stores organizational knowledge — decisions, rules, procedures, product behavior, customer specifics, past resolutions — as retrievable memories, each with attribution and traceability.

1.1 The problem it solves#

Every new conversation with an agent starts from zero. Someone has to re-explain which customer this is, what was decided last quarter, why the workaround exists, which rule forbids the obvious approach. That re-explaining is expensive, it's inconsistent between people, and it silently fails when the person who knew is unavailable.

Cerebro moves that context out of individual heads and chat logs into a queryable store. An agent that calls Cerebro first arrives already informed. An agent that doesn't is guessing — confidently, and in a house style that makes the guess hard to spot.

Concretely. Someone discovers that deleting from the Data Sources panel is a hard delete, not a detach. They save it once, into arpia_product, as Product Knowledge. Six weeks later a different person asks a different agent "what happens if I drop a data source?" — and the answer comes back correct, with a link to the memory and the doc it came from. Nobody re-derived it. Nobody had to remember who knew.

1.2 Mental model#

init is the map · load and search are the query · save writes · update corrects · config is the structure.

Two design principles govern the whole API:

Organizational, not personal. Cerebro holds knowledge the organization needs, not user configuration. "We markup LLM pricing at cost × 1.30" belongs in Cerebro. "I prefer bullet points" does not.

Discovery before action. init returns the map — which domains exist, which knowledge types are valid, which org-wide rules are in force. Every other call depends on that map. Init without Load is just discovery; Load without Init is guessing.

1.3 What Cerebro is not#

Not Why it matters
A document store It holds distilled knowledge, not files. Link to the document via references[]; don't paste it into content
A search engine General knowledge doesn't belong here. "How do I parse JSON in Python" is not a Cerebro question
A chat log Nothing is captured automatically. Every write is a deliberate, explicitly requested act
A preferences store Explicitly out of scope, by design
Editable indefinitely A memory is editable for 15 days, then frozen (§3.3). Write carefully the first time

1.4 How to read this document#

It draws on two sources of truth, and they disagree in places:

  1. The MCP tool descriptions and API schemas — authoritative for the contract: fields, formats, windows, rejections. Sections 3–8.
  2. Observed behavior in live sessions — authoritative for defects. Section 9 is entirely empirical and appears in no schema. An agent reading only the tool descriptions will not know any of it.

Where the two conflict, this document states both and marks the resolution as pending. It does not average them.


2. Quick start#

The shortest useful path, three calls:

// 1. Get the map. Once per conversation, before anything else.
{ "action": "initalize" }

// 2. See what already exists in a scope, without pulling content.
{ "mode": "list", "domain": ["arpia_product", "arpia_docs"] }

// 3. Ask a specific question and get a sourced answer.
{ "query": "what is the difference between a Repository and a Data Source?",
  "domain": ["arpia_product", "arpia_docs"] }

Four rules that prevent most errors:

  1. Init first. Without it, you don't know which domains or types are valid, and org-wide rules never load.
  2. Never infer intent to write. save and update run only when the user explicitly asks.
  3. Never guess a domain, type, or mid. If it isn't in loaded context, look it up or ask.
  4. Never pass exactly one domain. A single-element array silently excludes global, so the immutable rules don't fire (§9.3). Pass two or more, or omit domain entirely.

One thing to know up front: all six tools declare additionalProperties: true with no enumerated schema properties. Validation is server-side only — malformed payloads fail at runtime, not at the MCP layer. There is no safety net.


3. Core concepts#

3.1 Hierarchy#

Organization
   └── Domain (arpia_product, arpia_ciso, global, ...)
          └── Memory (mid_xxxxxx)
                 ├── knowledge_type_id  (Procedure, Immutable Rule, ...)
                 ├── parent_mid          (causal antecedent)
                 ├── references[]        (external URLs with a role)
                 ├── expires_at          (optional expiration)
                 └── status              (APPROVED | INACTIVE)

mid format is not documented. Schema examples show both 6 and 8 hexadecimal characters (mid_1df233, mid_a1b2c3d4). Do not infer a fixed length, and never construct a mid — copy it verbatim from an Init, Load, or Search result.

3.2 Object reference#

Object What it is Critical consideration
Organization Multi-tenant isolation boundary No memory crosses organizations. Returned as organization_id / organization_name
Domain Grouping and permission scope Every save and retrieval is bound to a domain. Has a domain_slug (lowercase, underscores) and a human domain_name — not interchangeable across actions (§4.6)
Memory (mid) Atomic unit of knowledge Editable for 15 days from creation, then frozen
knowledge_type_id Semantic classification Valid set is per-organization, from Init's available_types. Do not invent values
parent_mid Causal link to an antecedent Only the primary, canonical antecedent — never "related to." Memories form a tree
references[] External links: { url, title, role } Powers attribution in Search. Replaced wholesale on update, never merged
expires_at Auto-expiration, YYYY-MM-DD HH:MM:SS The only automatic hygiene mechanism
status APPROVED or INACTIVE Case-insensitive input, normalized to uppercase. No other value accepted. INACTIVE retires a memory
Scope (access) read_only or read_write Per user, per domain. Grantable but not revocable (§4.6)

3.3 Memory lifecycle#

   save
    │
    ▼
 APPROVED ──── editable window: 15 days ────► FROZEN
    │            (title, content, domain,        │
    │             type, references,              │  no further edits
    │             expires_at, parent_mid,        │
    │             status)                       │
    │                                           │
    ├──► expires_at reached ──► auto-expired    │
    │                                           │
    └──► status: INACTIVE ──► retired ◄─────────┘ (see Gap 7)

The window is the single most consequential fact in this document. After 15 days a memory cannot be corrected. The documented recovery — retire it and write a replacement — may itself be blocked by the freeze; see Gap 7 in §12. Plan on writes being permanent.

Practical consequences:

  • Set expires_at at creation for anything provisional. Adding it later is only possible inside the window.
  • Run a mode:"list" check before saving. A duplicate you catch today is an edit; a duplicate you catch in a month is permanent.
  • Draft in the conversation, get confirmation, then save. There is no cheap undo.

3.4 Knowledge types#

The authoritative list is available_types from cerebro_init. The table below is a convenience reference and may lag — if Init disagrees, Init wins.

Type Intended use Example
Immutable Rule Non-negotiable organizational rule Prohibition of npm install without safeguards
Business Rule Business rule, may change Markup formula for LLM model pricing
Procedure Repeatable sequence of steps Committee Minutes (Actas) generation flow
Customer Knowledge Customer-specific context ELCONIX configuration particularities
Product Knowledge Product behavior Repository vs. Data Source distinction
Fact Verified, stable data point Oria = Ontology Reasoning Interactive Agent
Tip Practical learning Operational shortcut discovered in the field
Todo Item Pending work Open [CONFIRMAR] fields in an Acta

Type is not cosmetic — it determines how a memory is prioritized during retrieval.


4. The six tools#

4.1 cerebro_init — discovery#

When: once per conversation, before any Load, Search, Save, or Update.

Invocation posture — the schema and ARPIA policy disagree.

Posture Behavior Authority
Context-triggered Init fires automatically when the first message names a customer/project/product/team, implies scoped work ("I'm working on…"), or asks about organizational knowledge The tool description. The documented default
Explicit-invocation-only No Cerebro tool fires — including Init — until the user asks ("check Cerebro," "load the context") ARPIA operating policy for interactive agent sessions, overriding the above

Policy is stricter than the schema, so following policy never violates the contract. Under explicit-invocation-only, an agent that needs Cerebro should say so and wait. Rules 2–4 in §2 hold under both.

Do not call: Init already ran this conversation; the question is general knowledge; the conversation won't touch institutional knowledge.

{ "action": "initalize" }
Warning

The literal value is initalize — missing the second i. The correctly spelled initialize is not documented as supported. Do not "fix" it.

Response fields

Field Meaning
user Authenticated user's email
organization_id Tenant identifier
organization_name Human-readable org name
available_types Knowledge types this user may save
domain Domains this user can save to and retrieve from (field is singular)
last_saved_memories Most recent memories — useful for inferring active work
global_immutable_knowledge Org-wide rules spanning all domains

How to use it: validate every requested scope against domain and every type against available_types. If the user names something absent from either, ask — don't guess. Use last_saved_memories to infer intent when a query is broad.

Presentation: never dump the Init response to the user unless asked. It is a silent planning input.


4.2 cerebro_load — broad context#

Retrieves a context package for a scope. Broad by nature. Requires prior Init.

When: the user opens work on a known scope — "working on ProjectX today," "continue the ERP migration," "load context for Customer A."

Don't call: that scope is already in the conversation; the user asked one specific question (→ Search); the requested scope matches no domain from Init (→ ask).

Four modes. Every domain array below carries two or more entries. This is the §9.3 mitigation, not a style choice — the schema's own examples use single-element arrays and would trigger the defect. Copy these shapes.

// Mode 1 — semantic retrieval within a scope (default)
{ "query": "natural language question or topic",
  "domain": ["arpia_ciso", "arpia_compliance"] }

// Mode 2 — specific memory by ID
{ "mid": "mid_1df233" }

// Mode 3 — latest activity in a scope, no specific query
{ "domain": ["arpia_docs", "arpia_product"] }

// Mode 4 — inventory: metadata only, no content
{ "mode": "list", "domain": ["arpia_docs", "arpia_product"] }

If the work genuinely concerns one domain, pad the array with a second relevant domain, or omit domain and filter the results. Never pass a one-element array.

mode:"list" is the most underused and most valuable mode. Use it for discovery and onboarding, duplicate detection before any save, and as the safe default when Load-vs-Search is ambiguous. Given that writes are effectively permanent (§3.3), the cost of skipping it is asymmetric.

After the call: do not dump results verbatim. Use them to inform the response. The user wants a working agent, not a memory dump.


4.3 cerebro_search — specific answer#

Returns a synthesized answer plus structured attribution: the contributing memories and their external references. Narrow by nature.

When: a specific question institutional knowledge could answer — decisions, rules, processes, standards, past resolutions. Also when a prior Load didn't cover it, or the conversation moved outside the loaded scope.

Don't call: the answer is already in the conversation; the question is general knowledge; the user wants a broad scope load (→ Load) or wants to write (→ Save).

// Scoped (two or more domains — see §9.3)
{ "query": "natural language question", "domain": ["arpia_compliance", "arpia_ciso"] }

// Across all accessible domains, global rules included
{ "query": "natural language question" }

Query construction: build it intentionally — include the system names, components, and domain terms the user mentioned.

Presentation (critical): present the synthesized answer and its attribution block as-is. Do not paraphrase, summarize, or strip the contributing memories or external references — that structure is what makes the answer auditable, and it is the only defense against the failure mode in §9.1. This is the one place Cerebro requires verbatim pass-through to the user; Init and Load require the opposite.

If empty: say Cerebro has no knowledge on the topic yet, and offer to save what the conversation uncovers. Do not fill the gap with general knowledge.


4.4 cerebro_save — create only#

Creates only. Never edits. Every call makes a new memory. A payload containing a mid is rejected, with a pointer to cerebro_update.

Reactive only. Called when the user explicitly says "save," "remember," "store," "persist," or equivalent. Never infer the intent.

Field Required Notes
title Yes Infer from context
knowledge_type_id Yes From Init's available_types
content Yes The knowledge body
domain Yes A single domain string — unlike Load/Search, which take arrays
parent_mid No Links the new memory as a child of an existing one
references No Array of { url, title, role }
expires_at No "YYYY-MM-DD HH:MM:SS"
// Minimum
{ "title": "Memory title", "knowledge_type_id": "Procedure",
  "content": "Content...", "domain": "arpia_ciso" }

// With causal antecedent and references
{ "title": "Q2 follow-up on auth refresh design",
  "knowledge_type_id": "Tip",
  "content": "Continuation of the original auth refresh notes...",
  "domain": "arpia_product",
  "parent_mid": "mid_a1b2c3d4",
  "references": [
    { "url": "https://docs.arpia.ai/...", "title": "Original doc", "role": "context" }
  ] }

// With expiration
{ "title": "Temporary access note", "knowledge_type_id": "Tip",
  "content": "Vendor VPN credentials valid for the Q4 audit only.",
  "domain": "arpia_ciso", "expires_at": "2026-12-31 00:00:00" }

API asymmetry — intentional, do not "correct" it. save takes domain as a single string; load and search take an array. A memory is written to exactly one domain. The two-domain rule in §9.3 applies to retrieval only.

Multi-domain knowledge: if it fits several domains, issue several saves. There is no multi-domain write.

Do not save when:

  • The user didn't ask.
  • Nothing identifiable was decided or discovered → ask what to persist.
  • It's a personal preference — Cerebro is organizational.
  • A near-duplicate may exist → run load mode:"list" first. If a match exists, that's an edit → cerebro_update.

Content fidelity (hard rule): if a draft was shown to the user before saving, content and title must be character-identical to what was displayed. Not a re-summary, paraphrase, or shortened version.

Continuations are new saves. An addition to an existing memory is a new save, optionally linked via parent_mid. Reach for update only to change the existing record itself.

After the call: confirm in natural language. Surface the returned mid only if a follow-up needs it.

Choosing a parent_mid

Link only the primary, canonical antecedent:

New memory Parent
DONE / PROGRESS / SHIPPED the original TODO
Bug-fix documentation the bug or the delivered feature
Postmortem the incident memory
Replacement / refinement the design it supersedes
Correction the corrected memory
Next step the previous step

Omit when the relationship is loose ("related to," "same topic") or when several parents would apply — reference it textually in the body instead.

The parent must exist, be in the same organization, with no self-references. When in doubt, omit — it can be attached later via update, inside the 15-day window.


4.5 cerebro_update — correct in place#

Edits a record in place. Never creates.

Requires a mid. If you don't have one, don't guess — find it via Search or Load, confirm with the user it's the right record, then update.

Reactive only. Called when the user explicitly asks to change, fix, correct, relink, re-domain, expire, or deactivate an existing memory. Use save instead when the user wants to record something new, even if it continues an existing memory.

Editable fields: title, content, domain, knowledge_type_id, references, expires_at, parent_mid, status. At least one must be present or the call is rejected.

Partial updates: send only what changes; omitted fields are untouched.

// Content only — most common
{ "mid": "mid_a1b2c3d4", "content": "Corrected content goes here." }

// Several fields at once
{ "mid": "mid_a1b2c3d4", "title": "Updated title",
  "content": "Updated content.", "knowledge_type_id": "Tip" }

// Move domain — needs read_write on the TARGET
{ "mid": "mid_a1b2c3d4", "domain": "arpia_product" }

// Set an expiration
{ "mid": "mid_a1b2c3d4", "expires_at": "2026-12-31 00:00:00" }

// Clear an expiration — empty string, NOT null
{ "mid": "mid_a1b2c3d4", "expires_at": "" }

// Attach or relink a parent
{ "mid": "mid_a1b2c3d4", "parent_mid": "mid_1df233" }

// Detach parent, memory becomes a root — empty string, NOT null
{ "mid": "mid_a1b2c3d4", "parent_mid": "" }

// Replace the references list — full replace; [] is rejected
{ "mid": "mid_a1b2c3d4",
  "references": [ { "url": "https://docs.arpia.ai/...",
                    "title": "Original doc", "role": "context" } ] }

// Retire a memory
{ "mid": "mid_a1b2c3d4", "status": "INACTIVE" }
Semantics that bite
  • Clearing vs. changing. For expires_at and parent_mid, "" is an explicit clear; omitting leaves as-is. Use the empty string, not JSON null.
  • References are replaced, not merged. Sending references overwrites the entire list — to add one, resend the existing ones too. An empty array [] is rejected, so references cannot be cleared this way.
  • Editing window: 15 days from creation, no exceptions. Including parent_mid does not waive it. Past the window the record is frozen. On that failure, do not retry.
  • Moving domains requires read_write on the target domain, else rejection.
  • status accepts only APPROVED or INACTIVE.

Response fields: updated_fields reports what actually changed. references_saved, embedding_status, and parent_mid report "unchanged" when not part of the edit.

Correcting a memory past the 15-day window

The documented path: mark the record status: "INACTIVE", then carry the correction forward with a new save, parent_mid-linked to the retired record.

Warning

Unresolved contradiction — verify before relying on this. The same source states that past 15 days the record is frozen, and that the recovery is an update setting status: "INACTIVE" on that frozen record. Both cannot be true unless status is exempt from the window, which is not documented. See Gap 7 in §12. Until a live test resolves it, assume retirement may fail.

Fallback requiring no update call:

  1. Write a new memory with the correct content.
  2. Set parent_mid to the memory being corrected — the "Correction" case in §4.4.
  3. State the supersession explicitly in the body: "Supersedes mid_xxxxxx, which stated X incorrectly."
  4. Log the bad mid for an administrator to retire out-of-band.

Step 3 is what prevents a future reader from acting on the stale record. It is not optional.

Invocability status

cerebro_update is declared in the MCP tool surface with the full contract above. However, a session verified Aug 14, 2026 exposed only five invocable tools — init, config, load, search, save — with update absent. Either the surface changed since, or that verification was session-specific.

Declared and invocable are not the same thing. Confirm with one live call before designing a workflow that depends on update. Tracked as Gap 1 in §12.


4.6 cerebro_config — domain structure#

Creates domains, renames them, grants a user access.

When: the user wants to create or rename a domain, grant access, or references a domain that doesn't appear in their Init response.

Don't call: the domain already exists in Init (just use it); the user asks about domain contents (→ Load/Search); the user asks what domains exist (→ Init).

// Create a domain
{ "action": "create_domain", "domain_slug": "elconix", "domain_name": "ELCONIX" }

// Grant a user access — "domain" here is the NAME, not the slug
{ "action": "add_user_domain", "domain": "ELCONIX",
  "user": "target_username", "scope": "read_only | read_write" }

The schema's comment for the first action reads "Crate a Domain" — a typo in the source, not a distinct action.

Inference rules

  • domain_slug: lowercase, underscores, no spaces or special characters. "ELCONIX customer stuff" → elconix; "backend team knowledge" → backend_team.
  • domain_name: infer from context; ask only if genuinely ambiguous.
  • add_user_domain matches by name, not slug. The most common config error — passing the slug targets nothing. The caller must already hold read_write on that domain; if not, the call fails. Report the lack of permission; do not retry. Ask for scope if unspecified.
  • Rename: confirm the existing domain appears in Init first; if not, ask before calling.

Rename is documented but not specified. The tool description references an existing_domain field, but no rename payload appears in the schema. Do not construct one by analogy — confirm the exact shape first. Tracked as Gap 8 in §12.

Grants only — no revocation. There is no action to revoke access or change an existing scope (read_only → read_write). Direct the user to an administrator; do not attempt a workaround. Treat every grant as permanent when deciding who to add.

CRITICAL — after every successful call, re-call cerebro_init. A new or renamed domain, or a newly granted access, will not appear in Load or Save until the session context refreshes. Config without an Init refresh = stale domain map. This is the only sanctioned second Init in a conversation. Under explicit-invocation-only posture (§4.1), tell the user the re-init is required and get the go-ahead.

After the call: confirm in natural language ("Domain 'elconix' is now available"). Don't expose the raw response. On rename, remind the user that prior saves or external tools referencing the old slug need updating.


5. Choosing the right tool#

First relevant message
        │
        ▼
   cerebro_init ───────────────────────────── once per conversation
        │
        ├─ "I'm starting on X" / broad scope ──────────► load (Mode 1 or 3)
        ├─ "what's the rule for Y?" / one question ────► search
        ├─ "what exists in this domain?" /
        │   duplicate check before saving ─────────────► load (mode:"list")
        ├─ "save / remember this" ─────────────────────► save
        │     └─ continues an existing memory? ────────► save + parent_mid
        ├─ "fix / correct / retire that record" ───────► update (needs mid)
        └─ "create a domain" / "give Jane access" ─────► config ──► re-run init
Signal in the message Tool
"I'm starting on X" / "load the context for Y" Load (Mode 1 or 3)
"what's the rule for X?" / "what did we decide about Y?" Search
"what's in domain Z?" / duplicate check Load mode:"list"
"save / remember this" Save
"save this, it continues the earlier note" Save + parent_mid
"fix / correct / retire that record" Update (needs mid)
"create a domain" / "give Jane access" Config → then re-run Init
It's already in the conversation Neither — don't re-query
It's general, not organizational, knowledge Neither — Cerebro is not Google

Load vs. Search, in one line: Load answers "give me everything for this scope"; Search answers "answer this question."

Save vs. Update, in one line: Save creates — including follow-ups and continuations; Update changes an existing record in place.


6. Canonical workflows#

A. Scoped work session

  1. cerebro_init
  2. Validate the user's scope against domain
  3. cerebro_load — Mode 1, ≥2 domains + query
  4. Work; cerebro_search for anything outside the loaded scope
  5. On explicit request, cerebro_save

B. Safe save into an unfamiliar domain

  1. cerebro_init
  2. cerebro_load with mode:"list" on the target scope (≥2 domains)
  3. Duplicate found? → cerebro_update. None? → cerebro_save
  4. Confirm in natural language

C. Correcting an existing memory

  1. cerebro_search or cerebro_load to obtain the mid
  2. Confirm with the user it's the right record
  3. Within 15 days of creation? → cerebro_update. Done.
  4. Past 15 days? → the edit is rejected. Do not retry.
  5. Attempt cerebro_update with status: "INACTIVE" — may also be rejected; see Gap 7
  6. cerebro_save a new memory carrying the correction, parent_mid-linked to the old record, supersession stated in the body

D. New domain

  1. cerebro_config → create_domain
  2. cerebro_init again — mandatory refresh
  3. cerebro_save into the now-visible domain

7. Rules for agents#

Rule Applies to
Call Init once, first; never twice except after a successful Config Init
Never guess a domain, type, or mid — ask the user All
Don't re-query knowledge already in the conversation Load, Search
Never dump raw Init or Load output to the user Init, Load
Do present Search's answer and attribution block verbatim Search
Save and Update are reactive only — never infer intent Save, Update
Displayed draft text must be sent character-identical Save, Update
Cerebro is organizational; personal preferences don't belong Save
Never pass exactly one domain Load, Search
Re-run Init after any successful Config Config

8. Failure modes#

Condition Behavior Correct response
mid present in a save payload Rejected Reroute to update
update without a mid Rejected Find the record first via Search/Load
update with no editable field Rejected Include at least one editable field
Memory older than 15 days Edit rejected, record frozen Don't retry — attempt INACTIVE (Gap 7) + new Save
status other than APPROVED/INACTIVE Rejected Use one of the two
references: [] on update Rejected References can't be cleared this way
null instead of "" to clear a field Not the documented clear Use the empty string
Domain move without read_write on target Rejected Tell the user; don't work around it
add_user_domain without caller read_write Fails Report lack of permission; don't retry
add_user_domain given a slug instead of a name Targets nothing Pass the domain name
Revoke access / change existing scope No such action Refer to an administrator
Search returns nothing Empty result Say Cerebro has no knowledge yet; offer to save what emerges
Requested domain not in Init N/A Ask the user, or config to create it
Malformed payload of any kind Runtime error, not schema rejection additionalProperties: true — no MCP-layer validation

9. Known defects#

Everything in this section is empirical. None of it appears in the schema documentation.

9.1 The confidence trap#

The most consequential finding from the Oria evaluations, August 2026: models learn institutional structure accurately and then fabricate specific details — CVE IDs, metrics, dates — without flagging that they are extrapolating.

The risk isn't that the model doesn't know. It's that it sounds exactly as confident when it knows as when it invents. In an executive decision-making context, that is worse than having no memory at all: unaided, a reader discounts an unsourced claim. Wrapped in institutional structure, the same claim reads as retrieved fact.

Mitigation:

  • Verify every numeric value or identifier against the source memory — load by mid.
  • Prefer search over load when attribution matters; only search returns the contributing-memories block.
  • Treat any response without an attribution block as unverified.
  • This applies to this document. An earlier revision asserted that mid values are always 8 hex characters — an inference from a single example, stated as fact, inside the section warning against exactly that. Where a figure here carries no source or verification date, treat it as unverified.

9.2 Empty memories and phantom duplicates#

Memories marked [HIDDEN — EMPTY] or [HIDDEN — DRAFT DUPLICATE] remain retrievable by search. Structure present, substance absent — this feeds §9.1 directly. Editing the title does not remove them from the retrieval index.

Mitigation, assuming update is invocable: within 15 days, correct the content or set expires_at. Past 15 days, attempt status: "INACTIVE" — subject to Gap 7.

Open question: it is not documented whether INACTIVE removes a memory from the retrieval index or merely flags it. If it only flags, retirement doesn't solve this and the phantom stays searchable. Tracked as Gap 9.

Prevention beats all of the above: set expires_at at creation for anything provisional, and run load mode:"list" before every save.

9.3 Domain-scoping defect#

Confirmed: when exactly one domain is passed, the global domain is silently excluded — meaning the organization-wide immutable rules are not applied, in what is otherwise the most natural way to call the API.

Mitigation until fixed: always pass ≥2 domains, or omit domain entirely. Every example in §4 follows that shape. Note that the schema documentation's own examples use single-element arrays — following them literally reproduces the defect.

9.4 Fact inversion in the synthesis layer#

cerebro_search has produced fact inversions — asserting the opposite of what the source memory says — in its synthesis layer. This is why the attribution block matters: it is not decorative, it is the verification mechanism. Trimming it for brevity removes the only signal that would catch an inversion.


10. ARPIA domain map#

As of Aug 14, 2026 — not re-verified since. Confirm against cerebro_init before relying on it.

Domain Users Purpose
global (all) Organizational immutable rules
personal individual User's own space
arpia_oria 6 Oria agent — evaluations, defects, design
arpia_core_support 5 Core platform support
arpia_git 3 Repository and versioning practices
arpia_product 3 Product knowledge
guia_de_cerebro 2 Cerebro usage documentation
csf_risk_governance_outcomes 2 NIST CSF 2.0, KEV, risk outcomes
arpia_ciso 1 Security governance
arpia_compliance 1 ISO 27001 / 42001, SOC 2
arpia_docs 1 Platform documentation
arpia_feature_updates 1 Product changes
test 2 Testing
new_action_test 2 Testing

10.1 Governance observation#

Four high-value domains have a single user (arpia_ciso, arpia_compliance, arpia_docs, arpia_feature_updates). Cerebro's stated purpose is institutional memory; a domain with a single reader is personal memory carrying infrastructure overhead.

This is a bus-factor risk in the most sensitive domains. arpia_compliance in particular should have a second reader — certification knowledge is exactly what an auditor asks for when the person who loaded it is unavailable.

Explicit trade-off: widening access to arpia_ciso exposes unremediated findings to more people. The mitigation isn't to close the domain, it's to split it — open findings in a restricted domain, control and process knowledge in a shared one.

Compounding factor: because access can be granted but never revoked (§4.6), the split must happen before the second reader is added. Adding a reader to arpia_ciso as it stands is a one-way door.


11. Global immutable rules in force#

Loaded automatically on every Init. They apply across all domains regardless of working scope — provided the call did not pass exactly one domain (§9.3).

11.1 Backup handling — mid_3d734797#

Every backup goes to .backups/ at the project root, chmod 700 on the directory and 600 on files, with .backups/ in .gitignore. Never file.php.bak next to the original. Backup lookups are performed first and only in .backups/.

11.2 npm install prohibition — mid_26ee9c33#

npm install / npm i / npm update / npm ci without flags are prohibited. Hierarchy of alternatives: pnpm (--ignore-scripts) → yarn berry (enableScripts:false) → bun (--ignore-scripts) → npm ci --ignore-scripts only as a last resort. Context: the TeamPCP campaign / "Mini Shai-Hulud" worm, March–May 2026, including the first documented attack carrying valid SLSA Build L3 attestations.

Implication for agents: if asked to run a prohibited command, reject the command as formulated, cite the rule, and propose the alternative appropriate to the lockfile present.


12. Open gaps#

# Gap Impact Status
1 update declared in schema but absent from the Aug 14 verified session Whether any memory is correctable from the agent is currently unknown Needs one live call
2 No domain access revocation Access can only be granted, never removed; every grant is a one-way door Open — requires admin
3 Scoping excludes global with exactly 1 domain Immutable rules not applied. Schema examples reproduce the defect Confirmed
4 Fact inversion in search synthesis Executive decision risk Confirmed
5 Empty memories retrievable Feeds detail fabrication. Fixable within 15 days if Gap 1 resolves favorably Open
6 Bus factor in single-user domains Compliance/CISO continuity — blocked behind Gap 2, since the domain split must precede any new grant Not addressed
7 15-day freeze vs. INACTIVE recovery contradiction The documented recovery from an expired edit window is itself an update on a frozen record. If retirement fails, expired-window memories are permanently uncorrectable and permanently searchable Needs one live test
8 Rename references an existing_domain field with no documented payload Renames cannot be performed safely; slug drift accumulates Open
9 Unknown whether INACTIVE removes a memory from retrieval If it only flags, retirement does not remediate Gap 5 Needs one live test
10 No MCP-layer schema validation (additionalProperties: true) All malformed payloads fail at runtime; no early rejection By design — behave accordingly

↑↓ to move↵ to openEsc to close