mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
feat(plugins): make setup focus load-bearing, seed schemas via metadata, add smoke test
- Focus question is now load-bearing: it drives an adaptive light folder-structure suggestion and is stored. The placement step branches learn (existing project with notes) vs suggest (new/empty project) instead of only learning. - Seed schema notes via the write_note `metadata` param instead of content frontmatter. The cloud write path silently coerces nested YAML to the string '[object Object]', corrupting schema/settings (basic-memory-cloud#1000); the metadata param round-trips correctly on both local and cloud. - Surface placementConventions + captureFolder in the SessionStart brief so the output style's "follow stored placement conventions" reflex has something to follow — previously written by setup but never shown to Claude (dead config). - Add a post-settings smoke test (run the hook's recall query, confirm routing) and a restart prompt gated on outputStyle in the close. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: phernandez <paul@basicmachines.co>
This commit is contained in:
committed by
Paul Hernandez
parent
4b6de80faa
commit
2ba1ca8722
@@ -109,6 +109,11 @@ default_prompt = (
|
||||
"Cite permalinks when referencing prior work."
|
||||
)
|
||||
recall_prompt = cfg.get("recallPrompt") or default_prompt
|
||||
# Placement guidance — surfaced in the brief below so the output style's "follow the
|
||||
# project's stored placement conventions" reflex has something concrete to follow.
|
||||
# Without this, setup writes them but they never reach Claude (dead config).
|
||||
placement_conventions = (cfg.get("placementConventions") or "").strip()
|
||||
capture_folder = (cfg.get("captureFolder") or "sessions").strip()
|
||||
|
||||
# --- Resolve the shared/team read set ---
|
||||
# secondaryProjects (read-only recall sources) + teamProjects keys (share targets,
|
||||
@@ -246,6 +251,19 @@ if shared_sections:
|
||||
if shared_capped:
|
||||
lines += ["", f"_(reading the first {MAX_SHARED} shared projects; more are configured.)_"]
|
||||
|
||||
# --- Where to write (placement guidance) ---
|
||||
# Trigger: a primaryProject is set (so capture is actually active — pre-compact and
|
||||
# proactive writes land somewhere intentional). Why: the output style tells Claude to
|
||||
# follow the project's placement conventions, but nothing else surfaces them.
|
||||
# Outcome: Claude sees the capture folder + any stored conventions, so writes land
|
||||
# where the user expects instead of being guesswork. Bounded — conventions are a
|
||||
# short string by design.
|
||||
if primary_project:
|
||||
placement = ["", "## Where to write", f"- Auto-capture and checkpoints go to `{capture_folder}/`."]
|
||||
if placement_conventions:
|
||||
placement.append(f"- Placement conventions: {placement_conventions}")
|
||||
lines += placement
|
||||
|
||||
# --- First-run / config nudges ---
|
||||
if not configured:
|
||||
lines += ["", setup_nudge]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: setup
|
||||
description: Set up the Basic Memory plugin for this project — a short guided interview that configures the project mapping, seeds note schemas, optionally learns the project's conventions, and enables capture reflexes. Use when the user runs /basic-memory:setup, says "set up basic memory", or asks to configure/bootstrap the plugin.
|
||||
description: Set up the Basic Memory plugin for this project — a short guided interview that configures the project mapping, seeds note schemas, learns or suggests placement conventions, and enables capture reflexes. Use when the user runs /basic-memory:setup, says "set up basic memory", or asks to configure/bootstrap the plugin.
|
||||
argument-hint: (no arguments — runs an interactive interview)
|
||||
---
|
||||
|
||||
@@ -32,8 +32,13 @@ it succeeds.
|
||||
|
||||
Ask only what you can't infer. Cover:
|
||||
|
||||
1. **Focus.** "What's this project mostly about — code, writing, research, planning,
|
||||
or a mix?" (Shapes folder suggestions later; one quick question.)
|
||||
1. **Focus / how you'll use it.** "What will this project mostly be — code/dev,
|
||||
research, writing, knowledge capture, planning, or a mix?" This answer is
|
||||
**load-bearing**, not small talk: it drives the folder structure you suggest
|
||||
(step 4) and is stored so the SessionStart brief can surface it, keeping capture
|
||||
matched to the use-case. Don't let it evaporate — if you infer it from context
|
||||
instead of asking, still say the use-case you assumed and the structure it
|
||||
implies, and let the user correct it in one word.
|
||||
|
||||
2. **Project mapping.** "Do you already have a Basic Memory project for this, or
|
||||
should I create one?"
|
||||
@@ -60,14 +65,23 @@ Ask only what you can't infer. Cover:
|
||||
Keep `primaryProject` a project the user owns for their *own* capture; team
|
||||
projects are for reading and deliberate sharing only.
|
||||
|
||||
4. **Learn conventions** (optional). "Want me to look at your existing notes and
|
||||
note your conventions so I place new notes consistently?" If yes, inspect the
|
||||
project: `list_directory` for the folder layout, sample a few notes per folder
|
||||
(and, where a folder holds recurring typed notes, you may run `schema_infer` to
|
||||
see their shape). Summarize what you find — folder-by-topic conventions, naming
|
||||
style, the observation categories they favor — into 3-6 short lines and store
|
||||
that string as `placementConventions`. Infer from their *real* notes; don't
|
||||
impose a structure.
|
||||
4. **Placement — learn or suggest** (depends on the project's state). The goal is a
|
||||
short `placementConventions` string (3-6 lines) telling you where new notes go.
|
||||
How you get it depends on whether the project already has notes:
|
||||
- **Existing project with notes** → *learn*. Inspect it: `list_directory` for the
|
||||
folder layout, sample a few notes per folder (and, where a folder holds
|
||||
recurring typed notes, you may run `schema_infer` to see their shape).
|
||||
Summarize the *real* conventions — folder-by-topic layout, naming style, the
|
||||
observation categories they favor. Infer from their actual notes; don't impose.
|
||||
- **New or empty project** → *suggest* (there's nothing to learn yet). Propose a
|
||||
**light** structure that fits the focus from step 1 — 3-5 optional top-level
|
||||
folders, no deep taxonomy — and be explicit that it's a starting point, not a
|
||||
scaffold: notes work fine without it and structure can stay emergent. Don't
|
||||
create empty folders; folders appear as notes land in them. Let the user edit
|
||||
or decline in one word.
|
||||
Either way, keep it short and store the result as `placementConventions`. The
|
||||
SessionStart brief surfaces it (alongside `captureFolder`), so this is what makes
|
||||
your captures land where the user expects — without it, placement is guesswork.
|
||||
|
||||
5. **Schemas.** "I'll add schemas for session checkpoints, decisions, and tasks so
|
||||
I can find them precisely later — okay?" (See "Seed the schemas" below.)
|
||||
@@ -99,12 +113,21 @@ For each one:
|
||||
(`search_notes` with `metadata_filters={"type": "schema"}`, or try
|
||||
`read_note("schemas/<name>")`). **If it exists, skip it** — never overwrite a
|
||||
schema the user may have customized.
|
||||
- Otherwise write it with `write_note`: `directory="schemas"`,
|
||||
`title` = the schema's title (Session / Decision / Task), `content` = the file's
|
||||
full contents (including its `---` frontmatter — Basic Memory merges that into the
|
||||
note's frontmatter, so the `type: schema` + `entity` + `schema` definition land
|
||||
intact and become resolvable by `schema_validate`), routed to `primaryProject`
|
||||
(pass it as `project`, or as `project_id` if it's an `external_id` UUID).
|
||||
- Otherwise write it with `write_note`, routed to `primaryProject` (pass it as
|
||||
`project`, or as `project_id` if it's an `external_id` UUID):
|
||||
- `directory="schemas"`, `note_type="schema"`, `title` = the schema's title
|
||||
(Session / Decision / Task).
|
||||
- `content` = the markdown **body only** — everything *after* the `---`
|
||||
frontmatter block (the `# Session` heading and the prose).
|
||||
- `metadata` = the schema's structured frontmatter as a **nested dict**: `entity`,
|
||||
`version`, the full `schema` map, and `settings` (keep its nested `frontmatter`,
|
||||
and pass enum values as JSON arrays, e.g. `["open","resumed","closed"]`).
|
||||
- **Do not** put the schema's `---` frontmatter inside `content`. On the cloud
|
||||
write path that nested YAML is silently coerced to the string `'[object Object]'`
|
||||
(basic-memory-cloud#1000), corrupting `schema`/`settings`. The `metadata` param
|
||||
round-trips correctly on both local and cloud. After seeding, verify one note
|
||||
with `read_note(..., output_format="json", include_frontmatter=true)` —
|
||||
`schema`/`settings` must come back as nested objects, not strings.
|
||||
|
||||
### 2. Install the shared skills (if the user opted in)
|
||||
Run, from the project root:
|
||||
@@ -130,7 +153,7 @@ Build the `basicMemory` block from the interview:
|
||||
"rememberFolder": "bm-remember",
|
||||
"recallTimeframe": "3d",
|
||||
"preCompactCapture": "extractive",
|
||||
"placementConventions": "<inferred summary, or null>",
|
||||
"placementConventions": "<learned or suggested summary, or null>",
|
||||
"teamProjects": {}
|
||||
},
|
||||
"outputStyle": "basic-memory"
|
||||
@@ -145,10 +168,36 @@ valid JSON.
|
||||
Writing the `basicMemory` block is also what stops the SessionStart hook's first-run
|
||||
nudge — the config's presence is the signal that setup has run.
|
||||
|
||||
### 4. Smoke-test the wiring
|
||||
Before you close, prove recall actually resolves — this catches a misnamed project,
|
||||
missing cloud credentials, or a ref that doesn't route, while the user is still here
|
||||
to fix it. Run the same structured query the SessionStart hook runs, via the CLI it
|
||||
uses (`basic-memory` / `bm` / `uvx basic-memory`):
|
||||
|
||||
- **Primary:** `… tool search-notes --type schema --page-size 5` against
|
||||
`primaryProject` — use `--project-id <uuid>` for a UUID, `--project <ref>`
|
||||
otherwise. It should return the three schemas you just seeded.
|
||||
- **One shared project** (only if `secondaryProjects` is non-empty): a
|
||||
`--type decision --status open` query against the first ref. It just needs to
|
||||
return *cleanly* — `0 results` is fine; an **error** means the ref doesn't route.
|
||||
|
||||
If a query errors, or the primary returns nothing, surface it and fix the project
|
||||
ref before closing — don't let the next session's brief come up empty.
|
||||
|
||||
## Close
|
||||
|
||||
Confirm what you did in a few lines: the project mapping, which schemas were seeded
|
||||
vs. already present, whether conventions were learned, and whether the output style
|
||||
is on. End with: *"Done — I'll use this from the next message. Run
|
||||
`/basic-memory:status` anytime to see what I'm tracking."* Note that the output
|
||||
style (if enabled) takes effect on the next session, since it's fixed at startup.
|
||||
vs. already present, whether placement was learned or suggested, the smoke-test
|
||||
result, and whether the output style is on.
|
||||
|
||||
Then handle activation based on the output style:
|
||||
- **Output style enabled** → it's fixed at session start, so the full capture
|
||||
reflexes only take effect next session. Prompt the user to **restart the session**
|
||||
(start a new Claude Code session) to activate them. Be precise so it doesn't read
|
||||
as "nothing works yet": recall is already live this session (the SessionStart
|
||||
hook's prompt ran), and the PreCompact checkpoint works now too — only the
|
||||
proactive-capture reflexes wait for the restart.
|
||||
- **Output style off** → no restart needed; the hooks already run.
|
||||
|
||||
End with: *"Done — I'll use this from the next message. Run `/basic-memory:status`
|
||||
anytime to see what I'm tracking."*
|
||||
|
||||
Reference in New Issue
Block a user