Knowledge in the head — Design
Status: proposed (2026-10-16). Nothing here is built. It goes with docs/apps.md: that doc says who owns and changes data, this one says where knowledge is kept and what becomes of the memex. It replaces docs/memex.md §2 (architecture), §4.4 (storage) and §6.1–6.5 (Google accounts and sync) as §11 lists; the rest of memex.md (what knowledge is, the pipelines' work, the mail client's behaviour) still holds.
1. The idea
The memex is a database: a knowledge graph with search. Like Postgres, it should store, index and enforce, and leave deciding what the data says to the programs that write it. Two things follow:
- The head keeps the knowledge graph. It's not optional and not a separate daemon: carbon6 always has it, beside the records, decisions and triggers it already keeps.
c6mgoes away. - Everything the memex does becomes an app or a kit. Gmail, Calendar and Contacts sync are apps, like decks (§6). Extraction, OCR, embeddings and face detection are kits on workers (§4). Understanding (summaries, facts, links between items and things) is apps that write claims (apps.md §9).
2. Why the head
The memex was a separate service so it could run where the disk and the GPU are (memex.md §2.1). That's a placement reason, and §3–§5 meet it in other ways. Against it:
- Two stores, one ownership model. Records live in the head and knowledge in the memex, so a write that touches both can't be one transaction, and collections are mirrored into the memex for search.
- Access is decided in the head (os.md §3.8), then enforced again by the memex from a scope the head stamps on each call.
- One more service to enroll, run, upgrade and back up.
With the graph in the head:
- One store for records, items, things, claims and facts, with one change feed for triggers and one transaction across them.
- One access check, where it's already made.
- One service, one backup, one upgrade path for the database.
3. What the head keeps
- Per realm, a knowledge database of its own:
<data_dir>/realms/<realm>/knowledge.db(SQLite, WAL), holding items, parts, things, claims, facts, notes, trails and vectors. home isrealms/home/. Deleting a realm deletes its folder; a large realm doesn't slow the others. - Collections and records move into the same file, so records and the graph share transactions, and records are graph citizens rather than a mirror (os.md §4.1's "where they live" changes).
- The head's own database (
c6h.db) keeps what isn't a realm's knowledge: sessions and their events, workers, connections, settings, decisions, installs. - Search: full text (FTS5) in each realm's file, as today; vectors in the same file with an approximate index (HNSW) built in memory when a realm is first searched, and dropped when it's idle, within a size you set.
- Blobs: see §5.
The c6-memex crate becomes a library linked into c6h: its schema, queries, graph and search move over; its fabric service, enrollment and RPC relay go.
4. The head stores; it never parses or computes
Mail, PDFs, Word files and images come from outside. A parser bug in the head would expose the process that holds master.key. So:
- Parsing runs in kits on workers. HTML to text, PDF and Word extraction, OCR, image and video decoding: sandboxed as kits are (packages.md §4: no network, a read-only root, resource limits). The head receives text, metadata and parts through ingest (§6.4).
- Models run on workers. Embeddings, captions, transcripts and faces: as kit runs, or through model connections from sessions. The head stores the vectors and serves the index.
- What the head still does with content: checks it against the item kind's schema (§7), hashes it, indexes it for full text, and stores it.
A head with no worker can store what's uploaded with its text already extracted, and search it; it can't extract.
5. Blobs live where you choose
Your memex is already 16 GB, mostly mail bodies, photos and videos. The head's machine shouldn't have to hold a photo library.
- A blob has a location:
head:the head's data folder (content-addressed,blobs/ab/cdef…), for mail and uploads, as the memex keeps them now;worker:<name>:<path>: where media already lives (memex.md §4.1), read through that worker when needed;- object storage (S3 and alike) later.
- The head keeps metadata, parts, thumbnails and indexes; the bytes stay where they are.
- A realm can choose where its new blobs go (Settings → System), so a business's mail can live on that business's machine.
- Backup: each realm's
knowledge.db, plus the blobs athead:. Blobs elsewhere are backed up where they live.
6. Mirror apps: Gmail, Calendar and Contacts
They are apps, installed as instances in a realm (apps.md §5), exactly as decks is. What makes them different is the pattern, not their place in carbon6:
- decks is a service: it runs when asked and hands its output over (apps.md §10).
- Gmail is a mirror: it keeps a copy of data whose source of truth is elsewhere. It must be the only writer of that copy, which ownership gives it (apps.md §6): the Gmail instance owns its mail items. Archiving, labelling or sending is an operation of the instance, which writes to Gmail and then updates the copy.
memex.md §6 still describes what they do (full history import, incremental sync, both-way changes, Gmail as the source of truth, spam kept out of agents' context, write-back rules for contacts, conflicts settled field by field). What changes is that they're written as packages on the primitives below, so an IMAP, Outlook, CalDAV or CardDAV app is written the same way, and none of them is special.
6.1 The packages
| Package | Owns | Operations | Triggers |
|---|---|---|---|
gmail | email and attachment items, sent_by / sent_to / cc claims, labels and read state; internal sync_state (history IDs per account) | send, draft, archive, label, mark_read, trash, import (mbox, Maildir, Takeout) | sync every 2 minutes, every 30 seconds while the mail UI is open |
google-calendar | event items and things, attended / invited claims; internal sync tokens | create, update, move, delete (with "this one / following / all"), rsvp | sync on a schedule |
google-contacts | person things it creates, contact fields as claims, groups; internal sync tokens | create, update, write_back (the carbon6 group rule of memex.md §6.5) | sync on a schedule |
- Accounts: one instance per realm, with that realm's accounts in its settings. Personal Gmail in home, a business's Workspace account in that business's realm; nothing crosses unless you grant it.
- Policies of the realm still hold: sending, inviting and writing back ask first by default, as
mail_senddoes today. - Mail is untrusted input (memex.md §6.6), still: agents get it as quoted data, and sessions that process it run with the restricted tool set.
6.2 The primitives they need
The rule (os.md §1): if an app needs code in carbon6, a primitive is missing. These are the missing ones. Each is general; none mentions Google.
- Triggers that run a kit, with no agent. A schedule or event trigger gets the action
kit: run a kit tool of the instance with mapped arguments. No session, no model. Syncing every two minutes must not start an agent. - OAuth providers declared by packages. A package names a provider: authorization URL, token URL, scopes, and the secrets that hold its client ID and secret. The head runs the flow at its redirect address and keeps the refresh token as a secret of the instance's realm. A kit run gets a short-lived access token in its environment, never the refresh token. Today's Google sign-in (memex.md §6.1) becomes one declared provider.
- Network allow-lists for kits.
networkgains a list of hosts (["gmail.googleapis.com", "oauth2.googleapis.com"]), enforced by the worker. packages.md §8 listed this as later; mirror apps need it. - Kit output that becomes owned data. A kit run can return an ingest batch (items, parts, things, claims, record writes) as a file it writes. The head ingests it as the instance that ran the kit, checked like any write of that owner (apps.md §6). The kit gets no token for the head, so the sandbox stays closed. Extraction kits (§4) feed the graph the same way.
- Kit operations. Beside write and template operations (apps.md §7), an operation can run a kit tool: send, archive, RSVP, edit a contact. It runs at once, returns its result, and its output is ingested as in 4.
- Shared item kinds.
email,attachment,event,contact,photo,documentand the rest are defined once, in root's vocabulary (apps.md §9.4), each with a schema and a data card. Gmail, Outlook and IMAP produce the sameemail, so readers never care which app it came from. - View kinds for rich data. The mail client, the calendar and the photo library can't be made from tables and boards, so they become view kinds (os.md §4.5):
messages,calendarandgallery, each rendering items of a shared kind, from whichever owner. An app binds one to its items and its operations: the mail view's Archive button calls the owning instance'sarchive. The UI code stays in carbon6, but it isn't Gmail's code.
6.3 Events
New mail, a changed event or a new contact is an item or record event (os.md §4.3), so mail rules, triage and meeting preparation are triggers in the realm, as os.md §12.3 already planned.
6.4 Ingest
memex.ingest (memex.md §4.5) becomes the head's ingest: the same batches typed by kind, written as the caller. A client with a realm token writes as import:<kind> into that realm, as today; an instance writes as itself. Parsing moves out (§4): a batch carries extracted text and parts, or names a blob for an extraction kit to read.
7. Understanding as apps
The memex's understanding steps (summaries, topics, commitments, captions, linking items to things, merging people) become system packages, installed in each realm that wants them:
- They write claims they own (apps.md §9): a
mentionsedge, asame_asbetween two people, a fact with its evidence. A wrong one is corrected by your own claim, which reader policies rank first; nobody edits another owner's claims. - They start from events through triggers, and their prompts are their package's skills, editable by forking, not strings in code.
- The review queue (merge suggestions, low-confidence links, unnamed face clusters) is decisions, as os.md §4.2 planned; answering one asserts your claim.
8. Your memex, moved
An upgrade moves an existing memex into the head, all or nothing, after a backup:
- Per realm, the memex's database (
~/Library/Application Support/c6m/memex, and eachrealms/<id>/) becomesrealms/<realm>/knowledge.dbunder the head's data folder. Items keep their ids. - Blobs stay where they are and are referenced in place: the content-addressed store becomes the realm's
head:blobs by location, and media keeps itsworker:locations. Nothing is copied that doesn't need to be. - The graph: entities become things; links become claims, their
made_bybecoming the owner (you, or the system package that replaces the pipeline that made them, at its first version); evidence becomes derived-from links. - Collections in the head's database move into each realm's knowledge file; the memex's record mirror is dropped.
- Mail, calendar and contacts: a
gmail,google-calendarandgoogle-contactsinstance is installed in home with your accounts, and takes ownership of what was synced, with its sync state (history IDs, sync tokens), so nothing is fetched again. Your OAuth client and tokens move to the declared provider unchanged. - Then
c6mis stopped and removed: its Homebrew service, systemd unit, enrollment and worker row. The upgrade says when it's safe to delete its state folder; it never deletes it itself. - Checks compare counts and samples between the old and new stores, per realm, before the switch.
9. Build order
- Knowledge in the head: the
c6-memexstore as a library inc6h, per-realm knowledge files, collections moved in, search and vectors served by the head, the memex API answered by the head. - Never parse: extraction, OCR and embeddings as kits on workers; ingest carrying parts; blob locations.
- Kit primitives: kit trigger actions, kit operations, kit output as owned data, network allow-lists.
- OAuth providers declared by packages.
- Shared item kinds in root's vocabulary, and the
messages,calendarandgalleryview kinds. - The Gmail, Calendar and Contacts packages, and understanding as system packages.
- Moving an existing memex (§8) and removing
c6m.
Steps 1–2 depend on apps.md's ownership (its step 1); 6 depends on its instances and operations.
10. Decisions
| Question | Decision | Why |
|---|---|---|
| Where knowledge lives | In the head, always; one knowledge file per realm | One store, one access check, one service; the graph isn't optional |
| Parsing and models | On workers, in sandboxed kits; never in the head | Untrusted content stays away from the process that holds the master key |
| Blobs | Where you choose: the head, a worker, later object storage | The head's machine needn't hold a photo library |
| Collections | In the realm's knowledge file, beside the graph | Records and knowledge share transactions; no mirror |
| Gmail, Calendar, Contacts | Apps on general primitives, one instance per realm | Nothing special; other providers are written the same way |
| What the memex's programs become | Kits (parsing, models) and system packages (sync, understanding) | Storage is the kernel; everything else is replaceable |
11. What this replaces
- memex.md §2 (architecture), §2.1 (a separate service), §2.4 (what the memex may do on the head): the head is the store; there's no fabric service to authorize.
- memex.md §2.3 (scopes by labels): realms and instances' approved reads (apps.md §5.2).
- memex.md §4.4 (storage): §3 and §5 here.
- memex.md §6.1–6.5 (Google accounts, mail, calendar and contacts sync): the packages of §6, on the primitives of §6.2. What they do is unchanged.
- os.md §4.1 "where they live": collections move from
c6h.dbinto each realm's knowledge file. - The
c6mbinary, its packages (Homebrew, .deb) andmake dev-memex.
12. Open questions
- Long-running kits. Polling every 30 seconds starts a container each time. Is that fine at personal scale, or do mirror apps need a kit that stays running between runs?
- A head with no worker. Should a head ship a minimal extraction kit it can run itself, sandboxed, so uploads of plain text and Markdown work with no worker at all?
- Vectors at scale. Millions of vectors per realm fit in memory on one machine; whether the index should live on disk (an on-disk ANN index) before that becomes a problem.