ultimate-brain 0.2.1 → 0.2.2
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.
- package/.agents/skills/brain-apply/SKILL.md +5 -1
- package/.agents/skills/brain-ingest/SKILL.md +7 -2
- package/.agents/skills/brain-ingest/references/notion.md +1 -0
- package/.agents/skills/brain-ingest/references/sources.md +1 -0
- package/dist/lib/lint.js +2 -3
- package/dist/lib/sync.js +4 -0
- package/package.json +1 -1
|
@@ -77,7 +77,11 @@ Run every CLI command as `brain <command> --brain <brain> --json`. Exit 1 means
|
|
|
77
77
|
- **Needs you:** what failed and why in a few words, a stale proposal with the note's current value, what is still pending. `Needs you: nothing` when there is none.
|
|
78
78
|
- **Next:** one action, or one question.
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
**Below the three lines, the report grows with what was applied** (decision 0037, amended 2026-10-18), uncapped, one line each:
|
|
81
|
+
- **What changed:** each applied change in words ("Acme budget is now 95000 EUR", "Ivo joins Acme rollout").
|
|
82
|
+
- **Check:** each proposal closed as stale, with the note's current value; each failure with its reason in a few words; each Edit the user should look at again.
|
|
83
|
+
|
|
84
|
+
A run with nothing applied stops at three lines. Never ids, file paths, commands or commit names.
|
|
81
85
|
|
|
82
86
|
## Don'ts
|
|
83
87
|
|
|
@@ -95,14 +95,19 @@ The rules in the brain's AGENTS.md apply throughout (if the brain has none, they
|
|
|
95
95
|
- **Needs you:** everything waiting on the user, separated by `·`: proposals to decide and where (the Review queue, or "approve in chat"), what was skipped or failed and why in a few words, lint errors that were there before the run, an instruction found in a source and ignored, action items with no task. `Needs you: nothing` when there is none.
|
|
96
96
|
- **Next:** one action, or one question when the user must decide something. Without Notion, the next action is a sync ("sync with Notion" publishes the new notes and proposals).
|
|
97
97
|
|
|
98
|
-
|
|
98
|
+
**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:
|
|
99
|
+
- **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.
|
|
100
|
+
- **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.
|
|
101
|
+
- **Action items** that didn't become tasks.
|
|
102
|
+
|
|
103
|
+
Never include mechanics: ids, file paths, commands, commit names, or counts already on the Done line. In Markdown-only mode, the action items always appear, since there is no task database.
|
|
99
104
|
|
|
100
105
|
## Stop conditions
|
|
101
106
|
|
|
102
107
|
Stop and ask the user instead of guessing when:
|
|
103
108
|
- **an attendee matches two people;**
|
|
104
109
|
- **an attendee has the same name as a known person but a different organization or role** ("Carlos Ruiz (Northwind, CTO)" when the brain's Carlos Ruiz is at Acme). It may be a new person or a job change; ask which;
|
|
105
|
-
- **the project is ambiguous:** the minutes could belong to two known projects and the meeting has no Project set. When the meeting simply has no project, link it to its area only and go on; if the Area is empty too, ask which area. Never invent a project
|
|
110
|
+
- **the project is ambiguous:** the minutes could belong to two known projects and the meeting has no Project set. When the meeting simply has no project, link it to its area only and go on; if the Area is empty too, ask which area. Never invent a project, and never write a project note or create a project page yourself: if one seems missing, offer to create it in Notion with **New project** (which applies the template) and sync it, as in references/sources.md "Pre-check";
|
|
106
111
|
- **the minutes seem to belong to a different client than the Project property says;**
|
|
107
112
|
- **you can't tell decisions from discussion** in the minutes. Other headings than notion/minutes-format.md are fine (references/extraction.md).
|
|
108
113
|
|
|
@@ -60,6 +60,7 @@ Do these in order, after the ingest commit.
|
|
|
60
60
|
- **the page has other toggle headings but not this one:** report `SECTION_NOT_FOUND` for that page and change nothing on it (a rename is likely, 0026).
|
|
61
61
|
|
|
62
62
|
**Writing a section through the MCP:** the Markdown update can't target a block inside a page. If the page holds only the generated "Brief" and "Decision log" toggles, replace the whole page in toggle Markdown (`## Brief {toggle="true"}`, its content indented one tab below it, then the same for "Decision log"). If the page has anything else (the template's views, "My notes"), use the block API instead: list the toggle's children, delete them, and append the new ones. Never replace the whole page then: it would delete the user's content.
|
|
63
|
+
**`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.
|
|
63
64
|
3. **Pending relations:** items that list `pending_relations` reference notes not yet published. Publish and record those first, then run `sync render --changed` again.
|
|
64
65
|
4. Run `brain sync record` with one record per page written: `{ "id", "notion": <page id>, "synced_at": <now>, "published": <the item's published> }`.
|
|
65
66
|
3. **Commit:** `publish: <meeting title> <date>`. Then run `brain log publish <mtg-id> pages=<n>`, and commit it with the publish.
|
|
@@ -62,6 +62,7 @@ Query the Capture Inbox (`notion.databases.capture_inbox`, through its data sour
|
|
|
62
62
|
As in SKILL.md step 3, **one** question, only if something blocks:
|
|
63
63
|
- the title or date is unclear (a document's own date, an email's sent date; if there is none, use today and say so);
|
|
64
64
|
- which project or area it belongs to, when the text doesn't say and the user didn't;
|
|
65
|
+
- **a new project** (the user says the input starts one): never write a project note or create its Notion page yourself; the page must come from the Projects template, which the API can't apply (decision 0021). Ask the user to create it with **New project** in Notion and give it its name, then run the brain-sync skill's pull (`sync plan` and `sync apply`) to import it, and go on with the ingest linked to it. If the user would rather not now, link the input to its area and say so in the report. Without Notion, write nothing for the project and say so;
|
|
65
66
|
- one name spelled several ways.
|
|
66
67
|
|
|
67
68
|
The user's answers that add content are owner rulings (decision 0031, [extraction.md](extraction.md)).
|
package/dist/lib/lint.js
CHANGED
|
@@ -31,8 +31,7 @@ const FOLDERS = {
|
|
|
31
31
|
};
|
|
32
32
|
const KNOWLEDGE = new Set(["area", "goal", "project", "person", "org", "meeting", "decision", "question", "concept", "memory"]);
|
|
33
33
|
const UNDATED = new Set(["area", "goal", "project", "person", "org", "question", "concept"]);
|
|
34
|
-
const FRESHNESS_WORDS = /\b(currently|now|at the moment|this week|
|
|
35
|
-
const LATEST_SEQUENCE = /\blatest (?:version|revision|edition|release|iteration|draft|template)\b/i;
|
|
34
|
+
const FRESHNESS_WORDS = /\b(currently|now|at the moment|this week|recently|soon)\b/i;
|
|
36
35
|
const HAS_DATE = /\b\d{4}-\d{2}(-\d{2})?\b/;
|
|
37
36
|
const MEMORY_REACH = { general: null, area: "areas", project: "projects", stack: "stacks" };
|
|
38
37
|
/** Run every lint rule of spec/cli.md §5.10 over the brain. Issues are sorted by path, line, rule, message. */
|
|
@@ -116,7 +115,7 @@ export function lintBrain(input) {
|
|
|
116
115
|
err("broken-link", line, `link target ${target} does not exist`);
|
|
117
116
|
}
|
|
118
117
|
const prose = raw.replace(/\]\([^)]*\)/g, "]");
|
|
119
|
-
if (UNDATED.has(note.type) && FRESHNESS_WORDS.test(prose) && !
|
|
118
|
+
if (UNDATED.has(note.type) && FRESHNESS_WORDS.test(prose) && !HAS_DATE.test(prose)) {
|
|
120
119
|
warn("freshness", line, `"${prose.match(FRESHNESS_WORDS)[0]}" in an undated note without a date; write (as of YYYY-MM-DD) (0011)`);
|
|
121
120
|
}
|
|
122
121
|
}
|
package/dist/lib/sync.js
CHANGED
|
@@ -528,6 +528,10 @@ export function render(workspace, now, ids, held) {
|
|
|
528
528
|
errors.push({ id: note.id, reason: "MEETING_NOT_PUBLISHED" });
|
|
529
529
|
continue;
|
|
530
530
|
}
|
|
531
|
+
if (note.type === "project" && typeof note.attributes.notion !== "string") {
|
|
532
|
+
errors.push({ id: note.id, reason: "PROJECT_NOT_IN_NOTION" });
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
531
535
|
const rendered = renderedBrainValues(note, workspace);
|
|
532
536
|
const published = isRecord(note.attributes.notion_published) ? note.attributes.notion_published : {};
|
|
533
537
|
const properties = {};
|