{"_id":"@bombadil/chorus","name":"@bombadil/chorus","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@bombadil/chorus","version":"0.1.0","description":"Memory for agents, built on Rhizomatic — every belief a signed claim.","type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"bin":{"chorus":"dist/cli.js"},"engines":{"node":">=22"},"license":"MIT OR Apache-2.0","author":{"name":"Mykola Bilokonsky"},"scripts":{"build":"tsc -p tsconfig.build.json","prepare":"npm run build","chorus:demo":"tsx src/demo.ts","chorus:mcp":"tsx src/mcp-server.ts","chorus:http":"tsx src/mcp-http.ts","chorus:console":"tsx src/console.ts","chorus:migrate":"tsx src/migrate.ts","demo":"npm run chorus:demo","test":"vitest run","typecheck":"tsc --noEmit","lint":"eslint .","format":"prettier --write .","format:check":"prettier --check .","check":"npm run format:check && npm run lint && npm run typecheck && npm test","preversion":"npm run check","version":"npm run build","postversion":"git push --follow-tags","release:patch":"npm version patch && npm publish","release:minor":"npm version minor && npm publish","release:major":"npm version major && npm publish"},"dependencies":{"@bombadil/rhizomatic":"^0.1.0","graphql":"^16.14.2"},"optionalDependencies":{"better-sqlite3":"^11.10.0"},"devDependencies":{"@eslint/js":"^9.15.0","@types/better-sqlite3":"^7.6.13","@types/node":"^22.0.0","eslint":"^9.15.0","eslint-config-prettier":"^9.1.0","prettier":"^3.3.0","tsx":"^4.19.0","typescript":"^5.7.0","typescript-eslint":"^8.15.0","vitest":"^2.1.0"},"publishConfig":{"access":"public"},"_id":"@bombadil/chorus@0.1.0","gitHead":"1de6bb72a82313bb754fb73330e67f44d639a2bc","_nodeVersion":"22.0.0","_npmVersion":"10.9.8","dist":{"integrity":"sha512-lk+/AUrEVNf7F6IwboDZpBb7w5j+Lfw5uATFY/vYvIbFiHoj4A4ukOHoP+uC+uvQ+BaLTR9Jp5wKSwo0HfW5tw==","shasum":"b32c4a40b6c4c03a403c57046a3336ab095cb73f","tarball":"https://registry.npmjs.org/@bombadil/chorus/-/chorus-0.1.0.tgz","fileCount":130,"unpackedSize":859611,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIDO6zJtlXyY3UnYRt2HkksolUziiKJbKNu7qQJ0S9RX2AiEAgysj9H5Dq9jbD/N2TLNC6dQScTwbICqFDsVwWegIGk0="}]},"_npmUser":{"name":"mykola","email":"mbilokonsky@gmail.com"},"directories":{},"maintainers":[{"name":"mykola","email":"mbilokonsky@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/chorus_0.1.0_1783410639001_0.5257152424453466"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-07T07:50:38.860Z","0.1.0":"2026-07-07T07:50:39.193Z","modified":"2026-07-07T07:50:39.407Z"},"maintainers":[{"name":"mykola","email":"mbilokonsky@gmail.com"}],"description":"Memory for agents, built on Rhizomatic — every belief a signed claim.","author":{"name":"Mykola Bilokonsky"},"license":"MIT OR Apache-2.0","readme":"# Chorus\n\n**Chorus doesn't store what happened. It stores what was believed — by whom, since when, on\nwhat grounds, and what became of that belief next.**\n\nYour agents already act on beliefs. They just can't show them to you. Ask a system today _why_\nit did something and you get a log of what it did; the belief that drove the act — where it\ncame from, how confident it was, what it contradicted, whether anyone had already retracted it\n— evaporated the moment the context window closed. Chorus is what you get when you refuse to\nlet that evaporate: every belief is a **signed claim** with an author and a timestamp;\ndisagreement is **held in superposition** instead of silently overwritten; trust is **your\neditable policy**, not the database's opinion; and every decision is **replayable against\nexactly what was known** when it was made. Memory is the feature. Belief accounting — the\nflight recorder for minds — is the product.\n\nAnd an accounted mind can be _examined_: `chorus vitals` reads a store the way a physician\nreads a chart (how contested? how stale? how much rests on one voice?), `chorus diff` catches\ntwo agents drifting apart before it costs something, `chorus bisect` binary-searches history to\nthe exact instant a belief flipped — and _who flipped it_ — and `chorus examine` puts the\nmeasurements on the record, signed by an examiner you can distrust like anyone else. The\nexaminer also _acts_: `chorus review` replays every standing decision against the present and\nmails the decider when the ground has moved — \"you acted on X; X is now known otherwise\" — and\n`chorus challenge` asks stale beliefs to re-verify before they rot, exploiting the substrate's\nkindest property: in a grow-only store, _re-assertion is re-verification_. `chorus\ncontradictions` finds the disagreements the contested scan can't see — one question wearing two\nvocabularies (`deploy-env` vs `deployment_environment`) with two different answers — and\nproposes them to a judge; proximity proposes, only a signed judgment disposes. And `chorus\nskeptic` houses a resident doubter: where the whole store knows something on one voice's word —\nespecially under a standing decision — it files a signed doubt-claim, stays quiet while the\ndoubt stands, and _withdraws it the moment a second voice corroborates_. Doubt is a claim with\nan author here: tune it, rank it, or fire it. None of them ever nags, and `chorus checkup` reads\nevery dial in one pass — the store's daily physical, exit 1 when anything wants a human. No view\nfrom nowhere, all the way up: the instruments live inside the epistemology they measure.\n\nChorus is the product layer on [`@bombadil/rhizomatic`](https://www.npmjs.com/package/@bombadil/rhizomatic)\n— the portable signed-content-addressed-delta format ([spec + witnesses](https://github.com/bombadil-labs/rhizomatic))\n— providing the agent handle, named/keyed/encryptable stores, the MCP server, GraphQL-on-demand,\ntrust dynamics, the librarian, the instruments, and the web console.\n\n**Status: alpha, unpublished.** The `chorus` CLI is code-complete — `init`, `store\ncreate|ls|show|adopt`, `serve` (stdio + multi-store HTTP, read-only GraphQL mounts including\n`@union`), `console`, direct data ops, the instruments\n(`vitals|diff|bisect|examine|review|challenge|contradictions|skeptic|checkup`),\n`migrate` — with the live-node cutover scripted and rehearsed ([CUTOVER.md](claude_notes/CUTOVER.md)).\nThe front door for humans is staged at [docs/index.html](docs/index.html) and for agents at\n[docs/llms.txt](docs/llms.txt) — a GitHub Pages site ready to serve the moment the repo goes\npublic (that switch is Myk's). Publication to npm is gated on the cutover proving out; until\nthen, install from a checkout\n(`npm install` builds `dist/`; `npm pack` produces the same tarball CI smoke-installs globally\non every push) or run the npm scripts below. See [EPISTEME.md](claude_notes/EPISTEME.md) for the five phases\nahead, [ROADMAP.md](claude_notes/ROADMAP.md) for the burndown, and [CONSTELLATION.md](claude_notes/CONSTELLATION.md) +\n[VISION.md](claude_notes/VISION.md) for the federated horizon.\n\n```\nnpm install\nnpm run chorus:demo     # the whole thesis, one deterministic receipt-printing story\nnpm run chorus:mcp      # the MCP server over stdio (local clients)\nnpm run chorus:http     # the same server over streamable HTTP (remote surfaces, :4821)\nnpm run chorus:console  # the human's web console over the same store (default :4820)\n```\n\n## The console\n\n`chorus:console` serves a zero-dependency local UI over `CHORUS_STORE`: the live briefing\n(preferences, open tasks, **contested facts**, recent session summaries), a topic browser and\nsearch, and a per-entity inspector — every receipt with its author resolved to _which model,\nwhich session_, retracted claims struck through but present, an **as-of time scrubber** that\nre-resolves the entity at any past instant, and a **distrust button** whose edit is signed by\n_your_ persistent key and rehydrates into every future session's lens. The console is the\nhuman seat at the table: it reads the same log the sessions write, live.\n\n## The identity model\n\nOne MCP server process = **one session = one author**. Session keypairs derive from a single\nmaster seed (`blake3(master + \"/session/\" + sessionId)`), so the master holder can re-derive\nand audit any session's key while nobody else can forge one. The human is **one persistent\nauthor** (`speaker: \"user\"`) across every session. Only public keys ever touch the substrate.\n\nA session binds itself to its model name with a signed **identity claim** (`begin-session`):\nauthor → `{model, sessionId, startedAt, purpose}`. The binding is data — exactly as\ntrustworthy as the claims it scopes, auditable like everything else. An author with no\nidentity claim shows up as `\"unknown\"` in receipts: visible, never silently trusted.\n\n**Introductions read as intervals.** The model name is testimony about a span of time, never\na property of the keypair — a serving model can change mid-conversation (a safety-refusal\nfailover, an upgrade) while the process and its keypair continue. Call `begin-session` again\nwhen that happens: each introduction binds from its `startedAt` until the next one, and every\nclaim attributes to the model in effect _at its own timestamp_. Nothing is relabeled\nwholesale, in either direction. `distrustModel` is conservative on purpose: it demotes any\nsession author that _ever_ introduced as that model, because a failed-over session carries\nthat model's testimony too.\n\nWhat this buys, concretely:\n\n- **`explain` answers \"who said this, exactly\"** — not just a key, but _which model, in which\n  session, started when, doing what_.\n- **Retroactive distrust works at session granularity**: \"that Tuesday session was working\n  from a bad premise\" is one `trust {distrust: <its author>}` call. Its testimony demotes\n  everywhere; its history stays queryable.\n- Model-level trust (\"prefer fable-5 sessions over haiku sessions\") is a policy built by\n  expanding identity claims into an author list — judgment over data, planned for the\n  briefing slice.\n\nEnvironment: `CHORUS_MASTER_SEED` (all keys derive from it), `CHORUS_PACK` (store file),\n`CHORUS_SESSION_ID` (optional; default minted per process).\n\n## MCP tools\n\n| Tool            | What it does                                                                                                                                                                                                                 |\n| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `begin-session` | Introduce this session: bind its author to your model + declared intent (purpose, topics, surface, mode). Call first; call again on any mid-session change.                                                                  |\n| `whoami`        | This session's author, the user author, session id, declared model.                                                                                                                                                          |\n| `briefing`      | Top-of-mind, computed fresh **through your declared scope**: preferences (always global), in-scope tasks/topics/**contested facts** (the rest as a count), recent sessions (shared-topic first), standing distrust edits.    |\n| `remember`      | Assert a belief (`speaker: \"user\"` to relay the human's own words under their key). Values may be `{entity}` references — see \"Reference, don't transcribe\".                                                                 |\n| `recall`        | Resolve an entity to one view under the current trust policy. `aliasedVia` crosses dialects; `unified` reads through sameAs; `all` returns every surviving candidate (the read for set-valued attributes).                   |\n| `topics`        | What the store knows about — entities, attributes, claim counts, recency.                                                                                                                                                    |\n| `search`        | Substring search over surviving beliefs (values, attributes, entity ids).                                                                                                                                                    |\n| `same`          | Assert two ids name the same thing — identity as a negatable judgment.                                                                                                                                                       |\n| `retract`       | Append a signed negation. History is never edited.                                                                                                                                                                           |\n| `revise`        | Retract + re-assert in one move, linked by a `revises` pointer (for facts that _changed_).                                                                                                                                   |\n| `recast`        | Re-encode without re-deciding: same meaning, better representation (string → `{entity}` reference; one fat claim → N). Lineage via a `recasts` pointer.                                                                      |\n| `post`          | Send a message to other sessions or the human: correspondence, not knowledge. Address a session, a model, a surface, a topic's sessions, or the user.                                                                        |\n| `inbox`         | Messages addressed to this session, sender receipts resolved, acked mail hidden.                                                                                                                                             |\n| `ack`           | \"Seen and handled\" — a signed per-recipient claim; the message leaves your inbox only.                                                                                                                                       |\n| `end-session`   | Write this session's summary so the next session's briefing starts there.                                                                                                                                                    |\n| `explain`       | Every candidate with receipts: author, session, model, timestamp, negated flag.                                                                                                                                              |\n| `trust`         | Retroactive distrust of an author (a person, a session, a model's bot).                                                                                                                                                      |\n| `as-of`         | The world as it stood at an instant — claims retracted later are visible again.                                                                                                                                              |\n| `gql-prepare`   | Pin the current world and **synthesize a GraphQL schema for it on demand** — types from id-prefixes, reference edges typed by target, set-valued attributes as list fields. The schema is ephemeral; the snapshot frozen.    |\n| `gql-query`     | Query a prepared snapshot. Forward traversal follows reference fields; `backlinks(target, …)` walks **backward** (who points at an entity), role-discriminated, no substring scan. Per-type roots: `<type>(id)` / `<type>s`. |\n| `gql-schema`    | Re-fetch a prepared snapshot's SDL + stats without regenerating it.                                                                                                                                                          |\n| `gql-release`   | Retire a prepared snapshot; `gql-list` shows the ones still live.                                                                                                                                                            |\n\n## GraphQL on demand\n\nPoint-resolution (`recall`), receipts (`explain`), and substring `search` answer most reads,\nbut some questions are graph walks — _\"what characters was I thinking about the last time I\nwatched a movie about individuation?\"_ `gql-prepare` answers them without a maintained schema:\nit **pins a snapshot** of the store and reflects over its surviving deltas to **synthesize a\nGraphQL schema** for that frozen world — a pure function of `(snapshot, policy)`, so nothing\nstatic is ever stored. Reflection reads the value pointer's _kind_, so references become typed\nedges you traverse (never substrings you match), and `plurality:set` declarations become list\nfields. You then run any number of queries against that frozen `(snapshot, policy, schema)`\ntriple until you `gql-release` or regenerate — so a long retrospective walk reads one\nconsistent world even as the live store moves on. Reverse adjacency (`backlinks`) is\nfirst-class on every node and at the root: the inbound index the store already maintains,\nsurfaced. The \"staticness\" of a schema doesn't disappear — it moves down to the pin, where a\nretrospective query wanted a frozen world anyway.\n\n## Reference, don't transcribe\n\nA belief's value should be an **entity reference** whenever it names something the store\ncould hold beliefs about. The string `\"event:eclipse\"` is a spelling; `{entity:\n\"event:eclipse\"}` is the thing spelled. Relations are composed of their relata, not of the\nwords for them — a synchronicity is composed of its events, a project of its tasks, a team of\nits people. Pass the reference and the edge is typed and bidirectional: the belief files at\nthe referent too, `explain` marks it (`reference: true`), and `recall` can follow it. Pass\nthe string and you have transcribed a name into a place where nothing can dereference it.\n\nThe test is one question: _could you ever want to `recall` the value itself?_ If yes, it is\nan entity — reference it. Strings, numbers, and booleans are for terminal content: prose,\nquantities, flags, things with no further inside.\n\nThe same instinct scales up to **atomic modeling**: a rich record is small entities related\nby references — observation entities carrying their own provenance, relation entities holding\n`composed-of` references plus interpretive attributes — never one fat claim with everything\npacked into its value. Fat claims cannot disagree at the attribute level, so they silence the\n`contested` machinery; atomic claims light it up.\n\n## The briefing is a lens\n\nThere is no view from nowhere — that is the substrate's whole thesis — so the briefing is\nnot a global broadcast. `begin-session` takes structured intent: **topics** (entity ids the\nsession is about; a trailing-`:` value like `\"synchronicity:\"` scopes a whole id-prefix\nfamily), **surface** (`claude-code`, `claude-desktop`, …), and **mode** (`work`,\n`conversation`, `research`, …) — all of it claims on the introduction delta, interval-bound\nlike the model name, auditable like everything else. Topics travel as entity _references_\n(real ids) or string _patterns_ (prefixes): you can only reference a thing; a pattern is a\nspelling.\n\nDeclared topics become the briefing's scope: the exact entities, their sameAs equivalence\nclasses, every prefix match, and **one hop along typed references** — declare\n`synchronicity:mirror` and the events its `composed-of` references name fall into scope\nstructurally. In-scope tasks, topics, and contested facts arrive in full; out-of-scope\ncontests compress to `contestedElsewhere`, an honest count — never hidden, never injected.\nDiscoverable beats broadcast. Two boundaries hold regardless of scope: **preferences are\nalways global** (they are about the principal, who is party to every session), and the\n**console stays panoptic** (the unbounded view is the keyholder's seat, not the default).\n\nNo declared topics = the global view, so small stores and fresh users lose nothing.\n\n(Next in this direction, per the standing design note in the store: salience as an _author_ —\ncurator digests as rankable, distrustable claims rather than a hardcoded computation.)\n\n## Messages (ephemeral salience, permanent record)\n\nDogfooding surfaced it immediately: sessions correspond. A chat session leaves a question\nfor a code session; the code session ships a ruling back. Before `post`, that mail rode the\nknowledge graph as task-kind beliefs on a project entity — addressing in prose, no structural\n\"what's addressed to me\", correspondence accreting where knowledge lives.\n\nA message is a signed delta like everything else — attributable, negatable, auditable — but\nit is **correspondence, not knowledge**, so it never enters the knowledge surfaces: no\n`topics`, no `search`, no `recall`, no `contested`. It exists in exactly one place — the\ninbox of whoever it addresses — and leaves that inbox the moment they `ack` it (a signed\nper-recipient claim: handled-ness has provenance; a broadcast acked by one recipient stays\nvisible to the rest; the sender's `retract` withdraws globally). Addressing targets\n**declared identity**: a session id, every session of a model, every session on a surface,\nany session scoped to a topic, or the human — whose inbox is the console, ack button\nincluded. **Author mail** closes the loop on the canonical gesture — one process notices\nsomething another process wrote: `to: {authorOf: <deltaId>}` addresses whoever _signed that_,\nthe exact keypair, resolved at send time. Threads ride a `re` pointer; `about` references\nconcerned entities without filing at them — on a `post` (what this concerns) and on an `ack`\n(what my response touched: a response is often an effect, not a reply).\n\nThe substrate is append-only and that is load-bearing, so \"ephemeral\" means what it can\nhonestly mean: **ephemeral salience over a permanent record**. The bytes stay; the attention\ncost goes to zero.\n\n## Wiring it into Claude Code\n\n```bash\nclaude mcp add chorus \\\n  --env CHORUS_MASTER_SEED=<64 hex chars, keep private> \\\n  --env CHORUS_STORE=~/.chorus/memory.jsonl \\\n  -- npx tsx <this repo>/src/mcp-server.ts\n```\n\nConcurrent sessions are safe: each server process is its own session author; they share the\nappend-only `CHORUS_STORE` log and converge by union (the store is a CRDT — the lock only\nprevents torn writes).\n\nThen teach the model the protocol — drop this in your `CLAUDE.md`:\n\n```markdown\n## Memory (Chorus)\n\n- At conversation start: call chorus `begin-session` {model: <your model id>, purpose: <one\n  line>, topics: [<entity ids this session is about — try `topics`/`search` for existing\n  ids; \"prefix:\" scopes a family>], surface: <claude-code|claude-desktop|…>, mode:\n  <work|conversation|…>}, then `briefing`. Your topics scope the briefing: treat preferences\n  as standing instructions; treat in-scope openTasks and the last shared-topic session's\n  summary as your starting context. If `contested` is non-empty, flag disagreements to the\n  user rather than picking silently; if `contestedElsewhere` is non-zero, mention it only if\n  the user steers there. If your serving model OR your topic changes mid-conversation (a\n  refusal failover, a pivot), call `begin-session` again — claims attribute to the\n  introduction in effect at their timestamp.\n- As durable facts/preferences/tasks emerge, `remember` them (kind matters). Use\n  speaker:\"user\" when relaying something the user themselves said. Three corrections, three\n  verbs: `revise` when the fact CHANGED, `retract` (+ remember) when it was WRONG, `recast`\n  when only the ENCODING improves (the audit trail must never read a re-encoding as a\n  changed mind). Read set-valued attributes (like composed-of) with recall {all: true}.\n- Reference, don't transcribe: when a value names a thing (an event, a person, a work — any\n  id), pass {entity: \"<id>\"} so the edge is typed and followable; strings are for terminal\n  content only. Model rich records atomically — small entities (with their own provenance)\n  related by references, never one fat claim. Fat claims can't disagree, so they starve\n  `contested`.\n- Set-valued attributes (composed-of, involves, …): declare once with remember\n  {about: \"attr:<name>\", attribute: \"plurality\", value: \"set\", kind: \"fact\"} — multi-author\n  divergence on a declared set reads as union (joint building), never contest. Read sets\n  with recall {all: true}.\n- When unsure what something is called, try `topics`/`search` before minting a new entity id;\n  if you find a duplicate id for the same thing, assert `same`.\n- Your briefing carries an `inbox`: messages other sessions addressed to you. `ack` what you\n  handle (with a note saying what you did). To hand off work, ask a question, or leave a\n  ruling for another session, `post` it — addressed to a surface, model, topic, or the user —\n  instead of writing task beliefs on a project entity. Correspondence is mail; knowledge is\n  `remember`.\n- Before ending: `end-session` {summary: what happened + what's still open}.\n```\n\n## Running it remotely (one node, every surface)\n\nThe protocol brain is transport-agnostic; `chorus:http` serves it over **streamable HTTP**\nso every Claude surface can share one store on one always-on machine. One `Mcp-Session-Id`\n= one chorus session = one author — a surface connecting twice is two keypairs, exactly\nlike two local processes.\n\n```bash\n# On the host (generate the token once, keep it private like the seed):\nCHORUS_HTTP_TOKEN=<48 hex chars> CHORUS_MASTER_SEED=... CHORUS_STORE=~/.chorus/memory.jsonl \\\n  npm run chorus:http     # binds 127.0.0.1:4821 — TLS terminates in front\n\n# Reach it from your other machines (tailnet only):\ntailscale serve --bg --set-path /mcp https://+:443 http://127.0.0.1:4821/mcp\nclaude mcp add chorus --transport http https://<host>.<tailnet>.ts.net/mcp/<token>\n\n# Reach it from claude.ai web (requires PUBLIC reachability — Claude connects from\n# Anthropic's servers, not your browser):\ntailscale funnel --bg 4821\n# then add a custom connector: https://<host>.<tailnet>.ts.net/mcp/<token>\n```\n\nAuth, v0: the token is a secret URL path segment, because claude.ai's connector UI offers\nOAuth-or-nothing and cannot send custom headers; clients that can send headers may use\n`Authorization: Bearer <token>` against `/mcp` instead. Treat the URL as a credential.\nReal OAuth (with dynamic client registration) is the planned upgrade if the node ever\nserves anyone but its keyholder. Unknown paths 404 without a body.\n\n## MX: parity with native memory, and past it\n\nNative Claude memory = an always-loaded index + free-text files. The Chorus equivalents:\n\n- **Index → `briefing`**: same role as MEMORY.md, but computed, salience-ranked, and honest —\n  it includes what the record _disagrees about_ (`contested`) instead of silently keeping the\n  last edit.\n- **Write a file → `remember`/`revise`**: same friction, but every write is signed, kinded,\n  and attributable.\n- What native memory cannot do at all: **receipts on every read** (`explain`: which model, in\n  which session, said this), **time travel** (`as-of`), **retroactive session distrust**\n  (standing trust edits rehydrate into every future session's lens), and **append-only\n  revision** (`revise` keeps the old fact queryable forever).\n\n## Skills: ephemeral apps over the store\n\nBecause GraphQL is synthesized on demand, a whole domain app is just conventions + a UI + the\nChorus wiring — no bespoke backend. [skills/](skills/README.md) holds a set of Claude Skills built\nthat way: **chorus-skill-designer** (the meta-skill that reifies the pattern and ships a template),\nplus media-log, decision-journal, and synchronicity-journal as working examples. Each runs through\nClaude or standalone against a Chorus HTTP node; `node skills/build-skills.mjs` packages them into\ninstallable `.skill` zips.\n\n## Naming (why there is no DNS here)\n\nCanonical ids for domain objects are a _judgment problem_, not an infrastructure problem.\nChorus's position, inherited from the substrate:\n\n- **Ids are cheap, local, and namespaced by convention** (`person:mike`, `svc:api`,\n  `topic:rhizomatic`). Minting requires no coordination.\n- **Convergence is asserted, not assigned.** When two sessions mint `person:mike` and\n  `user:mbilokonsky` for the same human, the repair is a _sameAs claim_ — signed, negatable,\n  confidence-scored, exactly like the librarian's vocabulary mappings (SPEC-9). Recall reads\n  through the equivalence closure under YOUR trust policy.\n- **A registrar is just an author.** A \"DNS-like service\" in this architecture is a well-known\n  keypair whose naming claims you choose to rank highly — naming as policy, not as a central\n  service. Two fleets can trust different registrars and still federate; disputes are held in\n  superposition like any other disagreement.\n\n(The sameAs closure and discovery tools are landed — [src/discovery.ts](src/discovery.ts).)\n\n## Status\n\nThe full MX arc is landed — identity (interval introductions), the shared store + pluggable\npersistence ([PERSISTENCE.md](claude_notes/PERSISTENCE.md)), discovery, the briefing, decide/replay, the\nconsole, and store identity + the registry (constellation Phase A) — and the system has\nsurvived first contact with live dogfooding (which produced the reference-over-string\nsurface, the unbounded contested scan, and mid-session model rebinding). The path from here\n— the CLI, the cutover of the live node, the constellation — is [ROADMAP.md](claude_notes/ROADMAP.md).\n","readmeFilename":"README.md","_rev":"1-103e15d50be86bc378dc401eb3ec63a6"}