Interactive exploration needs JavaScript. The complete drawing and every structure's description are shown below.
- CAPTURE
- The write path. Everything that ever enters the brain comes through here, whichever surface it arrived on. Its job is to decide whether this is worth keeping at all, whether it already exists, whether it contradicts something already stored, and how much it matters, before a single row is written.
- captureEntry() runs the sequence: sample the content for a duplicate check, embed it, compare against the nearest existing memories, then either block, merge, flag a contradiction, or continue. Classification (importance 1–5, canonical or not, episodic or semantic) is a model call that is deliberately NOT awaited on the request path: scheduleClassifyAndTag hands it to waitUntil so the caller gets its id back immediately. storeEntry then chunks, embeds each chunk, writes the entry row, and infers graph edges on the way out. share.ts moves an entry between a personal and a company workspace, a share is a move rather than a copy, and every one of these files threads an Identity and a workspace scope through so a write lands where the caller is actually allowed to put it.
- TEXT
- Cuts a memory into pieces small enough to embed, pulls hashtags out of the prose, tokenises a query into searchable terms, and reads dates out of phrases like "last Tuesday" so a question can carry a time filter it never stated.
- chunkText slices at CHUNK_MAX_CHARS with CHUNK_OVERLAP_CHARS of overlap, but backs the cut up to the last sentence break or newline if one falls in the second half of the window, so chunks end at a full stop rather than mid-word. tokenize.ts strips a stopword list and a minimum token length; temporal.ts parses time phrases and hands back a cleaned query with the phrase removed, so the words that became a date filter do not also get embedded.
- MODEL CALLS
- The one place the Worker talks to Workers AI, and, since v3 Team Edition, the identity, workspace-scoping and team-administration layer underneath everything else here. Embeddings for storing and searching, and streamed text for classification, contradiction checks, merges, digests, recall synthesis and insight reasoning; in the same directory, who a caller is, which workspace a write lands in, and how a company's roster is managed.
- ai.ts's readStreamText consumes a Server-Sent Events stream and pulls the answer out of two different response shapes: Llama-family models put text on `response`, OpenAI-lineage models put it under `choices[0].delta.content`. Reasoning models in that family emit chain-of-thought first as `delta.reasoning`, which is deliberately discarded: every caller treats the return value as the answer and JSON.parses it. identity.ts resolves a caller's role, personal workspace and every company workspace they belong to from a token; tenancy.ts bootstraps the company workspace and owner identity on any database, old or new, memoized per isolate; scope.ts is the one place workspace scoping is spelled out, enforced by a cross-user isolation test suite rather than lint; team-admin.ts owns membership, roster and offboarding; audit.ts and admin-audit.ts write insert-only event trails.
- DATABASE
- Creates and repairs the schema at runtime. Every request calls it before doing anything else, so a brain deployed a year ago gains new tables, columns and indexes the first time it is touched by a newer Worker.
- ensureDbReady runs init once per isolate and memoizes the promise in src/runtime. It creates ten tables and their indexes with IF NOT EXISTS: the original entries, edges and insight_candidates, plus workspaces, users, memberships and maintenance_cursor for v3 Team Edition, prompt_capsule_revisions for Prompt Capsules, and entry_events / admin_events as insert-only audit trails. It adds the columns that arrived after the original schema with ALTERs that tolerate already existing. db/schema.sql and this file must agree: the SQL file is what a fresh install runs, this is what an old one gets.
- GRAPH
- The connections between memories. Some are drawn explicitly with the link tool; most are inferred at write time by looking at what the new memory is nearest to. Recall can then walk those edges to reach context a plain search would never have matched.
- Eight edge types (relates_to, supersedes, caused_by, decided, about_person, part_of_project, follows, drawn_from), each with a direction flag and an optional restriction on which memory kinds it may join. drawn_from is the newest: the weekly insight pass draws it from a proposal back to the memories it was reasoned from, so an insight always carries its own sourcing. Validation lives in application code rather than a SQL CHECK, and per-edge extras go in a JSON metadata column, so the table has never needed an ALTER. Traversal is capped three ways: depth 3, fanout 8 per node, and 50 nodes total.
- RECALL
- The read path, and the most consequential code here. A question comes in as ordinary language and has to come back as the few memories that actually answer it, trimmed to fit inside somebody's context window.
- Two searches run in parallel against the same query: a dense vector query, and a keyword arm. Their results are fused with reciprocal rank fusion at k=60, then re-ranked by time decay, then thinned with MMR at λ=0.7 so near-identical results do not fill the answer. Decay has three floors by volatility: durable facts barely age, volatile ones fall away fast. If the best dense score comes back below the widening threshold the vector query is re-run wider, on the theory that a weak top match means the first window was too narrow.
- MCP SERVER
- How an AI client reaches the brain. Fourteen tools that Claude, ChatGPT, Cursor and Codex call directly: list_teams, remember, append, update, set_status, share, get_prompt_capsule, recall, list_recent, get, forget, link, unlink, connections.
- An McpServer whose tools are registered with Zod schemas and mounted at /mcp behind the OAuth provider. sanitize.ts scrubs what goes back out. The handler resolves config once at entry and threads it down rather than letting each layer re-read KV. share and get_prompt_capsule are v3 additions: share moves an entry between a personal and company workspace, get_prompt_capsule hands back the same reusable prompt prefix the HTTP prompt-capsule endpoints serve.
- HTTP ROUTES
- The REST surface: everything the dashboard, the CLI, the browser extension and the desktop app use. Capture, recall, entries, graph, integrations, admin, brief, config, migration and OAuth revocation.
- No router library. An ordered array of handler functions, each returning a Response or null to pass; the first non-null wins, and falling off the end is a 404. Every handler matches on exact pathname plus method. OAuth authorize is checked before the database is touched, so the login page renders even if D1 is unreachable.
- OAUTH
- Lets an AI client authorize itself through a browser instead of being handed the token. The client registers itself, a hosted page asks for the auth token once, and the resulting grant is what the client stores.
- Cloudflare's workers-oauth-provider with dynamic client registration, wrapping the whole Worker. Registration requests are intercepted and augmented before they reach the provider. A static bearer token is still accepted through resolveExternalToken, for clients that cannot open a browser.
- CONFIG
- The tuning layer. Twenty-nine numbers, model names and team settings that change how the brain remembers and recalls, editable from the dashboard without a redeploy.
- DEFAULTS is the shipped behavior, pinned `as const` so a typo is a type error. KV holds a sparse override blob containing only the keys actually changed, so a retuned default in a later release still reaches anyone who never overrode it, and resetting one key is a delete rather than a rewrite. Every key has a range rule enforced at resolve time, not only at write; values also arrive from hand-edited KV and from blobs written by older releases.
- TAGS
- The vocabulary. Keeps the tags across a brain converging on the same words instead of accumulating near-synonyms, and holds the reserved namespaces the system writes about a memory as opposed to tags describing what it is about.
- vocabulary.ts remembers which tags have been used and steers new writes toward them; system.ts owns the reserved prefixes and the replacement rules. Reserved-tag matching is case-insensitive throughout, and the set is derived from the prefixes themselves so the SQL, the guards and the test doubles agree by construction rather than by three copies staying in step.
- PROMPT CAPSULES
- A reusable prompt prefix built from your own canonical memories, so an AI client can open a conversation already knowing who you are instead of re-asking every time. One core capsule (identity, preferences, constraints, principles) and, per project, a project capsule (current state, decisions, open questions).
- Only entries tagged status:canonical inside a reserved capsule namespace fill a slot; drafts and deprecated rows are silently skipped, and a malformed or duplicate slot is reported rather than guessed around. serialize.ts renders a byte-stable JSON prefix with sections in a fixed order and normalized line endings, capped at 12,000 characters. build.ts checks a per-workspace D1 revision counter first (entry triggers advance it on every capsule-tagged write), then normally serves the immutable payload straight from KV, so a read costs one indexed D1 row plus a cache hit rather than a full reselect. Served over GET/HEAD at /prompt-capsules/core and /prompt-capsules/projects/:id with a strong ETag, and over MCP as get_prompt_capsule.
- MEMORY STATE
- What the system believes about a memory rather than what the memory says: whether it is current or superseded, how likely it is to stop being true, whether it is a fact or an event, and whether search can see it at all.
- Four small namespaced vocabularies stored as reserved tags on the entry (status:, volatility:, kind:, stale:as-of), each with a validated enum and a reader that tolerates junk. getVolatility returns the first *valid* verdict rather than the first tag in the namespace, because stopping at the first match and rejecting it let a junk tag shadow a real one.
- RUNTIME
- Two small runtime concerns: making sure the schema check happens once per isolate, and, since v3 Team Edition, rotating which workspace the nightly maintenance passes process next.
- state.ts keeps a module-scoped ready flag, set once per isolate by ensureDbReady and handed to waitUntil so a failed init does not surface as an unhandled rejection. rotation.ts advances a single D1-backed cursor lexicographically through every workspace, so one nightly invocation processes one workspace's slice rather than the whole corpus; full coverage cycles every K nights for K workspaces, and a read failure returns null so callers fall back to scanning everything, exactly as before v3.
- INDEX HEALTH
- Notices when the vector index is missing or broken, and lets the rest of the system keep working keyword-only instead of failing writes. Since v3 Team Edition, also scopes every query to the workspaces a caller may see.
- health.ts keeps a grace window (default five minutes, set by VECTORIZE_GRACE_MS) after which a failing index is treated as genuinely absent rather than briefly unavailable; /health reports the state and the dashboard raises a banner carrying the exact wrangler command to fix it. scope.ts adds a per-isolate workspace filter to every Vectorize query; if the index ever rejects that filter it is remembered as unsupported for the rest of the isolate's life, queries fall back to unfiltered, and the first caller able to report it writes a durable KV marker so the signal outlives the isolate that discovered it.
- ENTRY POINT
- The Worker itself. 141 lines that wire the OAuth provider around everything and route the five cron schedules to the right jobs.
- fetch() intercepts OAuth registration, then hands everything to the provider. scheduled() branches on the cron string: integration sync, insight accrual, personal weekly insight and team weekly insight each return early, and anything unrecognized falls through to nightly maintenance. The team pass additionally checks the TEAM_INSIGHTS config flag and the company workspace list before doing anything, so an opted-out or teamless brain spends one KV read and stops. Maintenance itself now resolves one workspace slice per night so compression, the graph pass and staleness move through the whole deployment together. Each job is wrapped so one failing cannot take the others down.
- CONSTANTS
- The numbers that are not user-tunable, and the reasoning for each one. More comment than code.
- Thresholds, token ceilings, batch sizes and the stopword list. Several carry a worked derivation rather than a value: the insight model choice is justified against Cloudflare's published neuron pricing, arriving at roughly 7% more cost for a model with about seven times the parameters, then converted into a percentage of the daily free allocation.
- ENV
- Eleven lines naming the four bindings and the one secret. The smallest structure on the map.
- A single TypeScript interface. The generated worker-configuration.d.ts does the actual typing work; this is what application code imports.
- COMPRESSION
- Rolls up old, low-value memories on one topic into a single digest, so a brain that has been running for years does not drown recall in things nobody has looked at since.
- Eligibility is deliberately more protective than the importance filter it replaced: it can only ever exempt more. A memory is safe if it is important, if recall has proven it useful at least twice, if it is under sixty days old, or if it survived a contradiction. Reserved tags are never candidates.
- STALENESS
- Decides how likely each memory is to have stopped being true, so that a birthday and this week's priority do not age at the same rate.
- A regex heuristic over three bands. Durable: birthdays, birthplaces, names, nationality. State: works at, lives in, plans to, role at. Volatile: meetings, appointments, deadlines. The verdict is written as a reserved tag and read by recall's decay floors.
- INSIGHT
- Reads two of your own memories written at least a month apart and says what changed between them, what they conflict on, or what connects them. At most three a week, and often none.
- Split across two schedules because it is two budgets. Nightly accrual does the searching and leaves scored pairs in a table; the weekly pass does no searching at all and spends its whole allowance on reasoning over ten candidates. Scoring requires cosine ≥ 0.80 (below that they are not about the same thing) and a gap of at least thirty days, below which it is one thought written twice rather than a position that moved. Pairs are normalized so (a,b) and (b,a) cannot both be stored and paid for.
- INTEGRATIONS
- Where memories arrive from without anybody typing them: a Notion workspace, three kinds of calendar, and two mailboxes. Read-only, all of them.
- A provider framework: each provider exports a descriptor and is registered in one map, which the routes, the cron and the dashboard all read from. Calendars are plain iCal links parsed with ical.js, so there is no OAuth app to register. Mail is IMAP with an app password, parsed with postal-mime, filtered so newsletters, marketing and receipts never become memories. mirror.ts syncs one provider per run.
- IMPORT / EXPORT
- Getting a whole brain out as JSON and back in again: for backup, for moving between Cloudflare accounts, and for restoring after a mistake.
- Import is paged and idempotent: each call handles a slice of array positions and returns the next offset, so the same file resent never duplicates anything. Entries come first, then edges, then embeddings are backfilled separately; the last step spends the daily AI allowance, so it only runs when asked.
- RE-EMBED
- Changing the embedding model means every vector in the index is now in a different space. This rebuilds them without touching a single memory.
- Budgeted in chunks rather than entries, because storeEntry fires one model call per chunk concurrently: 25 single-chunk entries is already about 75 binding calls, and a handful of long memories in one batch would be far more. A second cap on entries per batch stops a page of tiny memories ballooning either. Resumable if the daily allowance runs out, and reversible until the final step.
- DASHBOARD
- The web interface: a home screen showing what the brain has been doing, memories as a list or a graph, search, settings, integrations, team administration, and the insight review queue.
- Twenty-six plain ES modules, no framework and no build step, served as Worker assets. The graph is hand-drawn on canvas. i18n.js is the largest single file: the dashboard speaks English and Italian. team.js is the second-largest, added for v3 Team Edition's roster and workspace controls.
- DESKTOP APP
- What most people actually use. A Tauri app that creates the Cloudflare resources in your own account, deploys the Worker, sets a password, and connects your AI clients: about two minutes, no terminal.
- TypeScript front end over a Rust core. It talks to Cloudflare only to create resources inside your account; afterwards it only ever talks to your own Worker. Mac builds are signed and notarized by Apple; Windows builds are signed through SignPath, with every signing request manually approved.
- D1
- SQLite at the edge. Three tables: entries, edges, insight_candidates.
- Bound as DB. Free plan: 50 queries per invocation, 5 million rows read per day. Both limits shape code in at least four directories.
- VECTORIZE
- The vector index. 384 dimensions, cosine similarity, one vector per chunk rather than per memory.
- Bound as VECTORIZE. Rejects more than 20 ids per getByIds call, a limit discovered rather than documented.
- WORKERS AI
- Embeddings and text generation, billed in neurons against a daily free allocation.
- Bound as AI. Three models in use: bge-small-en-v1.5 for embeddings, a Llama model for general calls, and a larger reasoning model for insight only.
- OAUTH_KV
- Key-value storage for OAuth clients and tokens, config overrides, and integration credentials.
- Bound as OAUTH_KV. Four unrelated kinds of data share it, separated by key prefix.
- TEST SUITE
- What stops the thresholds above from drifting. Unit tests over the scoring and pipeline code, and DOM tests over the dashboard modules.
- Vitest. A D1 mock with a fidelity test of its own: a test whose job is to check that the mock lies in the same ways the real thing does. Several tests exist purely to fail when two things drift apart: cron strings against wrangler.jsonc, config defaults against their rules.