diff --git a/integrations/openclaw/commands/skills.ts b/integrations/openclaw/commands/skills.ts
index 23b7b7501..2e02552a9 100644
--- a/integrations/openclaw/commands/skills.ts
+++ b/integrations/openclaw/commands/skills.ts
@@ -1,4 +1,4 @@
-import { existsSync, readFileSync } from "node:fs"
+import { existsSync, readdirSync, readFileSync } from "node:fs"
import { dirname, resolve } from "node:path"
import { fileURLToPath } from "node:url"
import type { OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry"
@@ -39,13 +39,62 @@ function loadSkill(skillsDir: string, dir: string): string {
return readFileSync(resolve(skillsDir, dir, "SKILL.md"), "utf-8")
}
+/**
+ * List a skill's bundled resource files (references/, assets/, ...) so the
+ * command can tell the assistant where they live on disk. SKILL.md workflows
+ * reference these by relative path; without the mapping, bundled commands
+ * would direct the assistant to files it was never given. evals/ is excluded
+ * as test fixtures.
+ */
+function listResourceFiles(skillsDir: string, dir: string): string[] {
+ const root = resolve(skillsDir, dir)
+ const files: string[] = []
+ const walk = (rel: string) => {
+ for (const entry of readdirSync(resolve(root, rel), {
+ withFileTypes: true,
+ })) {
+ const relPath = rel ? `${rel}/${entry.name}` : entry.name
+ if (entry.isDirectory()) {
+ if (relPath !== "evals") walk(relPath)
+ } else if (relPath !== "SKILL.md") {
+ files.push(relPath)
+ }
+ }
+ }
+ walk("")
+ return files.sort()
+}
+
+function resourceSection(
+ skillsDir: string,
+ dir: string,
+ files: string[],
+): string {
+ if (files.length === 0) return ""
+ const lines = files
+ .map((f) => `- \`${f}\` → ${resolve(skillsDir, dir, f)}`)
+ .join("\n")
+ return (
+ "\n\n## Bundled resource files\n\n" +
+ "This skill references companion files by relative path. They are installed at:\n\n" +
+ `${lines}\n\n` +
+ "When the workflow directs you to read one of these files, read it from the absolute path listed above."
+ )
+}
+
export function registerSkillCommands(api: OpenClawPluginApi): void {
const skillsDir = resolveSkillsDir(api)
const manifest = loadManifest(skillsDir)
for (const entry of manifest) {
const commandName = entry.dir.replace(/^memory-/, "")
- const content = loadSkill(skillsDir, entry.dir)
+ const content =
+ loadSkill(skillsDir, entry.dir) +
+ resourceSection(
+ skillsDir,
+ entry.dir,
+ listResourceFiles(skillsDir, entry.dir),
+ )
api.registerCommand({
name: commandName,
diff --git a/integrations/openclaw/openclaw.plugin.json b/integrations/openclaw/openclaw.plugin.json
index d8f47c7bd..c68b2d309 100644
--- a/integrations/openclaw/openclaw.plugin.json
+++ b/integrations/openclaw/openclaw.plugin.json
@@ -26,6 +26,7 @@
"skills/memory-literary-analysis",
"skills/memory-metadata-search",
"skills/memory-notes",
+ "skills/memory-onboarding",
"skills/memory-reflect",
"skills/memory-research",
"skills/memory-schema",
diff --git a/integrations/openclaw/scripts/fetch-skills.ts b/integrations/openclaw/scripts/fetch-skills.ts
index c82a35dc5..7b4ccd886 100644
--- a/integrations/openclaw/scripts/fetch-skills.ts
+++ b/integrations/openclaw/scripts/fetch-skills.ts
@@ -1,15 +1,18 @@
/**
* Copy all memory-* skills from the top-level basic-memory skills source.
*
- * Auto-discovers skill directories in ../../../skills, copies each SKILL.md
- * into this package's skills/
/SKILL.md, and generates skills/manifest.json.
+ * Auto-discovers skill directories in ../../../skills, copies each skill's
+ * SKILL.md plus any bundled resources (references/, evals/, assets/, ...)
+ * into this package's skills//, and generates skills/manifest.json.
*/
import {
+ cpSync,
existsSync,
mkdirSync,
readdirSync,
readFileSync,
+ rmSync,
writeFileSync,
} from "node:fs"
import { dirname, resolve } from "node:path"
@@ -80,8 +83,25 @@ function main() {
const meta = parseFrontmatter(content)
const outDir = resolve(SKILLS_DIR, dir)
+ // Clear any previously generated copy so files deleted or renamed in
+ // the source skill don't survive as stale artifacts in the package.
+ rmSync(outDir, { recursive: true, force: true })
mkdirSync(outDir, { recursive: true })
writeFileSync(resolve(outDir, "SKILL.md"), content)
+
+ // Copy bundled resources (references/, evals/, assets/, ...) so
+ // multi-file skills stay self-contained in the generated package.
+ for (const entry of readdirSync(resolve(SOURCE_SKILLS_DIR, dir), {
+ withFileTypes: true,
+ })) {
+ if (entry.name === "SKILL.md") continue
+ cpSync(
+ resolve(SOURCE_SKILLS_DIR, dir, entry.name),
+ resolve(outDir, entry.name),
+ { recursive: true },
+ )
+ }
+
manifest.push({ dir, name: meta.name, description: meta.description })
console.log(` ✓ ${dir}`)
}
diff --git a/skills/README.md b/skills/README.md
index e5a4ce050..1d59056ae 100644
--- a/skills/README.md
+++ b/skills/README.md
@@ -27,6 +27,7 @@ Basic Memory provides the MCP server — tools like `write_note`, `search_notes`
| **memory-research** | Web research synthesized into Basic Memory entities. Researches a subject, checks for existing knowledge, presents findings, and creates entity notes. | When asked to research a company, person, technology, or topic. |
| **memory-literary-analysis** | Analyze a complete literary work into a structured knowledge graph — characters, themes, chapters, locations, symbols, and literary devices. | Full-text literary analysis, book club companions, teaching resources, or research projects. |
| **memory-continue** | Resume prior work by rebuilding context from the knowledge graph — `build_context` via `memory://` URLs, recent activity, and search, then read the key notes. | Starting a session, or when the user says "continue with...", "back to...", or "where were we?" |
+| **memory-onboarding** | Guided onboarding for people new to Basic Memory — interview, blueprint, approval gate, then build a full system: schemas, templates, instruction notes, a startup router, indexes, and real seed notes, plus assistant setup so the rules load every session. | When a user is new to Basic Memory, doesn't know what to use it for, wants structure in an empty or messy project, or wants their assistant to follow consistent rules across sessions. |
## Basic Memory Cloud
diff --git a/skills/memory-onboarding/SKILL.md b/skills/memory-onboarding/SKILL.md
new file mode 100644
index 000000000..8cff845d6
--- /dev/null
+++ b/skills/memory-onboarding/SKILL.md
@@ -0,0 +1,142 @@
+---
+name: memory-onboarding
+description: "Guide someone new to Basic Memory through designing and building a complete personal knowledge system — interview them about what they want to track, propose a structure, build it with schemas and instruction notes, teach them to use it, and set up their AI assistant to load it automatically. Use this skill whenever a user says they're new to Basic Memory, wants to 'get started', 'set up', or 'onboard' with Basic Memory, doesn't know what to use it for, asks how to organize their memory project or knowledge base, wants help designing folders/schemas/conventions, or asks how to make their assistant remember context between sessions. Also use it when a user has an empty or messy Basic Memory project and wants structure."
+---
+
+# Basic Memory Onboarding
+
+You are guiding a person who is new to Basic Memory through building a knowledge system that fits *their* life — then teaching them to use it and wiring it into their AI assistant so every future session starts already knowing the rules.
+
+This skill works with any LLM or assistant platform. Where platform-specific setup is needed (system prompts, project instructions), identify what YOUR environment supports and adapt the generic patterns in `references/assistant-setup.md`.
+
+## Why this approach
+
+Basic Memory is markdown files parsed into a knowledge graph. A pile of unstructured notes is barely better than a folder of text files. The compounding value comes from four things this skill installs from day one:
+
+1. **Schemas** — note types with defined fields, so every task/contact/expense note looks the same and can be queried structurally.
+2. **Observations and relations** — categorized facts (`- [status] active`) and typed links (`- depends_on [[Other Note]]`) that turn prose into a graph.
+3. **Instruction notes** — the rules of the system live *inside* the system, as notes the assistant loads at session start. The knowledge base becomes self-describing.
+4. **A startup router** — one small note that tells any assistant, on any platform, exactly what to load for each kind of task.
+
+**Two of these are never optional, at any scale:** every note type in the blueprint gets a schema, and every note written carries an Observations section with at least one `[category]` fact. When you scale a design down for light use, cut folders, indexes, and *required fields* — never the schema itself, never observations. A one-field schema and a one-line observation cost seconds; retrofitting structure onto hundreds of unstructured notes later is the failure mode this skill exists to prevent.
+
+## Speak Plainly — the User Doesn't Know the Jargon
+
+The person you're onboarding has likely never heard the words "schema", "observation", "frontmatter", or "knowledge graph" — and they never need to learn them to benefit from any of them. The structure is for you; the conversation is for them.
+
+- Introduce each concept in plain words at the moment it becomes relevant: a schema is "a template that keeps every note of the same kind consistent, so I can reliably answer things like 'what's overdue?'"; observations are "the key facts on a note, tagged so they're easy to find later"; relations are "links between notes, so one thing leads to the next".
+- **The user never writes syntax.** You handle the `[category]` lines, wiki-links, and validation under the covers — they just talk. Say this explicitly; it's reassuring.
+- One concept at a time, and only when it earns its place. If you catch yourself defining three terms in one breath, stop explaining and build something with their data instead — the example teaches better than the definition.
+
+## Workflow overview
+
+```
+Phase 0 Preflight — verify tools, pick/create project, assess existing content
+Phase 1 Interview — what do they want to track? (suggest if they don't know)
+Phase 2 Blueprint — propose full structure; iterate until approved
+Phase 3 Build — schemas → templates → instruction notes → indexes → seed notes
+Phase 4 Assistant setup — persistent instructions that load the router every session
+Phase 5 Teach — hands-on exercises with their real data
+Phase 6 Grow — suggest expansions and a maintenance cadence
+```
+
+Do not skip the approval gate between Phase 2 and Phase 3. Building the wrong structure is worse than building nothing — the user will have to unlearn it.
+
+## Phase 0 — Preflight
+
+Before asking the user anything:
+
+1. Confirm Basic Memory tools are available (`write_note`, `read_note`, `search_notes`, `list_directory`, and ideally `schema_infer`/`schema_validate`). If they aren't, stop and help the user connect Basic Memory first.
+2. List their projects (`list_memory_projects`). Ask which project to build in, or whether to create a fresh one. **Every subsequent call must pass this project explicitly** — mixed-project writes are one of the most common and painful setup errors.
+3. Check for existing content (`list_directory` at root, depth 2). Three situations:
+ - **Empty** — greenfield, proceed normally.
+ - **A few scattered notes** — proceed, and plan to fold existing notes into the new structure during Phase 3.
+ - **Substantial existing content** — this is a restructure, not an onboarding. Still use this skill, but Phase 1 becomes "what's working and what isn't", and Phase 2 must map old → new locations before anything moves.
+4. **Check the live docs when unsure.** Basic Memory's documentation is agent-readable: fetch `https://docs.basicmemory.com/llms.txt` for an index, and any page as clean markdown via its `raw/....md` URL (e.g. `raw/reference/mcp-tools-reference.md`, `raw/concepts/schema-system.md`). Tool names and parameters evolve — when this skill and the docs disagree, the docs are canonical.
+
+## Phase 1 — Interview
+
+Ask **one question at a time**, conversationally. Never present a wall of questions. What you need to learn:
+
+1. **Domains** — what do they want to keep track of? If they have ideas, dig into each: what specifically, how often, what does "done" look like?
+2. **If they have no idea**, offer a concrete menu and ask what resonates (multi-select). Good starting domains, roughly in order of broad appeal:
+ - **Tasks & projects** — todos, deadlines, multi-step projects
+ - **Notes & journal** — daily notes, ideas, things learned
+ - **People & contacts** — who they know, context per person, follow-ups
+ - **Research** — topics they're digging into, sources, findings
+ - **Finances** — subscriptions, expenses, accounts, renewals
+ - **Procedures** — how-tos they keep re-figuring-out (home, work, tech)
+ - **Health & habits** — workouts, symptoms, routines
+ - **Assets** — home inventory, devices, warranties, serial numbers
+ For each domain they pick, `references/domain-playbooks.md` has a starter kit: folders, a schema, naming conventions, and an example note. Read it before proposing the blueprint.
+3. **Volume and cadence** — a system for 5 notes a week looks different from one for 50. Light use → fewer folders, fewer required fields.
+4. **One real example per domain** — "tell me about a task on your plate right now" / "one subscription you pay for". These become the seed notes in Phase 3 and make every later phase concrete instead of hypothetical.
+5. **What they've tried before** — if a previous system failed, find out why. Design against that failure.
+
+Start with 2–3 domains even if they're excited about six. A small system that works grows; a sprawling empty scaffold dies. Note the deferred domains for Phase 6.
+
+## Phase 2 — Blueprint
+
+Read `references/conventions.md` and `references/schema-guide.md` now if you haven't. Then present ONE document (in chat, not yet written anywhere) containing:
+
+1. **Folder tree** — the full proposed directory structure with one-line purpose per folder. Include `Schemas/`, `Templates/`, and an `Instructions/` (or `Meta/`) folder alongside the domain folders.
+2. **Schemas table** — one row per note type: schema name, note_type, required observations, optional observations, status enum values.
+3. **Naming conventions** — title format per note type, date formats, status vocabularies.
+4. **Instruction notes** — the startup router plus one instruction note per domain (see `references/conventions.md` for anatomy).
+5. **The discipline rules** they'll live by — search before create, exact-casing paths, changelog rows, index updates, bidirectional links — each with a one-line "why".
+
+Walk through it, invite pushback, and iterate. Scale to their answers — but scaling means fewer folders, fewer indexes, and fewer *required* fields, never dropping schemas or observations (see the non-negotiables above). Get an explicit "yes, build it" before Phase 3.
+
+## Phase 3 — Build
+
+Build in this order — later items reference earlier ones:
+
+1. **Schemas** → `Schemas/` folder, one note per type, `validation: warn`. Syntax in `references/schema-guide.md`.
+2. **Templates** → `Templates/`, one per note type, matching the schema exactly.
+3. **Instruction notes** → per-domain rules notes, then the **startup router** last (it links everything). Full anatomy and a worked example in `references/conventions.md`.
+4. **Index notes** → one per domain that needs one (tables of contents; not every domain does).
+5. **Migrate existing notes** *(restructure path)* → execute the approved old→new mapping from Phase 2 before seeding anything: move each existing note to its new home, set its note type, add the observations its schema requires, and update indexes as notes land. Archive what doesn't fit — never delete. Phase 3 is not done while anything still sits unorganized at the root.
+6. **Seed notes** → 2–3 REAL notes per domain using the examples collected in Phase 1. Never seed with placeholder data — real notes teach the format and are immediately useful; fake ones are noise the user must delete.
+7. **Validate** → run `schema_validate` on the seed notes AND any migrated notes; fix anything it flags. Read back the router and one instruction note to confirm links resolve.
+
+Follow the write discipline in `references/conventions.md` throughout — most importantly: search before creating anything, use exact folder casing, and watch write results for duplicate-suffixed permalinks (`-1`, `-2`).
+
+## Phase 4 — Assistant setup
+
+The system only works if the assistant loads the rules every session — otherwise the user is the only one who knows the conventions, which defeats the point.
+
+Read `references/assistant-setup.md` and set up (or hand the user exact text for) a **persistent instruction stub**: a short block in whatever always-loaded mechanism their platform provides (project instructions, custom instructions, system prompt, agent context file) that says, in essence: *"Before any knowledge-base work, read the startup router note in project X and follow its dispatch table."*
+
+Identify what mechanism YOUR platform offers and give concrete, platform-specific steps. If you cannot determine the platform, present the generic stub and the common placements from the reference file. End Phase 4 with the verification test described there (simulate a fresh session; confirm the router gets loaded and followed).
+
+## Phase 5 — Teach
+
+Teach by doing, with their data — not by lecturing. Run short exercises:
+
+1. **Capture** — "Tell me something that came up today" → create the note together, narrating the schema fields and observations as you fill them.
+2. **Retrieve** — have them ask for something ("what's on my plate?", "what do I know about X?") → demonstrate `search_notes` and reading via `memory://` links; explain title-search vs semantic search for names.
+3. **Update** — change a status, append an observation, add a changelog row — showing `edit_note` for targeted changes vs full overwrites.
+4. **Connect** — add a relation between two of their notes; show how `build_context` walks the graph.
+
+Then write a **cheat-sheet note** into their KB (`Instructions/` folder): the phrases they can say, what happens for each, and the core rules. This note is theirs — written for a human, not an assistant.
+
+## Phase 6 — Grow
+
+Close the onboarding by opening doors:
+
+- **Suggest 2–3 specific expansions** drawn from their deferred Phase 1 domains or natural neighbors of what they built (built tasks → suggest meetings; built finances → suggest renewals calendar; built research → suggest a reading log). Frame each as "when you're ready" — never build unrequested.
+- **Maintenance cadence** — suggest a periodic (weekly/monthly) review: `schema_diff` for drift, scan for duplicate or orphaned notes, prune stale statuses. If their platform supports scheduled/recurring tasks, offer to set this up.
+- **Evolution rule** — when a convention starts to chafe, change the instruction note (with a changelog row), don't silently deviate. The system stays self-describing only if the rules in it stay true.
+
+## Reference files
+
+| File | Read when |
+|:--|:--|
+| `references/conventions.md` | Before Phase 2. Startup router anatomy, instruction notes, changelogs, indexes, linking, write discipline, failure modes. |
+| `references/schema-guide.md` | Before Phase 2. Picoschema syntax, observations, relations, validation workflow. |
+| `references/domain-playbooks.md` | Phase 1–2, for each domain the user picks. Starter folders, schemas, naming, example notes per domain. |
+| `references/assistant-setup.md` | Phase 4. Persistent-instruction stub patterns per platform + verification test. |
+
+## Related Skills
+
+When companion skills are installed alongside this one, hand off instead of duplicating: **memory-notes** and **memory-schema** for note-writing and schema mechanics, **memory-tasks** for agent-side task tracking, **memory-lifecycle** for archival on the restructure path, **memory-defrag** / **memory-curate** / **memory-reflect** for the Phase 6 maintenance cadence, and **memory-continue** for resuming work from the graph — a natural first thing to teach after onboarding.
diff --git a/skills/memory-onboarding/evals/evals.json b/skills/memory-onboarding/evals/evals.json
new file mode 100644
index 000000000..c42168960
--- /dev/null
+++ b/skills/memory-onboarding/evals/evals.json
@@ -0,0 +1,29 @@
+{
+ "skill_name": "memory-onboarding",
+ "evals": [
+ {
+ "id": 0,
+ "eval_name": "no-idea-newbie",
+ "prompt": "I just connected Basic Memory to my assistant but honestly I have no idea what to actually use it for. People talk about 'second brains' but I don't know where to start. Can you help me get set up with something useful?",
+ "persona": "Sam, marketing coordinator. When offered suggestions, is drawn to: tasks (loses track of follow-ups) and subscriptions (pays for services they forgot about). Light volume — maybe 5-10 notes a week. Real examples when asked: task 'send the Q3 sponsorship deck to Rivera Media by Friday'; subscriptions: Netflix $15.49/mo, Adobe CC $59.99/mo renews annually in March, a gym membership $40/mo they keep meaning to cancel. Uses a chat assistant that supports projects with custom instructions. Never tried a note system before.",
+ "expected_output": "Interview → blueprint scaled small (2 domains) → built KB with Task + Subscription schemas, Task Board and Subscriptions Index, instruction notes + startup router, seed notes using Sam's real examples, assistant stub for project instructions, cheat-sheet.",
+ "files": []
+ },
+ {
+ "id": 1,
+ "eval_name": "freelance-photographer",
+ "prompt": "I want to use Basic Memory to run my freelance photography business — keeping track of my clients, upcoming shoots, what I've invoiced, and all my camera gear. Set me up with a good structure that my AI assistant can work with consistently.",
+ "persona": "Priya, wedding/portrait photographer. ~3 shoots a month. Clients: couples and a few corporate accounts. Wants per-client history. Invoices tracked simply: date, client, amount, paid/unpaid (accounting itself stays in her accounting software). Gear: 2 bodies (Canon R5 serial 0482xx, R6), 6 lenses, lighting kit — wants serials and purchase dates for insurance. Real examples: upcoming shoot 'Chen-Okafor wedding Sept 12 at Maple Grove Estate, second shooter booked'; unpaid invoice 'Hartley corporate headshots $850 sent July 2'. Uses a desktop AI app with per-project custom instructions.",
+ "expected_output": "Blueprint with Clients/People, Shoots (project-like), Invoices (finance playbook adapted: no secrets, amounts from user only), Gear (assets playbook: serials, insurance index), schemas + router + instruction notes, seeds from her real examples, stub for project instructions, bidirectional client↔shoot links.",
+ "files": []
+ },
+ {
+ "id": 2,
+ "eval_name": "messy-restructure",
+ "prompt": "My Basic Memory project is a mess — like 30 random notes dumped in the root folder, no organization, half of them are ideas for my blog and the rest are random todos. I want an actual system: task tracking, and proper research organization for my blog posts. And I want my assistant to actually follow the same rules every session instead of doing something different each time.",
+ "persona": "Jordan, writes a woodworking blog. Existing project 'main' has ~30 root-level notes with inconsistent naming (some lowercase, some dated, e.g. 'bandsaw jig idea', '2026-05-02 misc', 'todo dump', 'japanese joinery links'). Wants: tasks, and blog research (topic → sources → draft outline). Blog posts monthly. Real examples: active research topic 'hand-cut dovetails vs router jigs' with 4 saved links; task 'edit the shop-tour video by end of July'. Uses a CLI assistant that auto-loads a context file from the home directory.",
+ "expected_output": "Restructure path: assess existing notes, propose old→new mapping BEFORE moving, build tasks + research structure (topic hubs), schemas + router with known-failure-modes seeded from their actual mess (casing, duplicates), stub written for an agent context file, verification test described.",
+ "files": []
+ }
+ ]
+}
diff --git a/skills/memory-onboarding/references/assistant-setup.md b/skills/memory-onboarding/references/assistant-setup.md
new file mode 100644
index 000000000..854b9aa49
--- /dev/null
+++ b/skills/memory-onboarding/references/assistant-setup.md
@@ -0,0 +1,64 @@
+# Assistant Setup — Loading Instructions Every Session
+
+The knowledge base is self-describing: its rules live in instruction notes inside it. But a fresh assistant session doesn't know those notes exist. This reference covers the last mile — a **persistent instruction stub** in whatever always-loaded mechanism the user's platform provides, pointing at the startup router.
+
+## The stub pattern
+
+The stub is deliberately tiny. It carries only:
+
+1. Which Basic Memory **project** to use (always, explicitly)
+2. The instruction to **read the startup router before any knowledge-base work** and follow its dispatch table
+3. The 3–5 rules that must hold **before** the router loads (because they govern the loading itself)
+
+Everything else — conventions, schemas, workflows, reference data — lives in the router and the notes it dispatches to. This keeps the always-loaded footprint small and means the user edits notes, not platform settings, when conventions change.
+
+### Stub template
+
+Adapt the wording; keep the shape:
+
+```
+You maintain my knowledge base in Basic Memory, project "{project-name}".
+
+Rules that apply before anything else:
+1. Every Basic Memory call (read, search, write, list) uses project "{project-name}" explicitly.
+2. At the start of every session, before any knowledge-base work, read the note
+ "Startup Router" (memory://instructions/startup-router) and follow its dispatch
+ table for the task at hand. If that reference doesn't resolve, search for the
+ note by title before doing anything else. Take no write actions until the
+ notes it lists are loaded.
+3. Folder paths use exact casing as given in the instruction notes.
+4. Before overwriting any existing note, read it in full first.
+5. When unsure where something belongs, ask me instead of guessing.
+```
+
+Rules 1, 3, 4 are in the stub rather than the router because they protect the system even if the router fails to load or has been corrupted.
+
+## Where the stub goes
+
+Determine what platform and mechanism **you** are running in, and give the user concrete steps for it. Common mechanisms, by shape rather than brand:
+
+| Mechanism shape | Typical examples | How to place the stub |
+|:--|:--|:--|
+| **Project-level instructions** | A "project" or "space" in a chat app with a custom-instructions field | Paste the stub into the project instructions. Best option when available — scoped, persistent, and editable. |
+| **Global custom instructions / personalization** | Account-level "how should I respond" settings | Works, but applies to every conversation — wrap the stub in "When I ask about my knowledge base: ...". |
+| **Agent context files** | A markdown file the agent auto-loads from the working directory or home directory (many CLI/desktop agents support one) | Add the stub as a section of that file. |
+| **System prompt** | Self-hosted assistants, API integrations, custom apps | Prepend the stub to the system prompt. |
+| **No persistent mechanism** | Bare chat with MCP tools | Fall back: create a note titled something unmissable like `START HERE — Assistant Instructions` at the KB root, and teach the user to open each session with "read Start Here first". Weakest option; say so honestly. |
+
+If you can't determine the platform, show the stub and this table and let the user place it. If the user runs the KB from multiple assistants/platforms (desktop app + CLI + phone), place the stub in each — the router being shared is exactly what keeps them consistent.
+
+## The router reference must be durable
+
+Inside the stub, give the router's **title and `memory://` path together, with a title-search fallback** — never a raw permalink string copied from a tool result. No single identifier is unconditionally durable: a retitled note breaks title lookups, a recreated note derives a fresh permalink, and a moved note's path changes when `update_permalinks_on_move` is enabled (it defaults to off). The stub is the one piece of the system that isn't a note and won't be caught by note-level maintenance, so it carries both identifiers plus the fallback — that combination self-heals when any one of them goes stale.
+
+## Verification test
+
+Never call Phase 4 done without testing. With the user:
+
+1. **Simulate a fresh session** — new conversation on their platform (or in this session, deliberately act as if starting cold).
+2. Give a natural task from one of their domains: "add a task: call the dentist Tuesday."
+3. **Watch the order of operations.** Pass = the assistant reads the router, loads the dispatched instruction note(s), THEN writes — correct folder, correct schema fields, correct naming. Fail = it writes first or freelances the format.
+4. If it fails: is the stub actually saved? Does the router reference resolve (test with `read_note`)? Is the "before any knowledge-base work" wording strong enough? Fix and re-test.
+5. Also verify the **escape hatch**: ask something ambiguous ("save this somewhere") and confirm the assistant asks rather than guesses.
+
+Leave the user with this framing: the stub + router is the system's ignition. If future sessions ever start behaving inconsistently, the first diagnostic is always "did the router get loaded?"
diff --git a/skills/memory-onboarding/references/conventions.md b/skills/memory-onboarding/references/conventions.md
new file mode 100644
index 000000000..4e5b768cb
--- /dev/null
+++ b/skills/memory-onboarding/references/conventions.md
@@ -0,0 +1,118 @@
+# Conventions & Discipline
+
+The structural patterns that keep a Basic Memory knowledge base coherent as it grows. These are defaults, not laws — but each exists because its absence causes a specific, recurring failure. When you relax one for a light-use setup, tell the user what they're trading away.
+
+## Contents
+
+1. [The startup router](#the-startup-router)
+2. [Instruction notes](#instruction-notes)
+3. [Changelog tables](#changelog-tables)
+4. [Index notes](#index-notes)
+5. [Linking discipline](#linking-discipline)
+6. [Write discipline](#write-discipline)
+7. [Known failure modes](#known-failure-modes)
+
+---
+
+## The startup router
+
+One note — suggested location `Instructions/Startup Router` — that any assistant reads at the start of every session, before doing any knowledge-base work. It is the single entry point to the whole system. It contains:
+
+1. **A read-me-first banner** — "Read this note at the start of every session, before any task work."
+2. **Non-negotiable rules** — the handful of rules that apply to every task type and can't be overridden by anything else (e.g. "always search before creating", "always pass the project name explicitly"). Keep this list short — five to eight items. A rule that only matters for one domain belongs in that domain's instruction note instead.
+3. **A dispatch table** — task type → which notes to load, in order:
+
+ | Task type | Load in order |
+ |:--|:--|
+ | Task / project work | 1. `memory://instructions/task-instructions` · 2. `[[Task Board]]` |
+ | New contact / person update | 1. `memory://instructions/people-instructions` |
+ | Expense / subscription | 1. `memory://instructions/finance-instructions` · 2. `[[Subscriptions Index]]` |
+ | Anything else / ambiguous | load all instruction notes |
+
+4. **Known failure modes** — a running list of documented mistakes to check before writing (see below).
+5. **Canonical reference data** — if the system has a roster-like table (accounts, categories, family members, clients), keep the ONE canonical copy here and make other notes point to it. Duplicated rosters drift apart; nobody notices until something routes to the wrong place.
+
+**Why a router instead of one big rules note:** context is finite. The router is small and always loaded; everything else loads only when the task needs it. It also gives the system one place to grow — a new domain is a new dispatch row, not a rewrite.
+
+The router itself is a note, so it gets a changelog table and observations like any other. When the user changes a convention, the change lands here or in a domain instruction note — with a changelog row — so the system stays self-describing.
+
+## Instruction notes
+
+One note per domain (`Instructions/Task Instructions`, `Instructions/Finance Instructions`, ...) holding everything an assistant needs to work in that domain:
+
+- **Scope** — what this note covers and what it doesn't ("for vendor stuff, see [[Vendor Instructions]]")
+- **Folder map** — where each note type lives, with exact casing
+- **Schemas in play** — table of note types, their schema notes, and required observations
+- **Naming conventions** — title formats with examples, date formats, status vocabularies
+- **Workflows** — step-by-step for the recurring operations ("closing a task: 1. set `[status] done` 2. add close date 3. append row to [[Task Board]]")
+- **Domain-specific rules** — anything true here that isn't true globally
+
+Write instruction notes for a reader with zero context: the assistant loading it next month is effectively a stranger. Explain *why* behind rules that aren't obvious — an assistant that understands the reason applies the rule correctly in situations the rule didn't anticipate.
+
+## Changelog tables
+
+Every structural or long-lived note carries exactly one changelog table, immediately below the title:
+
+```markdown
+| Notes | Modification Date | Approved By |
+|:--|:--|:--|
+| Initial Document | July 12, 2026 | {user's name} |
+| Added renewal-date field to all subscription rows | August 3, 2026 | {user's name} |
+```
+
+Rules:
+- **Append, never edit.** Existing rows are history; new rows record change.
+- **One table per note.** Before overwriting any existing note, read the full note first, carry the existing changelog forward verbatim, and append your row. If you ever find two tables, merge them into one at the top before writing.
+- **Consistent date format** — pick one (`Month D, YYYY` works well) and use it everywhere.
+
+Why: an assistant (or the user) reading a note months later can see what changed, when, and on whose authority — without any external version control. It also forces the read-before-overwrite habit that prevents accidental content loss.
+
+For a light setup, changelogs on *instruction notes, schemas, and indexes* are the non-negotiable core; changelogs on every individual content note are optional.
+
+## Index notes
+
+An index is a note containing a table of contents for one domain — one row per note, with wiki-links and a few key columns (status, date, owner):
+
+```markdown
+# Task Board
+
+| Task | Status | Due |
+|:--|:--|:--|
+| [[Fix gutter downspout]] | in-progress | July 20, 2026 |
+| [[Renew car registration]] | open | August 1, 2026 |
+```
+
+Rules:
+- **Update the index as part of any change to its members** — a stale index is worse than none, because it gets trusted.
+- **Full overwrite, not section edits.** When updating an index with `write_note`, always rewrite the whole note (read → modify → overwrite). Piecemeal section edits on tables are easy to get wrong — duplicated or mis-scoped sections — while a full overwrite is deterministic.
+- Not every domain needs one. Indexes earn their keep where the user will ask "show me all X with status Y" or wants a glanceable board. Journals and reference notes usually don't need one — search covers them.
+
+## Linking discipline
+
+- **Bidirectional links for paired entities.** If a task note links its project, the project note links its tasks. If a device links its owner, the owner links the device. One-directional links rot: graph traversal from the unlinked side finds nothing. Make "both directions, always" a rule for whichever entity pairs the user's system has.
+- **Relations sections for typed links, inline wiki-links for prose.** `- part_of [[Kitchen Renovation]]` in Relations; "discussed with [[Dana Reyes]]" in the body. Both create graph edges.
+- **Reference notes by title or `memory://` path — never by raw permalink strings.** A permalink is derived from the note's title and location, so a note that gets recreated or re-derived ends up with a different one and hardcoded strings silently break. `[[Title]]` resolves by title and `memory://` URLs match on path, so both survive reorganization.
+- **Link targets may not exist yet.** `[[Future Note]]` is valid and resolves when the note is created — use this to sketch structure ahead of content.
+
+## Write discipline
+
+The habits that prevent 90% of knowledge-base corruption:
+
+1. **Search before create.** Always search (try 2–3 query variations: full name, abbreviation, keywords) before writing a new note. Duplicates fragment the graph. If the entity exists, `edit_note` it instead. For people and other proper nouns, use **title search** — semantic search is unreliable for names.
+2. **Exact casing, exact paths.** `Tasks/` and `tasks/` are different directories. Take folder paths from the instruction note, character for character. If a write would create a new top-level folder you didn't plan, that's a casing error — stop and fix.
+3. **Explicit project on every call.** In multi-project setups, pass the project explicitly on every read, search, and write. Writes to the wrong project are invisible until much later.
+4. **Read before overwrite.** Full-note overwrites must start from the current content — never reconstruct a note from memory of what it contained.
+5. **Watch write results.** If a write returns a permalink ending in `-1` or `-2`, you just created a duplicate: delete it and re-write the original with overwrite semantics.
+6. **Prefer targeted edits.** `edit_note` (append an observation, find-and-replace a status) over full overwrites wherever possible — smaller blast radius.
+
+## Known failure modes
+
+Keep a "Known Failure Modes" section in the startup router and **add to it whenever a mistake happens twice**. Documented mistakes stop recurring; undocumented ones don't. Seed it during onboarding with the universal ones:
+
+- Duplicate notes from skipping search-before-create (or from name-search using semantic instead of title matching)
+- Wrong-casing paths creating parallel folder trees
+- Piecemeal section edits mangling index tables (duplicated or mis-scoped sections)
+- Second changelog table created by overwriting without reading first
+- Writes landing in the wrong project when project isn't passed explicitly
+
+Each entry: the mistake, how to recognize it, what to do instead. This list is the system's immune memory — it's often the highest-value section in the whole knowledge base.
diff --git a/skills/memory-onboarding/references/domain-playbooks.md b/skills/memory-onboarding/references/domain-playbooks.md
new file mode 100644
index 000000000..907ac2c85
--- /dev/null
+++ b/skills/memory-onboarding/references/domain-playbooks.md
@@ -0,0 +1,159 @@
+# Domain Playbooks
+
+Starter kits for the common things people track. Each gives folders, a schema sketch, naming, an index decision, and expansion ideas. These are starting points — adapt every one to the user's Phase 1 answers rather than installing verbatim. Statuses, folder names, and required fields should use the user's own vocabulary where they have one.
+
+Every domain also gets: an instruction note (`Instructions/{Domain} Instructions`), a row in the startup router's dispatch table, and templates for its note types.
+
+## Contents
+
+1. [Tasks & projects](#tasks--projects)
+2. [Notes & journal](#notes--journal)
+3. [People & contacts](#people--contacts)
+4. [Research](#research)
+5. [Finances](#finances)
+6. [Procedures](#procedures)
+7. [Health & habits](#health--habits)
+8. [Assets](#assets)
+
+---
+
+## Tasks & projects
+
+```
+Tasks/
+├── Task Board.md ← index: open/in-progress tasks
+└── {task notes}
+Projects/
+├── {Project Name}/ ← one folder per active multi-step project
+│ └── {Project Name}.md ← project note; links its tasks
+```
+
+- **Task schema:** `status(enum): [open, in-progress, blocked, done]` · `due?` · `priority?(enum)` · `project?: Project`
+- **Project schema:** `status(enum): [active, paused, done]` · `goal` · `target_date?`
+- **Naming:** tasks get short imperative titles (`Renew car registration`); completed tasks can be retitled with a date prefix (`2026-07-12 — Renew car registration`) when archived, so archives sort chronologically.
+- **Index:** yes — the Task Board is usually the single most-used note in the system. Open items only; done tasks drop off the board (search finds them).
+- **Bidirectional rule:** task ↔ project, both directions. The `project?: Project` field is a relation field — satisfied by `- project [[Project Name]]` in the task's Relations (the relation type must match the field name for validation).
+- **Key workflow to document:** closing a task (set status, add close date, update board, move to archive folder if using one).
+- **Expansions:** meeting notes with action items that become tasks; a weekly-review note; recurring-task conventions.
+
+## Notes & journal
+
+```
+Journal/
+└── {YYYY-MM-DD}.md ← one note per day
+Notes/
+└── {topic notes} ← ideas, things learned, free-form
+```
+
+- **Journal Entry schema (keep it tiny — one required field):** `date` · `mood?(enum)` · `highlight?`. Even the loosest domain gets a schema and observations — but here the observation load is deliberately one line (`- [date] 2026-07-12`, plus `[highlight]`/`[idea]`/`[mood]` when they apply), so capture stays frictionless.
+- **Note schema (topic notes):** `note_type?(enum): [idea, reference, learning]` — one optional field; the requirement is simply that every note carries at least one observation (`[idea]`, `[source]`, `[lesson]`...).
+- **Naming:** `YYYY-MM-DD` for journal (sorts itself); descriptive titles for topic notes.
+- **Index:** no. Date-named journals self-organize; topic notes are found by search.
+- **The one convention that matters:** when a journal entry mentions a person, project, or topic that has (or deserves) a note, wiki-link it. Journals become the connective tissue of the graph.
+- **Expansions:** weekly reflection summarizing the week's entries; automatic extraction of `[idea]` observations into topic notes.
+
+## People & contacts
+
+```
+People/
+└── {Full Name}.md ← one note per person
+```
+
+- **Schema:** `relationship?(enum): [family, friend, coworker, professional, acquaintance]` · `email?` · `phone?` · `company?` · `last_contact?`
+- **Naming:** full name, consistently — `Dana Reyes`, never `dana` in one note and `Dana R.` in another. Titles are graph identifiers.
+- **Index:** optional — useful if the user wants a follow-up board (`last_contact` older than N months).
+- **Critical rule:** ALWAYS title-search (full name, then last name) before creating a person note — people are the most-duplicated entity type, and semantic search misses names.
+- **Body guidance:** this is where prose shines — how they met, what they care about, gift ideas, kids' names. Observations for the queryable bits (`- [birthday] March 12`).
+- **Expansions:** interaction log (`- [contact] July 12, 2026 — coffee, discussed job change` appended per touch); linking people to meetings, projects, gifts.
+
+## Research
+
+```
+Research/
+├── {Topic}/
+│ ├── {Topic}.md ← topic hub: question, current understanding, links to sources
+│ └── {source notes} ← one note per significant source
+```
+
+- **Topic schema:** `status(enum): [active, parked, concluded]` · `question` (what they're trying to answer)
+- **Source schema:** `source_type(enum): [article, paper, video, book, conversation]` · `url?` · `date_consumed?`
+- **Naming:** topic hubs by topic name; sources by title of the source.
+- **Index:** the topic hub IS the index for its sources.
+- **Key conventions:** every source note ends with `- part_of [[Topic]]`; the hub's "current understanding" section gets rewritten (with changelog row) as understanding evolves — the hub is a living synthesis, not an append-only log.
+- **Expansions:** a reading queue; `[claim]`/`[evidence]`/`[contradiction]` observation categories for contested topics; concluded-topic summaries.
+
+## Finances
+
+```
+Finances/
+├── Subscriptions Index.md ← index: every recurring charge, cost, renewal date
+├── Subscriptions/
+│ └── {Service}.md ← one note per subscription/recurring bill
+├── Accounts/
+│ └── {Account}.md ← one note per account (no credentials — see below)
+└── Records/
+ └── {YYYY-MM-DD} — {Description}.md ← one-off: big purchases, tax docs, claims
+```
+
+- **Subscription schema:** `cost` · `billing_cycle(enum): [monthly, annual, quarterly]` · `renewal_date` · `payment_method?` · `status(enum): [active, cancelled, trial]`
+- **Naming:** records get `{YYYY-MM-DD} — {Description}`, dated by the document date, not the filing date.
+- **Index:** yes — the Subscriptions Index (name, cost, cycle, renewal, method) is the payoff note: total monthly spend at a glance, upcoming renewals visible.
+- **Two hard rules for the instruction note:** (1) **no secrets ever** — no account numbers beyond last-4, no passwords, no full card numbers; notes are plaintext markdown. (2) **amounts and payment methods come from the user or a document — never inferred or guessed.**
+- **Expansions:** annual-cost review workflow; warranty/receipt records linking to Assets; a renewals-this-month recurring check.
+
+## Procedures
+
+```
+Procedures/
+├── {area}/ ← optional grouping: Home/, Tech/, Work/
+└── {Procedure Name}.md ← one note per how-to
+```
+
+- **Schema:** `procedure_type(enum): [how-to, troubleshooting, checklist, reference]` · `applies_to?` · `last_verified?`
+- **Naming:** descriptive, search-first titles — the phrase the user would actually say (`Reset the water softener`, not `Softener maintenance procedure v2`).
+- **Index:** optional per area once a folder exceeds ~15 notes.
+- **Key conventions:** numbered steps; prerequisites up front; `last_verified` observation updated whenever the procedure is confirmed still-correct — and when a procedure is used and found wrong, fixing the note is part of finishing the task.
+- **Expansions:** seasonal checklists; linking procedures to the assets they service.
+
+## Health & habits
+
+```
+Health/
+├── Log/
+│ └── {YYYY-MM-DD} — {type}.md ← workouts, symptoms, appointments
+└── {condition/goal notes} ← ongoing threads: an injury, a training goal
+```
+
+- **Log schema:** `entry_type(enum): [workout, symptom, appointment, measurement]` · `date`
+- **Index:** optional — a current-goals note works better than a full log index.
+- **Key conventions:** log entries are quick and low-friction (two observations and a sentence beats an unfilled template); ongoing threads link their log entries so `build_context` on "left knee" pulls the full history.
+- **Sensitivity note for the instruction file:** health data in plaintext markdown — the user should decide consciously what level of detail they're comfortable storing, and where the project syncs to.
+- **Expansions:** habit streaks; pre-appointment summaries generated from the log.
+
+## Assets
+
+```
+Assets/
+├── Asset Index.md ← index: every asset, location, value band
+└── {Asset Name}.md ← one note per significant item
+```
+
+- **Schema:** `asset_type(enum): [electronics, appliance, vehicle, furniture, tool, other]` · `serial_number?` · `purchase_date?` · `purchase_price?` · `warranty_until?` · `location?` · `status(enum): [in-use, stored, loaned, sold, disposed]`
+- **Naming:** `{Make} {Model}` or a distinguishing name (`Garage Freezer`); serial in observations, not the title.
+- **Index:** yes — this is the insurance-claim / "where is the..." note.
+- **Bidirectional rule:** if assets are assigned to people (family laptops), asset ↔ person, both directions.
+- **Expansions:** warranty-expiry checks; maintenance logs linking to Procedures; purchase records linking to Finances.
+
+---
+
+## Combining domains
+
+Domains compound through relations — mention these links when the user picks the pairs:
+
+- Tasks ↔ People (`waiting_on [[Dana Reyes]]`) · Tasks ↔ Projects
+- Finances ↔ Assets (purchase records ↔ asset notes)
+- Procedures ↔ Assets (`services [[Garage Freezer]]`)
+- Journal → everything (daily entries wiki-link whatever they mention)
+- Research ↔ Notes (ideas graduate into research topics)
+
+The cross-domain links are where a knowledge *graph* starts beating a folder of documents — surface one concrete example using the user's own notes during Phase 5.
diff --git a/skills/memory-onboarding/references/schema-guide.md b/skills/memory-onboarding/references/schema-guide.md
new file mode 100644
index 000000000..743a06e95
--- /dev/null
+++ b/skills/memory-onboarding/references/schema-guide.md
@@ -0,0 +1,136 @@
+# Schemas, Observations & Relations
+
+How to make notes structured enough to query and consistent enough to trust. This is the mechanical core of the system the onboarding builds.
+
+## Contents
+
+1. [Note anatomy](#note-anatomy)
+2. [Observations](#observations)
+3. [Relations](#relations)
+4. [Picoschema syntax](#picoschema-syntax)
+5. [Creating a schema](#creating-a-schema)
+6. [Validation & drift](#validation--drift)
+7. [Design guidelines](#design-guidelines)
+
+---
+
+## Note anatomy
+
+Every well-formed note has: frontmatter (title, type, tags — generated by `write_note` from its parameters), a **body** of substantive prose, an **Observations** section, and a **Relations** section.
+
+```markdown
+# Fix Gutter Downspout
+
+| Notes | Modification Date | Approved By |
+|:--|:--|:--|
+| Initial Document | July 12, 2026 | Dana Reyes |
+
+Back downspout detached during the June storm; water is pooling against the
+foundation on the north side. Needs a bracket and probably a new elbow section.
+Hardware store trip required — measure the downspout diameter first (looks like 3x4).
+
+## Observations
+- [status] open
+- [priority] high
+- [due] July 20, 2026
+- [context] home-maintenance
+
+## Relations
+- part_of [[House Projects]]
+- relates_to [[June Storm Damage]]
+```
+
+**Write the body generously.** Search retrieves chunks from note bodies, so richer prose makes notes *more* discoverable, not less. Prose carries meaning; observations carry precision. A note that is only bullet-point observations reads like a database row and loses the context that makes it useful a year later.
+
+## Observations
+
+Categorized, atomic facts: `- [category] content #optional-tag`
+
+- Categories are **free-form** — `[decision]`, `[status]`, `[symptom]`, `[cost]`, `[lesson]` — whatever fits. Consistency within a note type is what matters (and is what schemas enforce).
+- **One fact per line.** `- [decision] Use JWT with 15-minute expiry` not a paragraph of three decisions.
+- **Categories are queryable** — searching by category finds every note carrying that kind of fact.
+- Tags add cross-cutting findability: `- [risk] no SLA on the API #vendor #reliability`.
+
+In this system, observations do double duty: they're facts, and they're the **fields** schemas validate — for scalar, enum, and array fields. A Task schema requiring `status` means every task note carries `- [status] ...` as an observation. (Entity-reference fields validate against relations instead — see below.)
+
+## Relations
+
+Typed, directional links: `- relation_type [[Target Note Title]]`
+
+- relation_type is a descriptive snake_case verb: `part_of`, `depends_on`, `assigned_to`, `replaces`, `paid_by`. Invent freely.
+- Wiki-links in body prose also create edges (untyped `references`). Use the Relations section for the structural links, prose links for narrative mentions.
+- Targets may not exist yet — forward links resolve on creation.
+- `build_context` on a `memory://` URL walks these edges to assemble connected context — this is what makes the graph worth building.
+
+## Picoschema syntax
+
+Schemas are notes (conventionally in a `Schemas/` folder) whose frontmatter metadata defines fields:
+
+```yaml
+schema:
+ status(enum): "[open, in-progress, blocked, done], current state"
+ due?: string, due date if any (Month D, YYYY)
+ priority?(enum): "[low, medium, high], urgency"
+ project?: Project, parent project note
+ steps?(array): string, ordered sub-steps
+```
+
+- Types: `string`, `integer`, `number`, `boolean`
+- `?` suffix = optional field
+- `(enum)` = fixed value list — use for anything status-like
+- `(array)` = list field
+- A capitalized type name (`Person`, `Project`) makes it a **relation field**, validated against the note's Relations section (the relation type must equal the field name: `- project [[Target Note]]`) — it creates a graph edge, not an observation
+- Every field gets a comma-then-description: it's documentation the next assistant reads
+
+## Creating a schema
+
+```python
+write_note(
+ title="Task",
+ directory="Schemas",
+ note_type="schema",
+ metadata={
+ "entity": "Task",
+ "version": 1,
+ "schema": {
+ "status(enum)": "[open, in-progress, blocked, done], current state",
+ "due?": "string, due date (Month D, YYYY)",
+ "priority?(enum)": "[low, medium, high], urgency",
+ "project?": "Project, parent project"
+ },
+ "settings": {"validation": "warn"}
+ },
+ content="""# Task
+
+Schema for task notes. Tasks live in Tasks/, titled with a short imperative
+description. Status moves open → in-progress → done; blocked is a holding state.
+
+## Observations
+- [convention] Every task carries status as an observation
+- [convention] Done tasks get a close-date appended before archiving"""
+)
+```
+
+Key points:
+
+- **`validation: warn`, not `strict`** — the modes are `warn`, `strict`, and `off`. Warn logs findings without blocking anything; `strict` escalates the same findings to errors. Start every schema on warn — a new user fighting rejected writes will abandon the system. Move a schema to `strict` only if something automated consumes the notes and malformed ones break it.
+- **Content notes declare their type** via `note_type` matching the schema's entity (e.g. `note_type="task"`).
+- **Scalar, enum, and array fields must appear as observations** in the note body (`- [status] open`) to satisfy validation — frontmatter-only values don't count. Putting them in both places gives you metadata search *and* schema validation. **Entity-reference fields are different**: they're satisfied by a relation, not an observation — a line in `## Relations` whose type matches the field name (`project?: Project` is satisfied by `- project [[Kitchen Renovation]]`).
+- **Version in metadata** — bump on breaking changes (new required field, removed field, type change). Additive optional fields don't need a bump.
+
+## Validation & drift
+
+- `schema_validate(note_type="task")` — check all notes of a type, or a single note via `identifier=`. It reports **missing required fields** and **invalid enum values** — that's the whole contract. Fields the schema doesn't declare are only counted as informational "unmatched" metadata (schemas are a subset, not a straitjacket), and scalar values are not type-checked, so a clean validate doesn't guarantee more than required-field presence and enum conformance. Use `schema_diff` to surface undeclared fields.
+- `schema_diff(note_type="task")` — finds drift: fields notes use that the schema doesn't define (candidates to add as optional), and schema fields nobody uses (candidates to drop).
+- `schema_infer(note_type="task")` — when notes of a type already exist without a schema, infer one from their actual structure instead of designing from scratch.
+
+Evolution loop: `schema_diff` → edit the schema note (append changelog row, bump version if breaking) → `schema_validate` → fix outliers. Suggest the user run this monthly-ish once the system has real volume.
+
+## Design guidelines
+
+- **Every note type gets a schema; every note gets observations.** These two are not scale-dependent. A domain the user wants "loose" gets a one-field schema and a one-observation minimum, not an exemption — unstructured notes can't be queried, validated, or trusted by a future assistant, and retrofitting structure later is far more expensive than carrying one line now.
+- **2–4 required fields, everything else optional.** Required fields are a tax on every note; each one must earn its place. Status almost always earns it. `notes_from_that_one_meeting` does not.
+- **Enums for anything status-like.** Free-text statuses drift (`done`, `Done`, `finished`, `complete ✓`) and become unqueryable. Define the vocabulary in the schema and list it in the domain instruction note.
+- **Schema per entity type, not per folder.** A `Person` schema serves contacts, family, and coworkers even if they live in different folders.
+- **Don't over-constrain.** A schema describes common structure; it is not a straitjacket. If the user fights a field during the first week, make it optional or delete it.
+- **Schemas are documentation.** Even at `warn` with validation never run, the schema note tells the next assistant exactly what a conforming note looks like. Write field descriptions accordingly.