ultimate-brain 0.4.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/.agents/skills/brain-apply/SKILL.md +35 -22
  2. package/.agents/skills/brain-catch-up/SKILL.md +51 -36
  3. package/.agents/skills/brain-connect-notion/SKILL.md +29 -2
  4. package/.agents/skills/brain-howto/SKILL.md +1 -1
  5. package/.agents/skills/brain-howto/references/guide.md +117 -48
  6. package/.agents/skills/brain-ingest/SKILL.md +14 -6
  7. package/.agents/skills/brain-ingest/references/cli-inputs.md +31 -5
  8. package/.agents/skills/brain-ingest/references/extraction.md +36 -1
  9. package/.agents/skills/brain-ingest/references/notion.md +8 -6
  10. package/.agents/skills/brain-ingest/references/sources.md +36 -14
  11. package/.agents/skills/brain-notion-change/SKILL.md +2 -0
  12. package/.agents/skills/brain-query/SKILL.md +18 -8
  13. package/.agents/skills/brain-sync/SKILL.md +31 -12
  14. package/.agents/skills/brain-sync/references/formats.md +28 -1
  15. package/dist/cli.js +5 -4
  16. package/dist/commands/modules.js +54 -0
  17. package/dist/commands/report.js +81 -4
  18. package/dist/commands/source.js +27 -35
  19. package/dist/commands/status.js +5 -5
  20. package/dist/commands/sync.js +3 -1
  21. package/dist/commands/upgrade.js +33 -18
  22. package/dist/lib/apply.js +237 -33
  23. package/dist/lib/diff.js +31 -0
  24. package/dist/lib/errors.js +2 -0
  25. package/dist/lib/ids.js +2 -0
  26. package/dist/lib/index-builder.js +6 -1
  27. package/dist/lib/lint.js +46 -8
  28. package/dist/lib/modules.js +91 -0
  29. package/dist/lib/note-new.js +111 -18
  30. package/dist/lib/paths.js +1 -0
  31. package/dist/lib/proposals.js +74 -18
  32. package/dist/lib/query.js +1 -1
  33. package/dist/lib/schemas.js +1 -1
  34. package/dist/lib/sync.js +246 -86
  35. package/package.json +1 -1
  36. package/spec/schemas/brain.schema.json +36 -0
  37. package/spec/schemas/note.schema.json +105 -18
  38. package/templates/brain/brain.json +3 -1
  39. package/templates/brain/knowledge/references/.gitkeep +0 -0
@@ -7,6 +7,19 @@ Your second brain has three parts:
7
7
 
8
8
  You never edit the Markdown by hand. You work in Notion and talk to your agent.
9
9
 
10
+ **Modules.** The space is a core you always have (Inbox, Meetings, Projects, Areas, People, Review) plus the modules you choose:
11
+
12
+ | Module | Adds | On for a new brain |
13
+ |---|---|---|
14
+ | **Knowledge** | Decisions, Questions, Concepts | yes |
15
+ | **Orgs** | Client and partner organizations | yes |
16
+ | **Documents** | A document, or part of one, kept as a page you can read | no |
17
+ | **Reports** | Ask the brain in the Inbox, and get a report you can refresh | no |
18
+ | **Tasks** | Action items as Notion tasks | no |
19
+ | **Planning** | Goals and Key Results | no |
20
+
21
+ Change them any time by asking your agent: "turn on documents", "I don't use goals, turn planning off", "which modules do I have?". Turning one on walks you through its Notion steps; turning one off deletes nothing, and the brain simply stops reading and writing its databases. This guide describes every module; skip what you haven't turned on.
22
+
10
23
  ---
11
24
 
12
25
  ## The Spaces
@@ -21,12 +34,12 @@ The navigation on the left of every page lists the Spaces. Each one has tabs tha
21
34
  | **Projects** | Keep projects moving | Active · By area · Deadlines · Gone quiet |
22
35
  | **Plan** | Check that your work serves your goals | Goals · Key results · Areas · Projects by goal |
23
36
  | **Review** | Decide on the changes the brain proposes | Needs my decision · Sources disagree · Approved recently · Rejected |
24
- | **Knowledge** | Find what the brain knows, and everything that came in | Decisions · Questions · Concepts · People · Orgs · Inbox (What's in my inbox?: new captures · What came in?: everything ingested, with what it produced) |
37
+ | **Knowledge** | Find what the brain knows, and everything that came in | Decisions · Questions · Concepts · Documents · People · Orgs · Inbox (What's in my inbox?: captures New or Ready · What came in?: everything ingested, with what it produced) |
25
38
  | **Archive** (under System) | Find finished and archived records | One tab per database |
26
39
 
27
40
  **Area pages** collect everything for one area: its goals, projects, tasks, meetings, decisions and open questions in views, and its people and clients as lists at the top. The brain adds a **Brief** toggle at the end: the area's projects with their status, and its recent decisions and open questions. Open one from Plan → Areas.
28
41
 
29
- **Project pages** show the Brief and Decision log (written by the brain), then the project's tasks, meetings, open questions and people, "What came in?" (every input filed under the project) and "What do we know?" (its decisions and concepts), then your own "My notes".
42
+ **Project pages** show the Brief and Decision log (written by the brain), then the project's tasks, meetings, open questions and people, "What came in?" (every input filed under the project), "What do we know?" (its decisions, concepts and Documents) and **Reports** (the project's reports), then your own "My notes".
30
43
 
31
44
  **A Brief shows only what you reviewed.** Decisions and questions still in Draft stay out of it until you accept them in Review. When a section has nothing reviewed yet, it says how many notes are waiting: "Nothing reviewed yet: 4 notes waiting in Review".
32
45
 
@@ -44,12 +57,13 @@ Every meeting moves through **Brain Status**:
44
57
  - minutes follow the format;
45
58
  - minutes checked and corrected.
46
59
 
47
- Then set Brain Status to **Reviewed**.
60
+ Check the minutes, fix them, then set Brain Status to **Reviewed**. What the minutes get wrong, fix here: it's cheaper than fixing what the brain read from them.
48
61
  4. **Ingest:** tell your agent "ingest my reviewed meetings". The brain reads the minutes and sets the meeting to **Ingested**. Then:
49
62
  - new notes (decisions, questions, people) arrive as **Draft**, with one **Review notes** row in Review to accept them all;
50
63
  - changes to things the brain already knew go to **Review**, and so does an answer it found to one of your open questions;
51
64
  - action items become **Tasks** (status To Do).
52
65
  5. Set **Skipped** for a meeting the brain should never read.
66
+ 6. **Fixed the minutes after the brain read them?** Set Brain Status back to **Reviewed**. The next catch-up reads the meeting again, compares it with what it read before, and proposes only what changed, in one Review row. The earlier version stays in the brain's history.
53
67
 
54
68
  The brain only ingests meetings you marked **Reviewed**, and only when you ask: nothing runs on its own. It never edits the meeting page itself.
55
69
 
@@ -59,71 +73,94 @@ The brain only ingests meetings you marked **Reviewed**, and only when you ask:
59
73
 
60
74
  ## Deciding in Review
61
75
 
62
- **What approving does:** it makes the brain's notes **trusted**. Approved notes appear in your Briefs and in the brain's answers; until then, the brain treats them as unconfirmed. Start from Home → **Needs you → What's waiting for you?**: it counts what waits, by Kind, and each row's **Target Page** opens the meeting or Inbox row it came from.
76
+ **What approving does:** it makes the brain's notes **trusted**. Approved notes appear in your Briefs and in the brain's answers; until then, the brain treats them as unconfirmed. Start from Home → **Needs you → What's waiting for you?**: it counts what waits, by Kind, and each row's **About Page** opens the meeting or Inbox row it came from.
63
77
 
64
- The brain never changes what it already knows without your yes. Each proposed change is a row in **Review → Needs my decision**, showing what it was (**Before**) and what it would become (**After**).
78
+ The brain never changes what it already knows without your yes. Each row in **Review → Needs my decision** says what it is **About**, what it is **Now** and what is **Proposed**, and **Why** quotes the source.
65
79
 
66
- 1. Set **Decision**:
67
- - **Approve** applies the change;
80
+ 1. Set **Your call**:
81
+ - **Approve** applies it;
68
82
  - **Reject** drops it;
69
- - **Edit** applies your own value: type it in **Note**.
70
- 2. **Note** is also for anything else you want the brain to know about that row: "all except Tomás" on a row that adds several people, or "she's the product lead, not marketing". The agent reads it, and when it describes a different change, proposes that change as a new row or asks you. It never applies something your Note didn't clearly say.
71
- 3. Tell your agent "apply my reviews" (or "catch up"). The change is made, and the row moves to Approved or Rejected.
83
+ - **Fix** applies it, corrected: say what's wrong in **What to fix**, in your own words ("it's March, not February", "Lucía is on Acme website, not Acme app").
84
+ 2. **What to fix** also works with Approve, to leave items out: "all except b, e".
85
+ 3. Tell your agent "apply my reviews" (or "catch up"). The agent reads What to fix, applies it, and repeats every correction back to you in its report ("a: launch set to March, not February"), so you can check it read you right. It never applies something you didn't clearly say; when unsure, it asks.
72
86
  4. **30 days after you decide,** the next catch-up moves the row to Notion's trash, so Review holds only what's recent. The brain keeps every decision, and Notion keeps the trash for 30 more days.
73
87
 
74
- **One Review notes row per input.** Every meeting or document the brain reads brings one row: "Accept 6 new notes from Acme launch review, and 2 links". Its After lists every new note and routine link, lettered:
88
+ **One row per meeting, email or document.** Everything one input brings is one row, "From Acme launch review: 2 changes, 6 new notes and 2 links", with its items lettered in **Proposed**:
75
89
 
76
90
  ```
77
- a) Decision: Use Contentful as the blog CMS
78
- b) Question: Who signs off the launch post?
91
+ a) ⚠ Launch date on Acme website: 2027-02 → 2027-03
92
+ b) Add to Row-level security: Carlos will use RLS for the auth migration.
93
+ c) Decision: Use Contentful as the blog CMS
94
+ d) Question: Who signs off the launch post?
79
95
  …
80
- g) People on Acme website: Lucía Fernández
96
+ h) People on Acme website: Lucía Fernández
81
97
  ```
82
98
 
83
- - **Approve** accepts them all: the notes become **Reviewed** and appear in the Briefs, and the links are added.
84
- - **Approve** with a Note "all except b, g" accepts the rest; b stays Draft and g isn't added.
85
- - **Reject** archives the notes that are still Draft and drops the links. Nothing is deleted.
99
+ Changes to what the brain already knew come first, and a changed fact is marked ⚠: those are the ones to read closely.
100
+ - **Approve** accepts them all: the changes are made, the notes become **Reviewed** and appear in the Briefs, and the links are added.
101
+ - **Approve** with "all except b, h" accepts the rest. b and h aren't rejected: they move to a new row, "Deferred from Acme launch review", for you to decide later.
102
+ - **Fix** with "a: March" applies everything, with a corrected.
103
+ - **Reject** applies nothing, and archives the notes that are still Draft. Nothing is deleted.
104
+ - If a fact changed since the row was written (you edited it in Notion, say), only that item is dropped, and the report says so. The rest applies.
86
105
 
87
- Changes to what a note says (a new fact, added text, two sources disagreeing) and answers get their own rows.
106
+ **Three kinds of row.** Every Review row's Name says which it is:
107
+ - **From <source>:** everything one meeting, email or document brings, lettered as above;
108
+ - **Conflict: …** two sources disagree, a new decision replaces an older one, or two records may be duplicates. These need your judgment, so each has a row of its own;
109
+ - **Answer: …** new material answers one of your open questions.
88
110
 
89
- **Answer rows.** When new material answers one of your open questions, an Answer row says so: "Who owns the mobile app? → Carlos Ruiz owns it". Approve it and the question shows as **Answered** in Notion; Edit it to write the answer yourself; Reject it and the question stays open.
111
+ **Answer rows.** When new material answers one of your open questions, an Answer row says so: "Who owns the mobile app? → Carlos Ruiz owns it". Approve it and the question shows as **Answered** in Notion; Fix it to give the answer yourself; Reject it and the question stays open.
90
112
 
91
- **Your corrections go in Note.** Target says what changes; typing there does nothing.
113
+ **Type your corrections in What to fix,** never in About, Now or Proposed: those are the brain's, and typing there does nothing.
92
114
 
93
- | Kind | Approve means | Can you Edit? |
94
- |---|---|---|
95
- | Update Fact | The new value replaces the old one; the old one stays in the history | Yes |
96
- | Add To Note | The text is added to the note | Yes |
97
- | Add Link | The links listed in After are added (people to a project, an alias to a person) | No: approve with a Note to leave some out |
98
- | Contradiction | Two sources disagree; both claims are kept as contested | Yes: your value becomes the truth |
99
- | Supersede | A newer note replaces an older one, which is archived | No |
100
- | Merge | A duplicate is folded into the record it duplicates | No |
101
- | New Item | A new note is created as Draft | No |
102
- | Review Notes | The notes listed become Reviewed and the links are added; Reject archives the Draft ones | No: approve with a Note ("all except b, d") |
103
- | Answer | The question gets this answer and shows as Answered | Yes: your text becomes the answer |
104
-
105
- To see why a change was proposed, open the row: **Why** quotes the sentence from the source, and **Source Meeting** links to the meeting when there is one.
115
+ The row's **Kind** property (hidden in your views) says exactly what the brain proposes:
116
+
117
+ | Kind | Approve means |
118
+ |---|---|
119
+ | Review Notes | Everything listed: the changes are made, the notes become Reviewed, the links are added. Reject archives the Draft notes |
120
+ | Update Fact | The new value replaces the old one; the old one stays in the history |
121
+ | Add To Note | The text is added to the note |
122
+ | Update Body | A Document's text is replaced by its new version; Proposed shows the lines that change (`-` old, `+` new) |
123
+ | Add Link | The links listed are added (people to a project, an alias to a person) |
124
+ | Contradiction | Two sources disagree; both claims are kept as contested. Fix with the true value |
125
+ | Supersede | A newer note replaces an older one, which is archived |
126
+ | Merge | A duplicate is folded into the record it duplicates |
127
+ | New Item | A new note is created as Draft |
128
+ | Answer | The question gets this answer and shows as Answered |
129
+
130
+ **Fix works on every kind.** To see why a change was proposed, open the row: **Why** quotes the sentence from the source, and **Source Meeting** links to the meeting when there is one.
106
131
 
107
132
  A rejected change can come back if a later meeting says the same thing again.
108
133
 
109
134
  ---
110
135
 
136
+ ## Correcting what came in
137
+
138
+ **How do I correct what came from a meeting?** It depends on where the mistake is:
139
+ - **The minutes are wrong** (a misheard name, a wrong date): fix the minutes on the meeting page, then set Brain Status back to **Reviewed**. The next catch-up reads the meeting again and proposes only what changed, in one Review row. The same goes for a capture: fix its text and set its Brain Status to **Ready**.
140
+ - **The minutes are right, but the brain read them wrong** (the wrong project, a suggestion taken as a decision): on the Review row, set Your call to **Fix** and say what's wrong in What to fix ("c is a suggestion, not a decision", "a belongs to Acme app"). If the row was already approved, tell your agent what's wrong, or set the note's Lifecycle to **Disputed**.
141
+
142
+ **How do I refresh a report?** Click **Refresh** on the Report row in the Inbox (it ticks **Refresh asked**), then "catch up": the brain rewrites that report in place, as of today, and unticks the box. Or say "refresh the Acme launch report". A new **Ask the brain** row always makes a new report. The earlier versions stay in the brain's history.
143
+
144
+ **A report says something wrong?** Write it in the Report row's **What to fix** ("Lucía left Acme in June"). The mistake lives in the notes the report rests on, so the next catch-up turns it into Review rows on those notes. Once you approve them, it refreshes the report.
145
+
146
+ ---
147
+
111
148
  ## What you can edit, and what the brain owns
112
149
 
113
150
  Hover over a property name to see its owner. Each description starts with "Owner: you", "Owner: brain" or "Owner: system".
114
151
 
115
152
  | Owner | Examples | What happens when you edit it |
116
153
  |---|---|---|
117
- | **You** | Status, Priority, Dates, Lifecycle, Archived, Decision, Note, Brain Status on meetings and captures, Project and Area on a capture, Full text on an Inbox row | Your value stands. The brain reads it but never overwrites it |
154
+ | **You** | Status, Priority, Dates, Lifecycle, Archived, Your call, What to fix, Brain Status on meetings, Project, Area, Kind and Only keep on an Inbox row, the buttons and the boxes they tick (Document asked, Refresh asked, Promote asked) | Your value stands. The brain reads it but never overwrites it; it unticks a button's box and clears a report's What to fix once it has acted on them, and sets a row it took in to Done. It fills Kind only when you left it empty |
118
155
  | **Brain** | Summary, Role, Client, Key Facts, Why, Assessment | The next sync reads your edit as a **correction**. Names, summaries and relations change in place; a key fact gets a dated history entry; judgments such as Assessment become a Review proposal |
119
156
  | **System** | Brain ID, Last Synced, Ingested At | Don't edit. The brain uses them to match records |
120
157
 
121
158
  **Page text:**
122
159
  - **Brief and Decision log** on project pages, and the **Brief** on area pages, are rewritten by the brain on every sync. Anything you type inside them is lost.
123
160
  - **My notes**, and everything else on a page, is yours.
124
- - Decision, Question and Concept pages are written entirely by the brain.
161
+ - Decision, Question and Concept pages are written entirely by the brain. So is a Document's page, except a promoted one ("Buttons" below): its text is yours once it's made.
125
162
  - A capture's text is yours; the brain only adds its Kind, Summary and what it produced. An Ask row's text is yours too.
126
- - **Inbox rows the brain creates** (a document, email, web page, a repo file) get a **digest** in their body: what the input is, a summary and the key points, with figures and dates as stated. Emails and chats also get their whole text in a **Full text** toggle. For a document, tick **Full text** on its row (or say "full text for …") and the next catch-up adds it. Both are written once and never read back, so an edit you make there stays in Notion. The original file is the real copy.
163
+ - **Inbox rows the brain creates** (a document, email, web page, a repo file) get a **digest** in their body: what the input is, a summary and the key points, with figures and dates as stated. It is written once and never read back, so an edit you make there stays in Notion. To read the whole input in Notion, keep it as a Document ("Buttons" below). The original file is the real copy. A **Full text** toggle on an older row stays as it is.
127
164
  - A question's **Status** is yours. The brain sets it twice at most: **Open** when it creates the question, and **Answered** once, when you approve an Answer row.
128
165
 
129
166
  **Lifecycle** tells you how far to trust a record:
@@ -136,19 +173,43 @@ Set **Disputed** on anything wrong. The brain stops relying on it, and you can a
136
173
 
137
174
  ---
138
175
 
176
+ ## The Inbox and its buttons
177
+
178
+ Every Inbox row moves through **Brain Status**: **New → Ready → Done**.
179
+ - **New:** a row you created by hand. The brain leaves it alone.
180
+ - **Ready:** the brain takes it in at the next "catch up". **Quick capture** creates its row as Ready.
181
+ - **Done:** the brain took it in, or skipped it and says why in Summary ("Skipped: same as Acme requirements"). Rows the brain creates for documents, emails and web pages start as Done.
182
+
183
+ **Buttons** ask the brain for something. Each ticks a box on the same row, which reads as "waiting for the brain"; the next "catch up" acts on it and unticks it.
184
+
185
+ | Button | On | Ticks | The brain then |
186
+ |---|---|---|---|
187
+ | **Keep as document** | Inbox rows | Document asked (and sets the row to Ready) | Keeps the row's file, or its text when it has no file, as a **Document**: the whole of it, or only what you wrote in **Only keep** ("just the requirements table") |
188
+ | **Refresh** | Report rows | Refresh asked | Rewrites the report as of today |
189
+ | **Promote to document** | Decisions, Concepts | Promote asked | Makes a Document from the note, linked both ways, whose text is yours to edit from then on |
190
+
191
+ **Documents** (the Documents module). A Document is a page you read, linked to its source, project and area:
192
+ - **the whole input:** the text exactly as it came in. It needs no review and is Reviewed straight away;
193
+ - **a part** (Only keep set, or "also keep the budget from the Acme doc"): what you asked for, as a list or a table. It arrives as Draft in the source's Review row, like a new note;
194
+ - **promoted** from a decision or concept: it starts from the note, then you write in it.
195
+
196
+ The brain still reads every input for decisions, questions and people, whether or not you keep it as a Document. A new version of the file later proposes only the lines that changed.
197
+
198
+ ---
199
+
139
200
  ## Adding things
140
201
 
141
202
  | You want to add | Do this |
142
203
  |---|---|
143
- | A quick thought, link or idea | **Quick capture** on Home. It lands in Knowledge → Inbox. Set its **Project** if you know it, so the agent doesn't ask. Then "catch up" (or "process my inbox") |
204
+ | A quick thought, link or idea | **Quick capture** on Home. It lands in Knowledge → Inbox as **Ready**. Set its **Project** if you know it, so the agent doesn't ask. A row you create by hand starts as **New**: set it to Ready when it's ready. Then "catch up" (or "process my inbox") |
144
205
  | A meeting | **New meeting** on Home, or let Notion AI create it when it starts taking notes |
145
206
  | A project, area, goal, person or org | Create the row in Notion (**New project** on Home for projects). The next sync imports it into the brain |
146
- | A document (PDF, Word, PowerPoint, Excel, saved HTML page, image) | Put it in your drop folder and tell your agent "process my drop folder". It lists the files and asks once which to take; each ingested file moves to `processed/` inside the folder, so what's left at the top is what the brain hasn't read yet. Or name one file: "ingest this PDF: ~/Documents/brain-dropbox/proposal.pdf". Word, PowerPoint, Excel and HTML files need MarkItDown installed once: `pipx install 'markitdown[all]'` |
207
+ | A document (PDF, Word, PowerPoint, Excel, saved HTML page, image) | Put it in your drop folder and tell your agent "process my drop folder". It lists the files and asks once which to take, and, with Documents on, whether to **keep each as a document**: "no" (the default: the brain only reads it), "all", or "only the requirements" ("The Inbox and its buttons"). A new version of a document later proposes only the lines that changed. Then, each ingested file moves to `processed/` inside the folder, so what's left at the top is what the brain hasn't read yet. Or name one file: "ingest this PDF: ~/Documents/brain-dropbox/proposal.pdf". Word, PowerPoint, Excel and HTML files need MarkItDown installed once: `pipx install 'markitdown[all]'` |
147
208
  | A web page | Give your agent the link: "ingest this page: https://…". For a page behind a login, save it as a PDF in your drop folder instead |
148
- | A file from your phone | Attach it to a **Quick capture** (or to the meeting page), with Project set if you know it. The next catch-up reads it with the row. Files on project and area pages are not read |
209
+ | A file from your phone | Attach it to a **Quick capture** (or to the meeting page), with Project set if you know it. To keep the file itself as a Document, click **Keep as document** (and write in **Only keep** if you want just a part). The row is Ready; the next catch-up reads the file with the row. Files on project and area pages are not read |
149
210
  | A repo's knowledge (decisions, docs, changelog) | "link the repo at ~/code/acme-api to the area Clients, files decisions/** and docs/*.md". Each catch-up then reads the files changed since the last one; the first time, it asks which to take. The brain never writes to the repo |
150
- | A question for a full report | **Ask the brain** on Home: type the question as the Name ("Where do we stand with the Acme launch?"). The next catch-up answers with a **Report** row in the Inbox, linked from yours |
151
- | An email, chat thread or note | Paste it into a **Quick capture** (keep the From, Date and Subject lines). For a thread, run **`/Clean email`** on the page: Brain Assistant drops signatures, disclaimers and quoted copies, keeps every message word for word, oldest first, and changes the page only after you confirm. Then "catch up". Or paste it straight to your agent: "ingest this email" |
211
+ | A question for a full report | **Ask the brain** on Home: type the question as the Name ("Where do we stand with the Acme launch?"). The next catch-up answers with a **Report** row in the Inbox, linked from yours, and on the project's or area's page under **Reports**. To bring it up to date later, click **Refresh** on it ("Correcting what came in"). Needs the Reports module |
212
+ | An email, chat thread or note | Paste it into a **Quick capture** (keep who sent it and when). For a thread, run **`/Clean email`** on the page: Brain Assistant gives each message a heading with names and date ("Tomás Vidal → Lucía Fernández · 3 Dec 2026"), its own text word for word below it, and a divider before the next, newest first. It drops addresses, signatures, disclaimers, quoted copies and Teams, Zoom or Meet blocks, and rewrites the page right away (the page history keeps the original), asking first only when something is truly unclear. Then set the row to **Ready** and "catch up". Or paste it straight to your agent: "ingest this email" |
152
213
  | A task | Add it in Tasks. Action items from meetings, and your own from documents, emails and captures, are created for you |
153
214
 
154
215
  **Tasks:**
@@ -171,7 +232,7 @@ Set **Disputed** on anything wrong. The brain stops relying on it, and you can a
171
232
  | `/Weekly review` | What got done and decided, goal and project health, next week |
172
233
  | `/Plan check` | Projects without goals, goals without projects, overdue items |
173
234
  | `/Tidy capture` (on a new capture in the Inbox) | A cleaner version of the capture; replaces the text after you say yes |
174
- | `/Clean email` (on a new capture holding a pasted email thread) | The thread without signatures, disclaimers and quoted copies, each message word for word, oldest first; replaces the text after you say yes |
235
+ | `/Clean email` (on a new capture holding a pasted email thread) | Each message under a heading of names and date, its own text word for word, a divider between messages, newest first; no addresses, signatures, disclaimers, quoted copies or meeting blocks; rewrites the page directly and asks only on a serious doubt |
175
236
  | "how do I …?" | An answer from this guide |
176
237
 
177
238
  Brain Assistant reads; your agent in Claude Code or Codex writes. To get something *into* the brain, use the phrases below.
@@ -192,8 +253,10 @@ Run these in Claude Code or Codex, from your brain's folder.
192
253
  | Apply your Review decisions | "apply my reviews" |
193
254
  | Bring Notion edits and new rows into the brain, and publish its changes | "sync with Notion" |
194
255
  | Ask what the brain knows | "what did we decide about …?", "who is …?", "when is the … launch?" |
195
- | Get a report on a subject: where it stands, a timeline, decisions, open questions, people and gaps | "report on the Acme launch". It includes notes you haven't reviewed, marked *(not reviewed)*, and is published as a Report row. A report is a snapshot: ask again for a fresh one |
196
- | Have a document's whole text in Notion | "full text for the Acme brief", or "slides 3–9 of the launch deck" (or tick Full text on its Inbox row) |
256
+ | Get a report on a subject: where it stands, a timeline, decisions, open questions, people and gaps | "report on the Acme launch". It includes notes you haven't reviewed, marked *(not reviewed)*, and is published as a Report row. "refresh the Acme launch report" rewrites it as of today |
257
+ | Keep a document, or part of one, as a page | "keep the Acme brief as a document", "also keep the budget from the Acme doc" (or click **Keep as document** on its Inbox row) |
258
+ | Turn a decision or concept into a page you write in | "promote Use Supabase for auth to a document" (or click **Promote to document** on it) |
259
+ | Turn a module on or off | "turn on documents", "turn planning off", "which modules do I have?" |
197
260
  | Read a repo into the brain | "link the repo at <path> to the area <name>, files <patterns>" |
198
261
  | Ask how the system works | "how do I …?", "why didn't … ?" (or ask Brain Assistant in Notion) |
199
262
  | Change the Notion structure (a property, an option, a view) | "add a property to Projects …". Structure is changed in the product first, then in Notion |
@@ -211,12 +274,18 @@ Run these in Claude Code or Codex, from your brain's folder.
211
274
  | Text you typed in a project's Brief disappeared | The brain rewrites Brief and Decision log on every sync | Put your notes in **My notes** |
212
275
  | Your edit to a Summary or Role changed back | Brain-owned fields are read as corrections only on the next sync | "sync with Notion" before the next ingest |
213
276
  | A new project or person isn't in the brain | It is imported on the next sync | "sync with Notion" |
214
- | A rejected change came back | A later source said it again | Reject it again, or Edit it to the true value |
277
+ | A rejected change came back | A later source said it again | Reject it again, or Fix it to the true value |
215
278
  | A record shows Draft | You haven't reviewed it yet | Read it; set **Reviewed**, or **Disputed** if it's wrong |
216
279
  | An Area page doesn't list a decision | A decision's Area comes from its project | Link the decision's project to the area, then "sync with Notion" |
217
- | A Review row with a Note is still pending | The agent couldn't tell what the Note meant, or it described a different change | Answer the agent's question, or look for the new row it proposed |
280
+ | A Review row with What to fix is still pending | The agent couldn't tell what it meant, or it described a different change | Answer the agent's question, or look for the new row it proposed |
281
+ | A Fix row is still pending | What to fix is empty | Say what's wrong in What to fix |
282
+ | A row "Deferred from …" appeared | You approved a row "all except …": the items you left out wait there | Decide it like any other row |
283
+ | A capture wasn't taken in | It is still **New**: the brain takes in only Ready rows | Set it to **Ready**, then "catch up" |
284
+ | You fixed the minutes after the ingest, and nothing changed | The meeting is still Ingested | Set it back to **Reviewed**, then "catch up" |
218
285
  | You want to see what the brain made from a document | Every input has a row in Knowledge → Inbox → What came in?, and on its project's page | Open the row: the body has the digest, and Decisions, Questions, Concepts and People list what it produced |
219
286
  | A Brief says "Nothing reviewed yet" | Its notes are still Draft | Approve their Review notes rows, then "catch up" |
220
- | A document's row shows only the digest | Documents and decks get a digest by default | Tick **Full text** on the row, then "catch up" |
221
- | A capture was skipped | It repeats a source the brain already has; the report names that source | Nothing, or say "ingest it anyway" if it adds something |
287
+ | A document's row shows only the digest | Inbox rows get a digest; the whole text lives in a Document | Click **Keep as document** on the row, then "catch up" |
288
+ | A capture is Done but produced nothing | It repeats a source the brain already has; its Summary says "Skipped: same as …" | Nothing, or say "ingest it anyway" if it adds something |
289
+ | A button's box stays ticked | No catch-up has run since, or the module is off | "catch up"; if the report says the module is off, "turn on documents" (or reports) |
290
+ | Goals, Tasks or Documents aren't updated any more | Their module is off | "which modules do I have?", then "turn on …" |
222
291
  | A file attached to a capture wasn't read | Its format can't be read, or the file is broken | The catch-up's Check line names the file and the fix |
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: brain-ingest
3
- description: Ingest into the brain reviewed meeting minutes from Notion or a file, documents (PDF, Word, PowerPoint, Excel, HTML, images), web pages by URL, pasted emails, chat threads and notes, the Notion Inbox, files attached in Notion, and the changed files of a linked repo. Snapshots each input as a source, matches it against what the brain already knows, writes new notes (meeting, people, decisions, questions, concepts) as drafts with one Review notes row to accept them, proposes changes to existing knowledge and answers to open questions for your review, and creates action items as Notion tasks. Use when the user says "ingest my meetings", "process the reviewed minutes", "ingest this PDF", "ingest this page <url>", "ingest this email", "process my inbox", "process my drop folder", "link the repo at <path>", or after marking meetings Reviewed.
3
+ description: Ingest into the brain reviewed meeting minutes from Notion or a file, documents (PDF, Word, PowerPoint, Excel, HTML, images), web pages by URL, pasted emails, chat threads and notes, the Notion Inbox, files attached in Notion, and the changed files of a linked repo. Snapshots each input as a source, matches it against what the brain already knows, writes new notes (meeting, people, decisions, questions, concepts) as drafts, keeps an input as a Document (whole, or a part) when asked, with one Review row per source holding the new notes and every change to existing knowledge, proposes answers to open questions, reads a corrected input again for only what changed, and creates action items as Notion tasks. Use when the user says "ingest my meetings", "process the reviewed minutes", "ingest this PDF", "ingest this page <url>", "ingest this email", "process my inbox", "process my drop folder", "link the repo at <path>", or after marking meetings Reviewed.
4
4
  ---
5
5
 
6
6
  # Ingest into the brain
@@ -23,7 +23,7 @@ The rules in the brain's AGENTS.md apply throughout (if the brain has none, they
23
23
 
24
24
  2. **Fetch** *(Notion)*. Query the Meetings database for pages with Brain Status = **Reviewed**, oldest Date first, through its data source ([references/notion.md](references/notion.md)). Process them one at a time. Never take Not Reviewed or Skipped meetings (decision 0012). For each page, read its properties (Name, Date, Attendees, Project, Area) and the minutes: which parts of the page count as minutes is in references/notion.md.
25
25
 
26
- **Already ingested?** If a meeting note in `brain index --json` already has this page's id as `notion`, the brain side is done (a publish failed earlier): skip to step 11 for it.
26
+ **Already ingested?** If a meeting note in `brain index --json` already has this page's id as `notion`, the user set it back to Reviewed: either they fixed the minutes (a **re-read**, decision 0045), or a publish failed earlier. Snapshot the minutes as a re-read (step 3): when the dry run skips them as `DUPLICATE_SOURCE`, nothing changed and the brain side is done, so skip to step 11 for it; otherwise go on as a re-read ([references/sources.md](references/sources.md), "Re-reads and new versions").
27
27
 
28
28
  3. **Pre-check** (both modes). Before writing anything, ask the user **one** question covering everything that blocks a correct ingest:
29
29
  - the Date is empty;
@@ -39,6 +39,8 @@ The rules in the brain's AGENTS.md apply throughout (if the brain has none, they
39
39
  - **`skipped` with `DUPLICATE_SOURCE`:** this exact text was already ingested. Report it, and in Notion mode set nothing. Stop here for this meeting.
40
40
  - **Otherwise:** keep the source item for step 7.
41
41
 
42
+ **A re-read** (the meeting was ingested before) adds `replaces` = the latest version of the meeting's source to the item, writes the new source alone in step 7, then reads only the lines `brain source diff` gives ([references/sources.md](references/sources.md), "Re-reads and new versions"). It writes no new meeting note: steps 4–6 run on the changed lines only, and step 8 proposes what changed in one Review row.
43
+
42
44
  4. **Match.** Run `brain index` (JSON) and resolve every name in the minutes against titles and `aliases`:
43
45
  - attendees → person notes;
44
46
  - the project and client → project and org notes;
@@ -58,7 +60,9 @@ The rules in the brain's AGENTS.md apply throughout (if the brain has none, they
58
60
  - contradictions with the loaded notes;
59
61
  - action items.
60
62
 
61
- Keep every claim attached to its subject, and copy values verbatim. Hold the result in memory as two lists: **new notes** and **changes to existing notes**.
63
+ Keep every claim attached to its subject, and copy values verbatim. Hold the result in memory as two lists: **new notes** and **changes to existing notes**. *(Documents)* When the input is to be kept as a document (Document asked on its row, the drop folder's answer, or the user's words), add its **Documents** to the new notes: references/extraction.md, "Documents". The notes are extracted either way (decision 0049).
64
+
65
+ **A re-read** analyses only the changed lines, and a changed line **corrects** what the old line said (decision 0045, U-18): propose to replace the old statement (references/extraction.md "Re-reads": an `update_fact` for a fact, else an `add_to_note` worded as a correction), never to add the new wording as a second claim next to the old one, and never mark the pair ambiguous.
62
66
 
63
67
  7. **Write new notes.** Write **one** `brain note new` batch containing the source, the meeting, new people, new decisions and new questions (shapes in [references/cli-inputs.md](references/cli-inputs.md) §2).
64
68
  1. **Get ids** with `brain id new <type> --count <n>`, so the notes can reference each other by id. The meeting lists its `decisions` and `questions`, and each decision's `decided_in` and each question's `raised_in` names the meeting, so the pair is consistent.
@@ -69,17 +73,20 @@ The rules in the brain's AGENTS.md apply throughout (if the brain has none, they
69
73
  8. **Propose changes.** Write every change to an existing note in **one** `brain proposal new` batch ([references/cli-inputs.md](references/cli-inputs.md) §3):
70
74
  - a fact change → `update_fact`;
71
75
  - text to add to an existing note → `add_to_note`;
76
+ - a Document's new text, from a new version of its file → `update_body` (references/extraction.md, "Documents"); never on a promoted Document, whose body is the user's;
72
77
  - a link to add to an existing note's list → `add_link`: a new or existing person joining a project's `people`, an attendee missing from an existing meeting, a new alias for an existing person (decision 0028);
73
78
  - two sources disagreeing → `contradiction`;
74
79
  - a new decision replacing an older one → write the new decision in step 7, then `supersede`;
75
80
  - a likely duplicate → `merge`;
76
81
  - a new decision or question for a meeting that already existed before this run → `new_item`.
77
82
 
78
- - a new note this run wrote, and every `add_link` → **one** `review_notes` item for the input (decision 0041, 0043): `{ "kind": "review_notes", "source": "<mtg-id, or the src- id for any other input>", "notes": [<every knowledge note step 7 created: the meeting, people, decisions, questions, concepts; never the source>] }`. The CLI folds every `add_link` item with the same `source` into it, so links and aliases are lettered items of that one Review row, and writes its title;
83
+ - a new note this run wrote, every `add_link`, `update_fact`, `update_body` and `add_to_note` → **one** `review_notes` item for the input (decisions 0041, 0043, 0045): `{ "kind": "review_notes", "source": "<mtg-id, or the src- id for any other input>", "notes": [<every knowledge note step 7 created: the meeting, people, decisions, questions, concepts, `part` Documents; never the source, and never a `whole` Document, which needs no Review>] }`, with `notes: []` when the input created none (a re-read). The CLI folds every change and link item with the same `source` into it, fact changes first, so they are lettered items of that one Review row, and writes its title ("From Acme sync: 2 changes, 1 new note and 1 link"). Send the change items as usual, each with its own `title` and `why`. Only judgment calls get rows of their own: `contradiction`, `supersede`, `merge`, `new_item` and `answer`;
79
84
  - the material answers an open question the brain already has → `answer`, on that question: the answer in one sentence, the quote as `why`, and `answer_note` = the note that answers it when there is one (usually a decision step 7 created).
80
85
 
81
86
  `DUPLICATE_PENDING`, `ALREADY_LINKED` and `ALREADY_ANSWERED` skips are fine: the change is already waiting for review, already made, or the question already has an answer. `NOTHING_TO_REVIEW` means the input created no note and no link: fine too.
82
87
 
88
+ **Never edit a proposal or a note file yourself** (`sed`, a text editor, a script; U-18): the CLI writes them, with their hashes and log entries. A proposal that came out wrong is rejected or fixed through brain-apply; a new batch with the right values is written instead, and the wrong one is closed when the user rejects it. If lint fails on a file this run wrote, stop (step 9).
89
+
83
90
  9. **Rebuild and check.** Run `brain index`, `brain views`, then `brain lint`. If lint reports an **error in a file this run wrote**, stop: report it and do not commit. Errors that were already there before the run are not yours to fix here; mention them.
84
91
 
85
92
  10. **Log and commit.** Run `brain log ingest <mtg-id> created=<n> proposals=<n> tasks=<n>`. Commit in the brain repo: `ingest: <meeting title> <date> (<n> new, <n> proposals)`. If this run does not publish, push now (step 11, "Push"); otherwise push after the publish commit.
@@ -87,7 +94,8 @@ The rules in the brain's AGENTS.md apply throughout (if the brain has none, they
87
94
  11. **Publish** *(Notion, per `settings.publish`: with `ask`, ask once before this step)*, following [references/notion.md](references/notion.md):
88
95
  - publish new and changed notes and the new proposals (`brain sync render --changed` → MCP → `brain sync record`);
89
96
  - then create the action items as tasks (`brain sync tasks` → MCP → `brain sync record`);
90
- - this sets the meeting's relations, Brain Status = Ingested and Ingested At, and never touches its title or body (decision 0007).
97
+ - this sets the meeting's relations, Brain Status = Ingested and Ingested At, and never touches its title or body (decision 0007);
98
+ - **after a re-read**, or when an earlier publish already sent them, render has no Brain Status left to send (it goes out once): set the meeting's Brain Status back to **Ingested** through the MCP yourself, and nothing else on the page. Otherwise it stays Reviewed and the next run reads it again.
91
99
 
92
100
  Then commit again: `publish: <meeting title> <date>`.
93
101
 
@@ -104,7 +112,7 @@ The rules in the brain's AGENTS.md apply throughout (if the brain has none, they
104
112
  - **Next:** one action, or one question when the user must decide something. Without Notion, the next action is deciding the proposals in chat ("what needs my decision"), or connecting Notion ("connect the brain to Notion"), after which a sync publishes everything.
105
113
 
106
114
  **Below the three lines, the report grows with what came in** (decision 0037, amended 2026-10-18). A run that only moved counts stops at three lines. Otherwise add, per input, one line each, and leave nothing out because the list is long:
107
- - **What came in:** every new project, decision (with its assessment), open question and risk, every fact that changed (old → new), and new people with their role. A one-line summary of what a document or thread is about comes first.
115
+ - **What came in:** every new project, decision (with its assessment), open question and risk, every fact that changed (old → new), new people with their role, and each Document with what it keeps ("the whole file", or what Only keep named). A one-line summary of what a document or thread is about comes first. For a re-read: "Acme sync, read again: 1 change (launch 2027-02 → 2027-03)".
108
116
  - **Check:** every assumption the user should verify: a date taken from today or from a month only, a fact marked ambiguous, a name left unlinked, a part of a document not analysed.
109
117
  - **Action items** that didn't become tasks.
110
118
 
@@ -42,14 +42,17 @@ A document, a web page, then a pasted email:
42
42
  ```
43
43
 
44
44
  - **`kind`:** `document`, `email`, `chat`, `note` or `capture`. Leave it out for minutes.
45
- - **`file_name`** (the name only, no folder) and **`converter`** (`claude-read <model id>`, `codex-view-image <model id>`, or `markitdown <version>`) are required with a `file:` key.
45
+ - **`file_name`** (the name only, no folder) and **`converter`** (`claude-read <model id>`, `codex-view-image <model id>`, `markitdown <version>`, `plain-text` for a `.txt` or `.md` file, `verbatim` for a repo file) are required with a `file:` key.
46
46
  - **Web page** (0036): `source_key` is `url:<the https URL as given>`; `kind` `document` and `converter` (`markitdown <version>` or `web-fetch <model id>`) are required; no `file_name`.
47
47
  - **Capture:** `source_key` is `notion:<row page id>`, `kind` is `capture`, `origin_edited` is the row's `last_edited_time`.
48
48
  - **`summary`** (every kind except minutes, added in the real run of step 6, not the step 3 dry run), in `frontmatter` like every field below: one line on what the source taught. It is the Inbox row's Summary.
49
49
  - **`digest`** (in `frontmatter`; every kind except minutes, captures and attachments, added with `summary`; decision 0043): the key points by section and the figures and dates as stated, in Markdown. It is the body of the Inbox row.
50
- - **`notion_text`** and **`notion_parts`:** leave them out unless the user chose otherwise; the CLI writes `full` for `email` and `chat`, `digest` for `document` and `note`. `"notion_text": "full", "notion_parts": ["3-9"]` puts slides 3 to 9 on the row. Never send `notion_text_requested`: only `brain source full-text` writes it.
50
+ - **Never send `notion_text`, `notion_parts`, `notion_text_requested` or `keep`:** they are retired (decision 0049) and the CLI refuses them (`INPUT_INVALID`). A whole text to read in Notion is a `whole` Document (§2, "Documents").
51
51
  - **A linked repo's file** (decision 0042) adds `"repo": "<name>", "repo_path": "decisions/0041-review.md", "commit": "<the listing's to, 40 hex>"` to a `document` with a `file:` key, `file_name` = the path's last segment and `converter: verbatim` for a text file.
52
- - **A file attached in Notion** adds `"attached_to": "<the parent's src- id>"` to a `document` with a `file:` key, and has no `digest`, `notion_text` or `notion_parts`. The parent must exist already or come earlier in the same batch.
52
+ - **`only_keep`** (decision 0049; any kind but `minutes` and `capture`, attached files included): what the user asked to keep as a Document, as written (`"only_keep": "just the requirements"`), from the row's Only keep, the drop folder's "only …" or the user's words. Leave it out when the whole input is kept, or none of it. An attached file takes its row's Only keep.
53
+ - **`area`** and **`projects`** (decision 0050): the Area and Project the user set on the Inbox row (or the meeting), as brain ids. Each must be an existing area or project, else the CLI refuses the batch (`UNKNOWN_ID`). Leave them out when the row has none.
54
+ - **`replaces`** (decision 0045): on a re-read or a new version, the `src-` id of the version it follows. The CLI then dedupes it by content only, and refuses an id that isn't a source or that another source already replaces (`INPUT_INVALID`).
55
+ - **A file attached in Notion** adds `"attached_to": "<the parent's src- id>"` to a `document` with a `file:` key, and has no `digest`. The parent must exist already or come earlier in the same batch.
53
56
  - **Title:** `<title> (<kind>)`; for a web page, `<title>` is the page's own title. **`file_date`:** the text's own date (a document's date, a web page's stated publication or update date, an email's sent date); for a capture, the row's Created date; else today.
54
57
  - **Dates in the notes:** a new note's timeline `from` is the date the text gives, else the source's `file_date`; `learned` is always today (the day the brain learned it).
55
58
  - **Duplicates:** the CLI also skips a source whose `file:` key, or whose `capture` row, was already ingested, even if the text differs.
@@ -89,6 +92,28 @@ Things the CLI checks that are easy to get wrong:
89
92
  - **The meeting body uses relative links**, e.g. `../people/…`, `../decisions/…`, `../../projects/<slug>/project.md`.
90
93
  - **Sources (`sources`) of knowledge notes are the meeting id.** The meeting itself cites the source snapshot.
91
94
 
95
+ ### Documents (decisions 0045, 0049)
96
+
97
+ A Document is a `reference` note with an `origin` (references/extraction.md, "Documents"). In the same batch as its source when the input is new; on its own for a source already in the brain.
98
+
99
+ ```json
100
+ { "type": "reference", "id": "ref-6p2v8k4m", "title": "Acme website brief",
101
+ "frontmatter": { "origin": "whole", "summary": "Acme's brief for the new website, as sent.",
102
+ "area": "area-2m7c4h8n", "projects": ["prj-9x4t1b7e"], "sources": ["src-5t8n2v6q"] },
103
+ "body": "<the source's body, byte for byte>" }
104
+ { "type": "reference", "id": "ref-4k8m2q7w", "title": "Acme website: requirements",
105
+ "frontmatter": { "origin": "part", "summary": "The requirements from Acme's website brief.", "projects": ["prj-9x4t1b7e"],
106
+ "area": "area-2m7c4h8n", "sources": ["src-5t8n2v6q"] },
107
+ "body": "## Requirements\n\n- Login with email\n- Launch in 2027-02\n" }
108
+ { "type": "reference", "id": "ref-9w3c7n2t", "title": "Use Supabase for auth",
109
+ "frontmatter": { "origin": "promoted", "promoted_from": "dec-3f7k9m2q", "summary": "Acme moves auth from Firebase to Supabase.",
110
+ "projects": ["prj-9x4t1b7e"], "sources": ["mtg-8c4n2p7w"] },
111
+ "body": "Acme moves auth from Firebase to Supabase.\n\n## Decision\nUse Supabase for auth.\n" }
112
+ ```
113
+
114
+ - **`origin` is required.** `whole`: `sources` is exactly that one `src-` id and the body is its body byte for byte, or the CLI refuses it; the CLI writes it as `reviewed`, and a second one of the same source comes back in `skipped` as `ALREADY_KEPT` (fine). `part`: a draft that goes in the input's `review_notes` like any new note. `promoted`: `promoted_from` names an existing decision or concept that has no promoted Document yet; it takes that note's lifecycle; `sources` may be left out.
115
+ - Leave `whole` and `promoted` Documents out of `review_notes`: they need no Review.
116
+
92
117
  ## 3. The proposals batch
93
118
 
94
119
  ```json
@@ -111,16 +136,17 @@ Things the CLI checks that are easy to get wrong:
111
136
  - **`title`** reads as a Review row: `<subject> <field>: <old> → <new>`.
112
137
  - **Other kinds** (spec/schema.md §11):
113
138
  - `add_to_note`: `target`, `content`. A link in `content` is relative to the target note's folder.
139
+ - `update_body` (decisions 0045, 0049): `target` = a Document (`reference` note) whose `origin` isn't `promoted`, `content` = its whole new body, every unchanged line copied exactly. The CLI stores the old body's hash, so a body changed meanwhile is caught as stale, and refuses a `content` equal to the body (`NO_CHANGE`).
114
140
  - `contradiction`: `target`, `field`, `after` (the target must have a current value).
115
141
  - `supersede`: `target` = the new note, `supersedes` = the old one.
116
142
  - `merge`: `target` = the duplicate, `merge_into` = the survivor.
117
143
  - `new_item`: `note`, a `note new` item without `id`, for a decision or question of a meeting that already existed.
118
- - **`review_notes`** (decisions 0041, 0043): one per input, in the same batch as its `add_link` items, which the CLI folds into it as lettered items:
144
+ - **`review_notes`** (decisions 0041, 0043, 0045): one per input, in the same batch as its `add_link`, `update_fact`, `update_body` and `add_to_note` items, which the CLI folds into it as lettered items (changes first, then notes, then links):
119
145
  ```json
120
146
  { "kind": "review_notes", "source": "mtg-pcpyn31n",
121
147
  "notes": ["mtg-pcpyn31n", "per-zzvs98vn", "dec-axker49q", "dec-xe9x6apm", "que-wtnyy4r6", "que-zv7ckbtk"] }
122
148
  ```
123
- `source` is the meeting id for minutes, else the source's id: the same value the batch's other proposals carry. `notes` lists every knowledge note `note new` created for this input (never the source). The CLI writes the title ("Accept 6 new notes from Acme launch review, and 2 links"). A note can be in only one `review_notes`.
149
+ `source` is the meeting id for minutes, else the source's id: the same value the batch's other proposals carry. `notes` lists every knowledge note `note new` created for this input (never the source), or is `[]` when it created none (a re-read). The CLI writes the title ("From Acme launch review: 1 change, 6 new notes and 2 links"). A note can be in only one `review_notes`. The reply's `created` has one proposal for all of them; folded items are not listed separately.
124
150
  - **`answer`** (decision 0041), on an open question the input answers:
125
151
  ```json
126
152
  { "kind": "answer", "title": "Who owns the mobile app: Carlos Ruiz", "target": "que-8n3v5x1d",
@@ -36,11 +36,46 @@ Minutes follow the table above. For other sources (references/sources.md) there
36
36
 
37
37
  | Kind | What it usually yields | Different from minutes |
38
38
  |---|---|---|
39
- | `document` (brief, contract, report, deck) | Facts and their changes, decisions the document records, people with roles, open questions and risks | A decision's `date` is the date the document gives for it, else the document's date. When the document is about a project, propose one `add_to_note` on the project: what the document is, in 1–2 sentences, with a link to the source (relative to the project note). A document about an area only, or about work that has no project note, gets none: its Inbox row already files it, and the report suggests creating the project in Notion when the work deserves one. Action items only where the document assigns them |
39
+ | `document` (brief, contract, report, deck) | Facts and their changes, decisions the document records, people with roles, open questions and risks; and, when it is kept as a document, its Documents (below) | A decision's `date` is the date the document gives for it, else the document's date. When the document is about a project, propose one `add_to_note` on the project: what the document is, in 1–2 sentences, with a link to the source (relative to the project note). A document about an area only, or about work that has no project note, gets none: its Inbox row already files it, and the report suggests creating the project in Notion when the work deserves one. Action items only where the document assigns them |
40
40
  | `email`, `chat` | Decisions and facts stated in the thread, people, questions | Who said what matters: attribute a decision to its sender (`deciders`) only when the thread shows they decided. A thread that reports a decision made elsewhere ("the launch moves to March") still yields the decision note if it passes the gate. A quoted earlier message is part of the thread, not a new statement |
41
41
  | `note` | Whatever the user wrote: facts, ideas, people | The user's own words: no `^[ambiguous]` against the user's other notes; a disagreement with the brain is a `contradiction` |
42
42
  | `capture` | Usually one thing: a fact, an idea, a person, a to-do | A fact about an existing note → `update_fact`; an idea or method → a `concept` note (`summary`, `sources`, and `area`, `projects` or `tags` when the capture says what it belongs to); a new person → a person note; the owner's own to-do → a task (below). Nothing durable is a valid result. **A capture holding a pasted email or chat thread** is analysed with the `email`/`chat` row instead (sources.md) |
43
43
 
44
+ ### Documents: keeping an input as a page (decisions 0045, 0049) *(Documents)*
45
+
46
+ A Document is a `reference` note shown in Notion's Documents database: something the user wants to read and refer to from any database. The extraction above runs **either way**: keeping an input as a page never stops its decisions, questions and facts from being taken out (decision 0049). There are three kinds, by `origin`:
47
+
48
+ - **`whole`:** the input is to be kept and **Only keep is empty** (Document asked on its Inbox row, "all" in the drop folder's question, "keep the Acme brief as a document" in chat). One Document per source, its body the source's body **byte for byte** (the CLI checks the hash): copy the source's body, never retype or tidy it.
49
+ - `title`: the input's title without the kind ("Acme website brief"), `frontmatter`: `origin: whole`, `summary` (one line: what the file is), `sources: [<that one source id>]`, and `area` and `projects` from the row or the project the input is about;
50
+ - it needs **no Review**: the CLI writes it as `reviewed`, and it never goes in `review_notes`;
51
+ - an Inbox row **with files attached** keeps each **file**, not the capture's text: one `whole` Document per attached source (`attached_to` = the row's source);
52
+ - a second `whole` of the same source is skipped as `ALREADY_KEPT`: fine.
53
+ - **`part`:** Only keep names something ("the requirements table and the deadlines"; or "also keep the budget from the Acme doc" in chat, from the source the brain already has). One Document holding only that:
54
+ - `title`: what it is, named for its subject: "Acme website: requirements", "Globex: price list";
55
+ - `frontmatter`: `origin: part`, `summary` (one line: what it holds and from which document, without a version or date, so a new version doesn't make it stale), `sources: [<the source id>]`, and `area` and `projects`;
56
+ - body: the kept content, as a Markdown list or table, in the document's order and wording; every figure, date and name exactly as stated. No commentary, no links of your own;
57
+ - it is a draft like any new note: it goes in the input's `review_notes` (for a request on a source already in the brain, a new `review_notes` with that source).
58
+ - **`promoted`:** Promote asked on a decision or concept (a `promote_requests` item). One Document seeded from the note, linked to it:
59
+ - `title`: the note's title, `frontmatter`: `origin: promoted`, `promoted_from: <the note id>`, `summary` = the note's summary, and the note's `area`, `projects` and `sources` copied;
60
+ - body: the note's summary, a blank line, then the note's body;
61
+ - the CLI gives it the note's lifecycle, and it needs no Review. From then on **its body is the user's**: never propose an `update_body` on it.
62
+
63
+ The source records what the user asked to keep in `only_keep` (cli-inputs.md §1b), so a new version knows it.
64
+
65
+ **A new version of a file that has a Document** (the source has `replaces`, sources.md "New versions"): never a second Document. Read the Document's body, change only the lines the new version changes (`brain source diff` says which), and propose the result as an `update_body` on that Document: `content` = the whole new body, every unchanged line copied exactly, so the Review row shows only the lines that differ. `why` names what changed ("Requirement 4: deadline 1 Mar → 15 Mar"). It goes in the new source's `review_notes` as a lettered item. A new version that changes nothing a `part` Document keeps proposes nothing for it.
66
+
67
+ ### Re-reads: only what changed (decision 0045)
68
+
69
+ A corrected input read again (a meeting set back to Reviewed, an Inbox row set back to Ready, a new version of a document) is a new source with `replaces` (sources.md "Re-reads"). Analyse **only the lines `brain source diff` gives**, against what the brain already holds from the earlier version:
70
+ - **a changed line corrects the old one** (U-18): what the earlier version said was wrong, so the new line **replaces** it; it is not a second claim. Never add the new wording next to the old one, and never mark the pair `^[ambiguous]`:
71
+ - a changed value (a date, an amount, a name, a role) held as a fact → `update_fact` on that note, `before` = the old value, `after` = the new, `why` = the new line ("launch in February" → "launch in March": `launch_date` 2027-02 → 2027-03);
72
+ - a changed statement in a note's text ("in a transition period" → "done with the transition period") → one `add_to_note` worded as the correction, naming what it replaces: "Correction (fixed minutes, 2026-10-27): the team is done with the transition period; the earlier minutes said it was still in it." No proposal kind rewrites a note's body (only a Document's `update_body`), so also name the note under Check with the old wording: "Acme sync's text still says 'in a transition period'; the correction is added below it";
73
+ - a new line that passes the rules above → a new note or a change, as in a first ingest. For a meeting, a new decision or question is a `new_item` (the meeting note already exists);
74
+ - a removed or reversed line that a note rests on (a decision the minutes no longer record, a misheard name) → never archive or rewrite that note yourself. Name it under the report's Check, with what to do ("Use Firebase for auth rests on a line the corrected minutes removed: reject it in Review if it's still pending, or say 'archive it'").
75
+ - the meeting note's own text (its summary and body) still says what the first version said: when a change touches it, add one `add_to_note` on the meeting ("Corrected minutes: the launch moves to March 2027, not February"), and name under Check any `summary` the change makes stale (a project's, the meeting's): no proposal kind rewrites a summary;
76
+ - an action item only when its line changed (a new owner or date): it becomes a task as in a first ingest. Unchanged ones already are tasks, and the report doesn't list them again;
77
+ - unchanged lines are not read again: what they gave is already in the brain.
78
+
44
79
  ### Tasks for the owner (decision 0037)
45
80
 
46
81
  In these sources, an action item becomes a Notion **task** only when it is addressed to the **owner**: "can you send me the plan by Friday" in an email to the owner, "I need to book the venue" in the owner's capture. Each task:
@@ -42,6 +42,8 @@ When the user's notes and the minutes disagree on a fact, ask in the pre-check (
42
42
 
43
43
  Do these in order, after the ingest commit: pages first, so every task's project, meeting or Inbox row exists when the task is created.
44
44
 
45
+ **One write, final content** (U-18). Every write carries the page's real content: never create a page with a placeholder ("…", "TBD", "content to follow") to fill it in later, and never write a body in pieces that leave the page half-written between turns. A body goes in the create call, or in one append right after it; a body longer than one append allows (100 blocks, 2000 characters a block) goes in consecutive appends of real content, in order, in the same turn. If a write fails partway, report it: the next render produces the page again.
46
+
45
47
  **Write in parallel** (decision 0037). Within each step, send the writes that don't depend on each other as parallel tool calls in one turn, up to 10 at a time (Notion limits the request rate). Don't read a page back after writing it: the write's response holds its id. Read a page only when the write needs its current content, such as a project's blocks before a section is replaced.
46
48
 
47
49
  1. **Pages: notes, meeting, sources and proposals:**
@@ -52,7 +54,7 @@ Do these in order, after the ingest commit: pages first, so every task's project
52
54
  - **`action: trash`** (a Review row decided more than 30 days ago, decision 0045): move `page_id` to Notion's trash (update the page with `in_trash: true`; `archived: true` on API versions before 2025-09). Nothing else. Record it like any other write; the proposal stays in the brain.
53
55
  - **Meeting and Inbox relations with `"mode": "add"`:** add the listed pages and keep the existing ones.
54
56
  - **`"mode": "if_empty"`:** write only if the property is empty in Notion.
55
- - **`body` (decisions, questions, concepts):** replace the page body with it.
57
+ - **`body` (decisions, questions, concepts, Documents):** replace the page body with it. A `promoted` Document has a `body` only on `create`; on `update` it is `null`, and its page body is the user's (decision 0049).
56
58
  - **`body` and `sections` on an Inbox item** (a source, or a report): see "Inbox bodies" below. A capture's or an Ask row's page body is the user's: render never gives one a body.
57
59
  - **`sections` (projects):** replace only the children of the toggle heading with that exact name ("Brief", "Decision log"). Read the page's blocks first (decision 0033):
58
60
  - **the page has no toggle headings at all** (created without the template): append a "Brief" and a "Decision log" toggle heading, in that order, at the end of the page, then fill them;
@@ -61,7 +63,7 @@ Do these in order, after the ingest commit: pages first, so every task's project
61
63
 
62
64
  **Writing a section through the MCP: the block API only** (decision 0043). List the toggle's children, delete them, and append the new ones as blocks. Never write a section through the Markdown page update, even on a page that holds nothing else: it flattens the toggles and can delete the user's content.
63
65
 
64
- **`properties` with `"Full text": { "type": "checkbox", "value": false }`** clears the row's box: send it as any other property.
66
+ **`properties` with `"Refresh asked": { "type": "checkbox", "value": false }`** on a report row clears its box: send it as any other property. Document asked and Promote asked are never in `properties`: the skill unticks them through the MCP once it has acted (brain-catch-up, step 5).
65
67
  **`PROJECT_NOT_IN_NOTION`** in `errors`: a project note with no Notion page (written before 0.2.2, or by hand). Never create the page through the API: it would miss the template. Report it, and ask the user to create the project with **New project** in Notion under the same name and put the note's id in its **Brain ID**, so the next sync links the two.
66
68
  3. **Pending relations:** items that list `pending_relations` reference notes not yet published. Publish and record those first, then run `sync render --changed` again.
67
69
  4. Run `brain sync record` with one record per page written: `{ "id", "notion": <page id>, "synced_at": <now>, "published": <the item's published> }`.
@@ -74,11 +76,11 @@ Do these in order, after the ingest commit: pages first, so every task's project
74
76
  ### Inbox bodies (decision 0043)
75
77
 
76
78
  The brain writes the body of the Inbox rows it creates, once:
77
- - **`body`** on a `create`: the row's page content, written as blocks after the row is created. For a source it is the digest: a line saying what the input is, the summary and the key points. For a report it is the report's six sections.
78
- - **`sections` `{ "Full text": … }`:** a toggle heading **"Full text"** after the body, holding the text. Create the toggle when the row has none; when it has one, replace its children. Keep the text's headings as headings (one per slide of a deck), Markdown tables as Notion tables, and an email or chat thread as one block per message. Split long text into as many blocks as the API needs (a block holds at most 2000 characters of text, and one append at most 100 blocks), in order, never cutting a word.
79
- - Neither is ever rebuilt or read back: an edit you make there stays in Notion.
79
+ - **`body`** on a `create`: the row's page content, written as blocks after the row is created. For a source it is the digest: a line saying what the input is, the summary and the key points. For a report it is the report's six sections; a refreshed report comes back as an `update` with a `body` (decision 0045): replace the row's page content with it, then send its properties (Refresh asked cleared).
80
+ - **No Full text** (decision 0049): render sends no `sections` on a source. A row that already shows a "Full text" toggle keeps it; leave it alone. The whole text of an input now lives in a Document ([extraction.md](extraction.md), "Documents").
81
+ - The body is never rebuilt or read back (except a report's body on a refresh): an edit you make there stays in Notion.
80
82
 
81
- A report row's **Ask** relation links it to the Ask row it answers. After writing the report row, set that Ask row's **Brain Status** to Processed through the MCP; change nothing else on it.
83
+ A report row's **Ask** relation links it to the Ask row it answers. After writing the report row, set that Ask row's **Brain Status** to Done through the MCP; change nothing else on it.
82
84
 
83
85
  ## If Notion fails partway
84
86