I have abandoned at least six note systems. None of them died because the notes were bad. They died because writing a note cost more than the moment was worth. By the time I had opened the app, picked a folder and thought about a title, the thought was gone.
So this time I built for the opposite constraint. Capture costs a few seconds of talking. Everything expensive happens after I have stopped paying attention.
Capture Has to Cost Nothing
There are three ways into my system.
A Shortcut in Control Center. I swipe down, tap once, talk, tap again to stop. The Shortcut posts the audio to a webhook. This is the one I use ten times a day: a to-do I remembered on a walk, an event someone just proposed on a call, a half-formed idea about a product.
A share-sheet Shortcut on top of Voice Memos. For anything longer, I record with the native app, then share the file into a second Shortcut that hits the same endpoint. That covers real meetings, and the recaps I dictate to myself walking away from a call.
A dedicated Gmail address. I forward mail to it and it gets processed. A conference acceptance, a booking confirmation, a client deciding something in a thread. Forwarding is one tap and I was already in the mail app.
That is the entire input surface. Nothing to open, nothing to name, no decision about where anything goes. Killing that last decision is what the rest of the system is for.
One Sentence Is Enough
Most personal knowledge bases are write-only. You pour things in and one day, in theory, you will search them. Mine works the other way round. It is written for a machine to read, and it gets read on every single capture, before anything is written.
I made a version of this argument about business data a while back. This is the same idea pointed at my own life.
Say I record one sentence: “book dinner with my partner Thursday at eight.” The calendar event that appears has her actual email address on the invite. I never said her name.
That works because the wiki has a page listing the people I deal with, and the router reads it live on every capture:
| Person | Relation | Aliases (incl. Czech cases) | Email |
|---|---|---|---|
| Jana Nováková | Partner | Jana, Jany, Janě, Janu, Janou, Janča | jana@example.com |
| Petr Svoboda | Android dev, Atlas | Petr, Petra, Petrovi, Petrem, Svoboda | (not on file) |
The alias column exists because Czech declines names heavily. One person is “s Janou”, “Janě”, or “Janu” depending on the sentence, and a transcript hands over whichever one I actually said. Without those forms the name resolves to nobody. When the system misroutes someone, the fix is almost always a new alias rather than a prompt change.
Context Beats Audio Quality
The bigger payoff is in meetings. Transcription gives me diarized speakers, so I get “Speaker A” and “Speaker B” instead of names. The wiki has a page for the project those people work on: the team, their roles, who reports to whom, the stack, the current goals. That page is what turns Speaker B back into a person with a job. Action items come out attributed to whoever actually owes them.
Transcription errors fix themselves the same way. Audio mangles technical terms constantly, especially across languages. When the project page says what the team actually builds with, a mangled framework name gets corrected on the way in. Without that page you get a clean transcript of the wrong words. That is worse than a messy one, because it looks correct.
None of this needs to be clever. It is plain markdown in a git repo:
index.md the map, read first
CLAUDE.md operating rules for any agent touching this
log.md append-only record of what changed and when
about/ who I am, how I work
projects/ one page per active project
reference/
people.md names, roles, aliases, the disambiguation table
projects.md the full catalog
The conventions are aimed at that machine reader rather than at me. Everything is third person. Volatile claims are dated inline, so a later session can tell what is still safe to trust. A new fact rewrites the stale sentence instead of landing as a correction underneath it. It reads a little oddly to a human. That is deliberate: this is an LLM wiki, not a notebook that happens to be written in markdown.
There is a loop in all this that I did not see coming when I started.
Every capture makes the wiki denser. A denser wiki means the next capture can be lazier, because fewer words carry more meaning. The more I use it, the more useful it gets. Note-taking normally runs the other direction: the more you have, the more there is to maintain.
What Actually Runs
n8n receives the capture, saves the file, and sends it to AssemblyAI for transcription with speaker labels. Then it calls a small local HTTP service that does the routing and the work.
I ran Whisper locally first, and it is genuinely good, but it cannot tell you who spoke. Speaker labels are the whole reason meeting recaps work at all, so that one feature is worth paying for.
Three decisions in there are worth stealing.
n8n stays a straight line. Receive, save, transcribe, route, execute, send, confirm. Every branch, every filter, every retry guard lives in a Python service in git instead of on the canvas. A canvas is hard to diff, hard to review, and hard to test. I wanted the confidence threshold and the replay logic somewhere I could read them in a pull request.
Where the credential lives decides who acts. The local service works out what calendar events to create and hands them back. n8n creates them, because the Google OAuth token is n8n’s. Same for sending mail. The service never holds a credential it does not need.
Two model sizes for two different jobs. Routing is classification: a transcript and the people page go in, structured JSON comes out against a fixed schema. That runs on a small model with no tools at all, because the entity context is passed in the prompt rather than read off disk.
"type": {
"enum": ["reminder", "calendar", "wiki", "note"]
},
"confidence": {
"description": "0..1. Below 0.6 the action is archived and reported instead of executed."
}
Updating the wiki from a meeting recap is a different job. That one runs as a Claude Code agent on a bigger model, with real file and git access, because for that task reading the repo is the work. It pulls, finds the right page, updates facts in place rather than appending corrections underneath stale ones, appends a line to the change log, then commits and pushes.
The prompts are mostly rules about restraint, not about output format:
Resolve `attendees` to email addresses **only** from the digest. If someone is
named but has no address there, put their name in `notes` and leave `attendees`
empty. **Never guess or construct an email address.**
If a name is ambiguous between two known people, pick neither: lower
`confidence` below 0.6 and say so in `notes`.
Every capture ends with a message on my phone telling me what happened: what got created, what was skipped for low confidence, and what could not be resolved. That last part matters most. An automation that quietly decides not to act is indistinguishable from one that is broken, and you find out weeks later when you go looking for something that was never there.
What Lands in My Inbox
I never tell it that a recording was a meeting. The router works that out on its own, and when it does, the wiki update becomes only half the job. A second agent writes a report and emails it to me: what the meeting was and what changed, what got decided and why, action items grouped by owner, and the questions nobody answered. If the recap does not say who owes something, the report says unassigned instead of picking someone.
The order matters more than it looks. The update runs first, so by the time the report agent starts, it can read the commit that was just made and the project page behind it. That is what separates a report from a summary of what I said into my phone. In one run it turned a bare first name into the right person, because the people page listed more than one candidate. In the same run it flagged that a date I had given contradicted the project page.
The email and the Slack version are rendered in code, not by a second model call, so the two can never disagree about what was decided. And the prompt is strict about length: every line has to be something I can take in at a glance, not a paragraph I have to parse.
The Part I Don’t Let It Decide
The model writes freely. It just does not get to decide anything that leaves the machine. Calendar invites built from forwarded mail have their attendee list stripped in code, not forbidden in the prompt, because a prompt can be argued with by the very text it is reading, and an invite sent to a client cannot be taken back. Meeting reports reach a shared channel based on which wiki files the commit actually touched, never on the topic labels the model gave itself. Anything under the confidence threshold gets archived and reported to me instead of performed. And a spoken venue only becomes a map pin if the lookup can verify it against what I said. A missing pin is recoverable. A wrong address is the one you drive to.
It Runs on Hardware I Own
An old MacBook sits in a cupboard with the lid closed, always on. It runs the automation, the local service, and a self-hosted Forgejo git server. All three of my devices sit on a Tailscale mesh, so my phone reaches that machine from anywhere as if the two were on the same home network, and nothing is published to the internet.
The wiki lives on that git server, so no third party holds it. Because it is plain markdown in git, syncing two machines needs no product: it is just git. The whole protocol is four lines in the repo’s CLAUDE.md, and agents follow it without being asked:
1. Before answering anything in a session, first action, always:
run `git pull --rebase origin main`.
2. After any change to wiki files: immediately
`git add -A && git commit -m "<what changed>" && git push origin main`.
The nice side effect is that a remote agent session on that machine gives me the whole wiki from my phone. I can ask what was decided on a project three weeks ago while standing on a train, and the answer comes from a repo that has been quietly writing itself all along.
Takeaways
- Capture cost decides whether a system survives. Not structure, not tooling, not tagging. If capture takes longer than the thought, you will stop capturing.
- A knowledge base earns its keep when it reads back. Storing things is the easy half. The value arrives when the system uses what it already knows to make sense of what you just said.
- Context fixes transcription better than a better model does. Knowing what a project is called and who is on it corrects errors that no amount of audio quality will.
- Keep branching in code, not on a canvas. Let the visual tool be a straight pipe and put the decisions where you can diff and test them.
- Let the model decide what to write, never what to send. Anything that leaves the machine and reaches another person should be constrained in code, not requested in a prompt.
- If you want to try this, start with the people file. Not the automation. One markdown page of who you deal with, what you call them, and what they work on. It is useful to an agent on day one, before any of the plumbing exists.