// Product · In daily use, still being built
My AI Workspace
A shared memory, a task ledger and a morning job that checks its own work, so every AI tool I use starts from the same context.

- My role
- Designed, built and run it; personal project
- Type
- Product
- Status
- In daily use; still being built
- Supabase
- Postgres
- pgvector
- MCP
- Linear
- Claude Code
- Codex
- Gemini
- Ollama Cloud
- OpenRouter
Overview
I built this workspace for my own work. It has three parts and a rule about who is in charge of what. A vault of plain markdown files holds the evidence: decisions, deliverables, receipts. A memory database holds what we know about all of it and answers questions by meaning, not just keywords. Linear holds what is open and what is done. Several AI tools reach the same memory through one interface, so switching from one to another does not mean explaining the background again.
The rule is that each part has one job. Files are the source of truth for what a project is. The memory answers "what do we know". Linear alone decides what is open. When memory and Linear disagree, Linear wins. The AI tools do the work and keep no private memories of their own.
Why I built it
Useful information gets scattered across conversations, files and task lists. Every new AI chat started from zero, and the thing I needed was usually in a file I had already written or a decision I had already made. I wanted one memory that every tool could read, and a task list that did not depend on me remembering it.
The second reason came later. Once agents started doing routine work for me, I needed to trust what they said they had done. So the system is built around verification: write the real artifact first, then the memory that points at it; read back every write by its ID; keep a ledger so a repeated run adds nothing; write a receipt for every run. A good part of this workspace exists to keep the other part honest.
A good part of this workspace exists to keep the other part honest.
How it's built
The memory is a Postgres database on Supabase with pgvector for semantic search, exposed to the AI tools over an MCP endpoint. Through that one interface a tool can search by meaning or by keyword, ask for a brief on a person or a project, walk the graph of related entries, or save a new memory. An extraction worker turns new memories into entities and relationships; it runs as an edge function and uses an open model on Ollama Cloud. Embeddings come from OpenRouter.
The clients are the tools I already use: Claude Code, Codex, Gemini and Grok, plus Ollama for local and cloud open models. Each one reaches the same memory through the same interface, and each keeps only its own preferences locally. Linear is the task ledger. Nothing in the memory can change a task; nothing in Linear is treated as knowledge.
The design was inspired by Nate B. Jones's public "Open Brain" pattern. The system itself is mine: the vault, the one-job-per-part rule, the verification loop, the daily job and everything that keeps it running.
An earlier layer, a compiled wiki view of the memory, was part of the first design and has been retired.
How it runs each morning
The scheduled part is a daily job that keeps the memory current and reconciles it with mail, files and Linear. It runs every morning on Codex, follows a written procedure, and does these steps in order:
What it never does on its own: send or reply to mail, touch a calendar, delete, archive, merge or deduplicate anything, create schedules, or change providers or credentials. Anything that needs a judgment call about who someone is gets posted as a question for me.
A normal morning, in plain terms: the job reads the overnight mail from two mailboxes, recognises that most of it is already handled, already tracked, cancelled, or noise, and is left with a handful of real candidates. One becomes a new task, one updates an existing task, a couple become memories that point back to the source. The receipt lists every write, and a second pass makes none. That is what success looks like; it is deliberately boring.
Step 1 of 7
File inboxes
Find every inbox folder, look only at new or changed files, file originals with a hash check, never overwrite. Protected files stay closed.
Step 2 of 7
Read mail
Personal and work mailboxes, from a saved cursor with a day of overlap. Only hashed message IDs are stored, never bodies.
Step 3 of 7
Reconcile
Each item is checked against memory and Linear: handled, cancelled, superseded, waiting, noise or uncertain. Only confirmed facts are saved. A task is created or updated only if it is genuinely missing.
Step 4 of 7
Protect every write
A pending entry goes in a ledger before the write, the result is read back by ID, and a repeat pass has to produce zero extra writes.
Step 5 of 7
Extract
The worker turns new memories into entities and relationships, within fixed limits. A failure stays marked incomplete; nothing is retried on its own.
Step 6 of 7
Receipt
Every run ends with a receipt, and cursors move forward only after the read-back checks pass.
Step 7 of 7
Log the misses
Failures and defects go to a Linear issue, not under the rug.
Step 1 of 7
File inboxes
Find every inbox folder, look only at new or changed files, file originals with a hash check, never overwrite. Protected files stay closed.
Step 2 of 7
Read mail
Personal and work mailboxes, from a saved cursor with a day of overlap. Only hashed message IDs are stored, never bodies.
Step 3 of 7
Reconcile
Each item is checked against memory and Linear: handled, cancelled, superseded, waiting, noise or uncertain. Only confirmed facts are saved. A task is created or updated only if it is genuinely missing.
Step 4 of 7
Protect every write
A pending entry goes in a ledger before the write, the result is read back by ID, and a repeat pass has to produce zero extra writes.
Step 5 of 7
Extract
The worker turns new memories into entities and relationships, within fixed limits. A failure stays marked incomplete; nothing is retried on its own.
Step 6 of 7
Receipt
Every run ends with a receipt, and cursors move forward only after the read-back checks pass.
Step 7 of 7
Log the misses
Failures and defects go to a Linear issue, not under the rug.
Tools
- Supabase (Postgres, pgvector, edge functions): the memory and the extraction worker.
- MCP: the one interface every tool uses to reach the memory.
- Linear: tasks, status and the action ledger.
- Claude Code, Codex, Gemini, Grok: the AI tools doing the work.
- Ollama Cloud: the open model behind memory extraction, and other open-model routes.
- OpenRouter: embeddings.
- Codex automations: the scheduler for the daily and weekly passes.
Where it stands
In daily use. The job runs every morning on its own and every run leaves a receipt, and the receipts are honest when something is missing: one of them records a skipped backup and a missing worker total rather than reconstructing them. The memory holds 20,000+ memories and 34,000+ entities with the links between them, with records going back two years; roughly half of the memories are imported notes and call transcripts. It runs on my own machine, so it runs only when that machine is on.
Still open: duplicate memories from older imports; a search that sometimes returns more results than asked; contradiction flags that are not reliable yet; a security review of the database access that is tracked and not finished. Model routing across providers exists as separate tools and is switched off inside the daily job until I turn a specific lane back on. I do not claim time saved; nothing here is measured that way.
What went wrong, and what changed:
- A silent false success. Truncated or empty model replies were being counted as completed extractions. I reproduced it with a synthetic test, fixed the worker, and re-verified the affected records.
- Too many gates. Two days of added approvals, length rules and expiry checks turned a finished batch into a pile of "incomplete" files. An independent audit found the rules had been invented by the agents. I froze the harness and cut them. Less is more.
- A stalled queue. Items sat waiting for two weeks because nothing invoked the worker after I removed model work from routine runs. Now it is scheduled.
- Search is not proof of absence. A new issue was missed by keyword search and found by its ID, which is why every write is read back by ID.
- 20,000+memories
- 34,000+entities