You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add sources/wiki split, truth-timeline page structure, and MCP server (#14)
Redo of closed PR #11 with BizerBrain naming throughout. Brings two
cross-cutting patterns into BizerBrain that have been proven elsewhere
(Karpathy's LLM Wiki pattern, GBrain's compiled-truth structure) and
adds a Model Context Protocol server so the brain works with any
MCP-capable agent.
1. Folder convention: sources/, pages/, daily/
The SKILL.md now teaches three distinct folders:
- sources/ raw, immutable inputs (transcripts, articles, email
dumps). Agent treats as append-only.
- pages/ the wiki: synthesized topical/per-entity notes the agent
owns and maintains.
- daily/ the user's journal, mutable by the human.
A new "Ingesting a source" procedure files raw input under sources/
and links it back to pages/. The boundary: sources/ is the receipts,
pages/ is the synthesis, daily/ is the human's voice.
2. Page structure: compiled truth + timeline
Every pages/<Entity>.md now has a stable, rewritable "compiled truth"
section above a "---" separator and an append-only "## Timeline"
below, with dated entries that back-link to [[daily/...]] or
[[sources/...]]. The truth section is overwritten when facts change;
timeline entries are never edited or removed.
Pitfalls added: never rewrite sources/, never delete timeline
entries, never edit existing timeline entries.
3. MCP server (packages/mcp-server)
New package exposing the same four tools (list_notes, search_notes,
read_note, write_note) over the Model Context Protocol via stdio.
Agents that speak MCP natively (Claude Code, Cursor, any MCP client)
can use BizerBrain by adding one line to their MCP config:
{
"mcpServers": {
"bizerbrain": {
"command": "node",
"args": ["/opt/bizerbrain/packages/mcp-server/src/server.js"],
"env": { "BRAIN_DIR": "/srv/bizerbrain/brain" }
}
}
}
Implementation:
- src/brain.js filesystem ops with the same safety contract as
brain_tools.py: path traversal blocked, atomic writes
(tmp + rename), consistent {ok, ...} shape.
- src/server.js MCP Server wired to StdioServerTransport. Tool
schemas include the truth-timeline guidance in the
write_note description so MCP-only agents (which
don't load SKILL.md) get the same convention.
Tests (17 passing, node:test):
- brain.test.js round-trip, ensureMd, traversal blocked, null byte
rejected, search snippet correctness, list sorted.
- server.test.js list_tools exposes all four with schemas, call_tool
round-trips, unknown tool name handled, traversal
rejected at the protocol layer.
No code changes outside .agents/skills/bizerbrain/SKILL.md and
packages/mcp-server/. The web UI (packages/notes-app), file-api
(packages/file-api), and docker image are unaffected.
Co-authored-by: Claude <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: .agents/skills/bizerbrain/SKILL.md
+84-33Lines changed: 84 additions & 33 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -22,6 +22,7 @@ metadata:
22
22
Use this skill any time the user:
23
23
24
24
-**Captures** something they want to remember (a meeting, a decision, a reading note, a thought)
25
+
-**Drops in a raw source** (a transcript, an article, an email thread) and wants it filed into the brain
25
26
-**Asks about prior context** ("what did we decide about X?", "what's the status of Y?", "who did I talk to about Z?")
26
27
-**Mentions a person, project, or topic recurrently** — even casually — and would benefit from those references being linked together
27
28
-**Asks for a summary** of recent activity, a person, a project, or a topic
@@ -42,73 +43,123 @@ The brain lives at `$BRAIN_DIR` (default `/srv/bizerbrain/brain`). Four tools op
42
43
43
44
### Folder conventions
44
45
45
-
-`daily/YYYY-MM-DD.md` — daily journal-style capture (one note per day)
46
-
-`pages/<Topic>.md` — topical or per-entity notes; one note per person, project, place, or recurring idea (e.g., `pages/Project Aurora.md`, `pages/Sarah Johnson.md`)
46
+
Three folders, three jobs:
47
47
48
-
Use exact human-friendly filenames. `pages/Project Aurora.md`, not `pages/project-aurora.md`. The user reads these in a UI that links by exact name.
48
+
-**`sources/`** — **raw, immutable inputs.** Transcripts, articles, email dumps, dictated notes, anything the user drops in for you to process. **Treat as append-only.** Never rewrite the body of a source file. You may add a small `<!-- ingested: YYYY-MM-DD -->` HTML comment at the top, but do not edit the content.
49
+
-**`pages/`** — **the wiki: synthesized topical or per-entity notes.** One note per person, project, place, recurring idea (e.g., `pages/Project Aurora.md`, `pages/Sarah Johnson.md`). You own these — create them, maintain them, merge as needed.
50
+
-**`daily/`** — **the human's journal.** One note per day, named `daily/YYYY-MM-DD.md`. The user may write here directly. You may append, but be conservative — preserve their voice.
51
+
52
+
The boundary that matters most: **`sources/` is read-only for you; `pages/` is yours to maintain; `daily/` is the user's home turf.**
53
+
54
+
Use exact human-friendly filenames in `pages/`. `pages/Project Aurora.md`, not `pages/project-aurora.md`. The user reads these in a UI that links by exact name.
49
55
50
56
### Wiki links
51
57
52
-
Cross-link related notes with `[[Page Name]]`. The first time you reference a person, project, or recurring topic in a daily note, link it to its topical page. The link target is the basename of the file without the `.md` extension. The web UI auto-creates a stub note if the target doesn't exist yet.
58
+
Cross-link related notes with `[[Page Name]]`. The first time you reference a person, project, or recurring topic in a daily note or a source, link it to its topical page in `pages/`. The link target is the basename of the file without the `.md` extension. The web UI auto-creates a stub note if the target doesn't exist yet.
53
59
54
60
Optional alias form: `[[Sarah Johnson|Sarah]]` displays as "Sarah" but links to `pages/Sarah Johnson.md`.
55
61
62
+
### Page structure: compiled truth + timeline
63
+
64
+
Every note in `pages/` follows this structure:
65
+
66
+
```markdown
67
+
# <Entityname>
68
+
69
+
<Compiled truth — a concise, current, rewritable summary of what is
70
+
known. 1–6 paragraphs or a few bullet points. This is what you'd
71
+
tell someone who asked "who/what is X?" in a sentence or two.>
72
+
73
+
---
74
+
75
+
## Timeline
76
+
77
+
- YYYY-MM-DD — <eventorfact> ([[daily/YYYY-MM-DD]] or [[sources/...]])
78
+
- YYYY-MM-DD — <earlierevent>
79
+
- ...
80
+
```
81
+
82
+
The **compiled truth** above the `---` separator is rewritable: you keep it current as new information arrives. The **timeline** below is **append-only**: every meaningful piece of evidence gets a new dated entry with a back-link to where it came from. Never delete or rewrite timeline entries; only add to them.
83
+
84
+
This gives the user two things in one file: the current understanding (truth), and the provenance trail (timeline) they can audit if they ever doubt something you wrote.
85
+
86
+
`sources/` files do not follow this structure — they're raw input. `daily/` files do not follow this structure — they're the user's journal.
87
+
56
88
## Procedure
57
89
58
-
### Capturing from a conversation or event
90
+
### Capturing from a conversation or event (daily note)
59
91
60
-
1. Compute today's path: `daily/YYYY-MM-DD.md` (UTC or user's local; pick one and be consistent).
92
+
1. Compute today's path: `daily/YYYY-MM-DD.md`.
61
93
2.`read_note(today_path)` — if it returns `ok: false`, treat as empty.
4. Append a new section to the day's note with what was captured. Use `[[Page Name]]` for every entity.
64
96
5.`write_note(today_path, merged_content)` — pass the full file contents, never just the new section.
65
-
6.**For each new or significantly-updated entity**: ensure `pages/<Entity>.md` exists. If it doesn't, write a stub:
97
+
6.**For each entity referenced**: update or stub the topical page in `pages/` using the "Update a topical page" procedure below.
66
98
67
-
```
68
-
# <Entity>
99
+
### Ingesting a source (transcript, article, email)
69
100
70
-
First mentioned in [[YYYY-MM-DD]].
71
-
```
101
+
1. Pick a clear filename under `sources/`, dated and descriptive: `sources/2026-05-09 product review transcript.md`.
102
+
2.`read_note(path)` to confirm it's not already filed. If the user pasted content but didn't pick a path, choose one and tell them.
103
+
3.`write_note(path, content)` — write the raw source verbatim. Optionally add a one-line HTML comment with the date you ingested it.
104
+
4.**Extract entities** from the source: people, projects, decisions, dates, claims.
105
+
5. For each entity, **update its topical page** (see below). Link the new timeline entries back to `[[sources/<filename>]]`.
106
+
6.**Do not** synthesize the source into `pages/` so heavily that you replace it. The source is the receipt; the wiki is the synthesis.
72
107
73
-
If it already exists, optionally update it with what's new (use the "Updating" procedure below).
108
+
### Updating a topical page (the truth + timeline pattern)
74
109
75
-
### Updating a topical page
110
+
1.`read_note('pages/<Entity>.md')`. If `ok: false`, create with a stub (see "Stubbing a new entity" below).
111
+
2.**Decide if the compiled truth needs to change.** New information may:
112
+
- Add a fact ("Sarah is now the launch lead") → update truth
113
+
- Correct a fact ("Sarah moved to Berlin in March, not February") → update truth
114
+
- Add a one-time event with no lasting effect ("Sarah was on PTO last week") → timeline only
115
+
3. Update the compiled-truth section above the `---` separator to reflect the current state.
116
+
4.**Append** a new timeline entry below the `---` with the date and a back-link. Never edit or remove existing timeline entries.
117
+
5.`write_note('pages/<Entity>.md', merged_content)` with the full file contents.
76
118
77
-
1.`read_note('pages/<Entity>.md')` — preserve existing structure and content; do not paraphrase or rewrite what's already there unless the user asked.
78
-
2. Merge new context into the existing structure: extend lists, add subsections, update status lines, add a new dated entry under a "## History" or "## Updates" section.
79
-
3.`write_note('pages/<Entity>.md', merged_content)` — full content, never partial.
119
+
### Stubbing a new entity
80
120
81
-
### Recalling for the user
121
+
When you reference `[[Name]]`for the first time and the file doesn't exist yet, create:
82
122
83
-
1.`search_notes(query)` — start with the user's words. Try variants if the first miss returns nothing useful.
84
-
2. For the top 3-5 hits, `read_note(path)` to get the actual content.
85
-
3.**Synthesize the answer from the read contents** — quote or summarize what's actually in the user's notes, do not invent or fill in from your training data. If the brain is silent on the question, say so.
86
-
4. When citing, use the path: "From `daily/2026-04-12.md`: …"
123
+
```markdown
124
+
# Name
125
+
126
+
First mentioned in [[daily/YYYY-MM-DD]].
127
+
128
+
---
129
+
130
+
## Timeline
131
+
132
+
- YYYY-MM-DD — First mention in [[daily/YYYY-MM-DD]]
133
+
```
87
134
88
-
### Cleaning up or restructuring
135
+
You can flesh out the compiled truth later as more arrives.
89
136
90
-
When the user asks you to merge duplicate notes, rename a topic, or reorganize:
137
+
### Recalling for the user
91
138
92
-
1.`list_notes()` to see the current structure.
93
-
2. Use `read_note` to confirm what's in each affected file.
94
-
3. Plan the merge or move; explain it to the user before executing if it touches more than ~5 files.
95
-
4. Execute with `write_note` (and use the file-api `move` endpoint via the user if a true rename is needed — this skill does not include a delete or move tool by design).
139
+
1.`search_notes(query)` — start with the user's words. Try variants if the first miss returns nothing useful.
140
+
2. For the top 3-5 hits, `read_note(path)` to get the actual content.
141
+
3.**Synthesize the answer from the read contents** — quote or summarize what's actually in the user's notes, do not invent or fill in from your training data. The compiled-truth sections of `pages/` are the best starting point; consult the timeline or the underlying `sources/` files when the user asks "how do we know?" or "when did that happen?"
142
+
4. When citing, use the path: "From `pages/Sarah Johnson.md`: …" or "Per the 2026-04-22 source: …"
143
+
5. If the brain is silent on the question, say so.
96
144
97
145
## Pitfalls
98
146
99
-
-**`write_note` replaces the entire file.** Always `read_note` first when updating; never call `write_note` with only the new content. This is the #1 source of data loss.
147
+
-**`write_note` replaces the entire file.** Always `read_note` first when updating. This is the #1 source of data loss.
148
+
-**Never rewrite a `sources/` file.** They are receipts. If a source contains errors, note the correction on the relevant topical page's timeline; don't edit the source.
149
+
-**Never delete timeline entries.** Even a fact you later contradict belongs in the timeline — it's the audit trail.
100
150
-**Don't invent paths or filenames.** When unsure whether a note exists, `search_notes` or `list_notes` first. Creating `pages/sarah.md` when `pages/Sarah Johnson.md` already exists fragments the brain.
101
-
-**Preserve the user's words.** When updating an existing note, extend or annotate; don't rewrite. The user reads these in a web UI and notices when their phrasing changes.
151
+
-**Preserve the user's words in daily notes.** When extending an existing daily entry, append rather than rewrite. The user reads these in a web UI and notices when their phrasing changes.
102
152
-**The user may also be editing.** If they were typing in the UI when you write, the UI surfaces a conflict banner. Avoid spurious writes — only write when there's a real change to commit.
103
-
-**Markdown only.** Stick to plain markdown. No HTML unless the user has been using HTML in the brain already.
153
+
-**Markdown only.** Stick to plain markdown. No HTML unless the user has been using HTML in the brain already (the dated `<!-- ingested -->` comment in sources is the one exception).
104
154
-**One topic, one note.** Don't create `pages/Aurora Launch.md` if `pages/Project Aurora.md` already covers it. Update the existing note.
105
155
-**Wiki-link the basename, not the path.**`[[Sarah Johnson]]`, not `[[pages/Sarah Johnson.md]]` or `[[Sarah Johnson.md]]`.
106
-
-**Date format.** Always `YYYY-MM-DD` for daily notes — sorts chronologically and matches the UI's "Today" button.
156
+
-**Date format.** Always `YYYY-MM-DD` for daily notes and timeline entries.
107
157
108
158
## Verification
109
159
110
160
After a capture or update, verify:
111
161
112
162
1.`read_note(path)` and confirm the content is what you intended (especially after a `write_note` that merged old + new).
113
-
2. For wiki links: each `[[Page]]` reference in a daily note should resolve to either an existing `pages/<Page>.md` or a freshly-created stub. `list_notes()` after the operation should show all referenced pages.
114
-
3. For recall: the answer to the user should be supportable by quoting from the notes you read. If you can't quote it, you're hallucinating — re-read or admit the gap.
163
+
2. For wiki links: each `[[Page]]` reference in a daily note or source should resolve to either an existing `pages/<Page>.md` or a freshly-created stub. `list_notes()` after the operation should show all referenced pages.
164
+
3. For pages, confirm the structure is intact: a compiled-truth section, a `---` separator, a `## Timeline` heading, and dated entries with back-links.
165
+
4. For recall: the answer to the user should be supportable by quoting from the notes you read. If you can't quote it, you're hallucinating — re-read or admit the gap.
0 commit comments