mirror of
https://github.com/basicmachines-co/basic-memory
synced 2026-06-21 13:47:35 +00:00
feat(skills): port useful retired plugin skills into the shared memory-* set
Following the evaluation on #866, the genuinely-useful behavior from the deleted Claude Code plugin skills is preserved as framework-agnostic shared skills (usable by any MCP agent — Claude Desktop, OpenClaw, etc.), instead of being lost in the v0.4 clean-break. The Claude Code plugin itself is unchanged — it deliberately relies on hooks + the output style for capture/recall and pulls these shared skills via /basic-memory:setup. New shared skills (ported from the deleted set, CC-specific glue stripped): - memory-curate (from knowledge-organize) — the real coverage gap: knowledge-GRAPH curation (orphan notes, relation suggestion, duplicate merge, tag/folder audit, hub notes, sparse-note enrichment). Distinct from memory-defrag, which is agent-memory-FILE hygiene. - memory-continue (from continue-conversation) — resume prior work by rebuilding context from the graph (build_context / recent_activity / search), timeframe table, resume playbooks. - memory-capture (from knowledge-capture) — synthesize a thread's current state into one note, rewriting in place via a thread_id key. The Claude-Code-specific session UUID is generalized to "any stable thread id your host exposes." Also completed memory-notes' edit reference (added prepend / replace_section to the two existing operations). Updated skills/README.md and skills/CLAUDE.md. `just package-check-skills` validates 13 skills. NOTE: skills/skills-lock.json is a generated artifact of the `npx skills` CLI (not used by Claude Code or OpenClaw) and should be regenerated once the set is final — not hand-edited here. 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
fc8ac86fa1
commit
877e52fd73
@@ -23,6 +23,9 @@ memory-lifecycle/SKILL.md # Entity status transitions and folder-based arc
|
||||
memory-ingest/SKILL.md # Process external input into structured entities
|
||||
memory-research/SKILL.md # Web research synthesized into Basic Memory entities
|
||||
memory-literary-analysis/SKILL.md # Literary analysis knowledge graph pipeline
|
||||
memory-curate/SKILL.md # Knowledge-graph curation: orphans, relations, tags, hub notes
|
||||
memory-continue/SKILL.md # Resume prior work by rebuilding context from the graph
|
||||
memory-capture/SKILL.md # Capture a thread's current state into one coherent note
|
||||
```
|
||||
|
||||
There is no code to compile — this is a pure markdown project. Run `just check`
|
||||
|
||||
@@ -17,13 +17,16 @@ Basic Memory provides the MCP server — tools like `write_note`, `search_notes`
|
||||
| **memory-tasks** | Structured task tracking that survives context compaction. Creates typed `Task` notes with steps, status, and context. | Multi-step work (3+ steps), anything that might outlast a context window, or after compaction to resume. |
|
||||
| **memory-schema** | Schema lifecycle management — discover unschemaed notes, infer schemas, create/edit definitions, validate, and detect drift. | When structured note types emerge (Task, Person, Meeting, etc.) and you want consistency. |
|
||||
| **memory-reflect** | Sleep-time memory reflection. Reviews recent conversations and daily notes, extracts insights, consolidates into long-term memory. Inspired by [sleep-time compute](https://www.letta.com/blog/sleep-time-compute). | Schedule via cron (1-2x daily), trigger from heartbeat, or run on demand. |
|
||||
| **memory-capture** | Capture the current state of a working thread into a single coherent note — synthesize where it landed, not an append-log. Re-captures rewrite the same note in place via a `thread_id` key. | Mid-thread or end-of-thread, when decisions, insights, or context are worth preserving. |
|
||||
| **memory-notes** | How to write well-structured notes — frontmatter, observations with semantic categories, relations with wiki-links, and best practices. | When creating or improving notes, or when you need a reference for the note format. |
|
||||
| **memory-metadata-search** | Structured metadata search — query notes by custom frontmatter fields using equality, range, array, and nested filters. | When finding notes by status, priority, confidence, or any custom YAML field. |
|
||||
| **memory-defrag** | Memory defragmentation — split bloated files, merge duplicates, remove stale information, restructure the hierarchy. | Run weekly/biweekly via cron, or on demand when memory feels messy. |
|
||||
| **memory-curate** | Knowledge-graph curation — find orphan notes and suggest links, propose typed relations, merge duplicates, audit tags and folders, build hub notes. | When organizing, connecting, or improving a knowledge base as notes accumulate. |
|
||||
| **memory-lifecycle** | Entity lifecycle management — status transitions through folder-based organization, archiving completed work. Core principle: archive, never delete. | When marking items complete, archiving old entities, or managing folder-based status workflows. |
|
||||
| **memory-ingest** | Process unstructured external input into structured entities. Parses meeting transcripts, conversation logs, and pasted documents. | When pasting a transcript, conversation log, or external document that should become structured knowledge. |
|
||||
| **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?" |
|
||||
|
||||
## Basic Memory Cloud
|
||||
|
||||
|
||||
@@ -0,0 +1,275 @@
|
||||
---
|
||||
name: memory-capture
|
||||
description: "Capture the current state of a working thread or conversation into a single coherent Basic Memory note — synthesize where it landed, don't append a log. On re-capture, rewrite the same note in place instead of duplicating. Use mid-thread or end-of-thread when decisions, insights, or context are worth preserving."
|
||||
---
|
||||
|
||||
# Memory Capture
|
||||
|
||||
Capture the gist of a working thread — the decisions made, insights surfaced, and context built — into a single coherent Basic Memory note that reflects where the thread has landed.
|
||||
|
||||
## Purpose
|
||||
|
||||
A thread has a beginning, middle, and end. Things change as the conversation progresses: an early decision gets revised, a problem looks different in light of new information, a trade-off is settled differently than it first seemed. When this skill is invoked, capture the **current state of understanding**, not the history of how it got there.
|
||||
|
||||
If the skill is invoked more than once in the same thread, the **same note is rewritten** so it stays coherent — not appended to. The result should read top-to-bottom as a single document about the thread's outcome, with brief prose where a meaningful change is worth acknowledging.
|
||||
|
||||
## When to Use
|
||||
|
||||
Typical timing is **mid-thread or end-of-thread**, after enough has been settled to be worth preserving.
|
||||
|
||||
Use this skill when:
|
||||
- Key decisions have been made and shouldn't evaporate when the thread closes
|
||||
- A design, debugging, or planning discussion has produced something concrete
|
||||
- The user explicitly asks to capture, save, or remember what's been discussed
|
||||
- Toward the end of a session, to summarize the outcome
|
||||
|
||||
It is fine — and expected — to invoke this skill multiple times in the same thread as the conversation evolves.
|
||||
|
||||
## Same-Thread Detection
|
||||
|
||||
To rewrite the same note on re-capture instead of duplicating, key the note to a stable `thread_id` in its frontmatter.
|
||||
|
||||
**If your agent exposes a stable session or thread id**, store it as `thread_id` so subsequent captures within the same thread find and rewrite the same note. Any value that stays constant for the duration of the thread works — a session UUID, a conversation id, a ticket number the work is scoped to.
|
||||
|
||||
> **Example (hosts with a JSONL transcript):** some agents write a per-session transcript whose filename is a stable session UUID. If yours does, you can derive the id from the most-recently-modified transcript file and use it as `thread_id`. This is optional — only do it if your host actually exposes such a transcript.
|
||||
|
||||
**If no stable id is available**, match the existing note by title/topic instead: search for a note covering the same thread (`search_notes(query="<topic>")`), and if you find the one this thread already produced, rewrite it. Omit `thread_id` and rely on a consistent title.
|
||||
|
||||
## Decision Flow
|
||||
|
||||
1. **Determine the thread key.** Use a stable session/thread id if your agent exposes one; otherwise plan to match by title/topic.
|
||||
2. **Search Basic Memory** for the existing thread note.
|
||||
- With a thread id, use `metadata_filters` (not `query`) — full-text query doesn't reliably match YAML frontmatter custom fields:
|
||||
```python
|
||||
search_notes(
|
||||
metadata_filters={"thread_id": "<thread-id>"},
|
||||
project="<project>"
|
||||
)
|
||||
```
|
||||
- Without one, search by topic and identify the note this thread already produced:
|
||||
```python
|
||||
search_notes(query="<thread topic>", project="<project>")
|
||||
```
|
||||
3. **If a match is found:**
|
||||
- Read the existing note (use the full permalink returned by search)
|
||||
- Synthesize a new version that integrates the latest understanding from the conversation
|
||||
- Overwrite via `write_note` with `overwrite=True` (same title, same `thread_id` if used, same directory)
|
||||
4. **If no match is found:**
|
||||
- Synthesize the note from the conversation
|
||||
- If you have a thread id, pass `metadata={"thread_id": "<thread-id>"}` to `write_note` (it surfaces as a custom frontmatter field)
|
||||
- Save it
|
||||
|
||||
## Synthesis Rules
|
||||
|
||||
When updating an existing thread note, **synthesize, don't append**:
|
||||
|
||||
- Decisions that are still current → keep, possibly refined
|
||||
- Decisions that have been superseded → replaced inline (the new one goes where the old one was)
|
||||
- Significant revisions that deserve explanation → a sentence woven into the relevant section, *not* an appended changelog
|
||||
- Outdated context → removed
|
||||
|
||||
Goal: the note reads top-to-bottom as a single coherent document. A reader who never saw the conversation should still understand the outcome from the note alone. There is no `## Changes` section at the bottom; revisions live in the prose where they're relevant.
|
||||
|
||||
## Escape Hatch
|
||||
|
||||
If the user explicitly asks for a separate note (e.g., "capture this as a new note, don't merge with the existing thread note"), skip the same-thread lookup and create a fresh note without setting `thread_id`. This is rare; the default is to update.
|
||||
|
||||
## Note Structure
|
||||
|
||||
```markdown
|
||||
---
|
||||
title: <descriptive title for the thread>
|
||||
type: note
|
||||
thread_id: <thread-id, if your agent exposes one>
|
||||
tags:
|
||||
- relevant
|
||||
- tags
|
||||
---
|
||||
|
||||
# <Title>
|
||||
|
||||
## Context
|
||||
|
||||
What this thread is about — the situation, problem, or topic being explored.
|
||||
|
||||
## <One or more topical sections>
|
||||
|
||||
The actual content. Could be decisions, a design rationale, an investigation summary, etc.
|
||||
|
||||
## Observations
|
||||
|
||||
- [decision] What was decided #tag
|
||||
- [insight] Key understanding gained #tag
|
||||
- [tradeoff] Option A chosen over B because... #tag
|
||||
|
||||
## Relations
|
||||
|
||||
- relates_to [[Related Concept]]
|
||||
- implements [[Parent Spec]]
|
||||
```
|
||||
|
||||
## Common Observation Categories
|
||||
|
||||
- `[decision]` — choices made
|
||||
- `[insight]` — understanding gained
|
||||
- `[pattern]` — reusable approaches
|
||||
- `[learning]` — lessons learned
|
||||
- `[tradeoff]` — options weighed
|
||||
- `[problem]` — issues identified
|
||||
- `[solution]` — fixes applied
|
||||
|
||||
## Title
|
||||
|
||||
The title should reflect the thread's topic. On update, the title can be refined if the topic has clarified — but it should still describe the same thread. Don't drift to a wholly new topic; if that's needed, use the escape hatch and create a new note.
|
||||
|
||||
## MCP Tools Used
|
||||
|
||||
```python
|
||||
# Find existing thread note by thread id (use metadata_filters, not query)
|
||||
search_notes(
|
||||
metadata_filters={"thread_id": "<thread-id>"},
|
||||
project="<project>"
|
||||
)
|
||||
|
||||
# Or, without a thread id, find it by topic
|
||||
search_notes(query="<thread topic>", project="<project>")
|
||||
|
||||
# Read existing thread note (use the full permalink from search results)
|
||||
read_note(
|
||||
identifier="<full-permalink>",
|
||||
project="<project>"
|
||||
)
|
||||
|
||||
# Create
|
||||
write_note(
|
||||
title="<title>",
|
||||
content="<markdown body — frontmatter is generated from title/tags/metadata>",
|
||||
directory="<folder>",
|
||||
tags=["..."],
|
||||
metadata={"thread_id": "<thread-id>"}, # omit if no stable id
|
||||
project="<project>"
|
||||
)
|
||||
|
||||
# Overwrite an existing note (same path)
|
||||
write_note(
|
||||
title="<same title>",
|
||||
content="<new content>",
|
||||
directory="<same folder>",
|
||||
tags=["..."],
|
||||
metadata={"thread_id": "<same thread-id>"}, # omit if no stable id
|
||||
overwrite=True,
|
||||
project="<project>"
|
||||
)
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1 — First capture during a brand design conversation
|
||||
|
||||
**Preceding conversation:** The user has been working through visual identity decisions for a new product. They settled on a deep navy primary (`#2B3651`), explored accent options and chose orange (`#F26B3A`) for warmth, and picked Inter as the body font with Helvetica Neue as the display font.
|
||||
|
||||
**User asks to capture.**
|
||||
|
||||
**Result — note created:**
|
||||
|
||||
```markdown
|
||||
---
|
||||
title: Visual identity — initial decisions
|
||||
type: note
|
||||
thread_id: 7c1d4a2e-3b5f-4d8a-9e1c-2f6b8a4d7c39
|
||||
tags:
|
||||
- branding
|
||||
- design
|
||||
---
|
||||
|
||||
# Visual identity — initial decisions
|
||||
|
||||
## Context
|
||||
|
||||
Working through the visual identity for the new product. This thread covers the initial palette and typography pass — a starting point that will likely be refined.
|
||||
|
||||
## Color palette
|
||||
|
||||
- Primary: deep navy `#2B3651` — calm and professional
|
||||
- Accent: warm orange `#F26B3A` — energy and warmth as a complement to the navy
|
||||
|
||||
## Typography
|
||||
|
||||
- Body: Inter — neutral, readable at small sizes
|
||||
- Display: Helvetica Neue — strong presence for headings without being heavy
|
||||
|
||||
## Observations
|
||||
|
||||
- [decision] Primary color is navy `#2B3651` #branding
|
||||
- [decision] Accent color is orange `#F26B3A` #branding
|
||||
- [decision] Inter for body, Helvetica Neue for display #typography
|
||||
- [tradeoff] Considered teal as accent; orange tested better for warmth #branding
|
||||
|
||||
## Relations
|
||||
|
||||
- relates_to [[Brand Strategy]]
|
||||
```
|
||||
|
||||
### Example 2 — Update capture later in the same thread
|
||||
|
||||
**Preceding conversation (continued):** After the initial decisions above, the conversation continued. The orange accent felt too aggressive in mock-ups, so we tested a coral (`#E89B7A`) which read warmer and more refined. The body font also shifted: Geist felt slightly tighter and more modern than Inter. Helvetica Neue for display stayed.
|
||||
|
||||
**User asks to capture again — same thread.**
|
||||
|
||||
**Result — same note rewritten (note the same `thread_id`):**
|
||||
|
||||
```markdown
|
||||
---
|
||||
title: Visual identity — initial decisions
|
||||
type: note
|
||||
thread_id: 7c1d4a2e-3b5f-4d8a-9e1c-2f6b8a4d7c39
|
||||
tags:
|
||||
- branding
|
||||
- design
|
||||
---
|
||||
|
||||
# Visual identity — initial decisions
|
||||
|
||||
## Context
|
||||
|
||||
Working through the visual identity for the new product. This thread settled on a navy + coral palette and a Geist/Helvetica typography pairing after a round of refinement.
|
||||
|
||||
## Color palette
|
||||
|
||||
- Primary: deep navy `#2B3651` — calm and professional
|
||||
- Accent: coral `#E89B7A` — warm and refined
|
||||
|
||||
The accent went through a round of revision: an initial orange (`#F26B3A`) felt too aggressive in mock-ups, so we shifted to a coral that reads warmer and more refined while keeping the energy.
|
||||
|
||||
## Typography
|
||||
|
||||
- Body: Geist — slightly tighter and more modern than Inter, which we tried first
|
||||
- Display: Helvetica Neue — strong presence for headings without being heavy
|
||||
|
||||
## Observations
|
||||
|
||||
- [decision] Primary color is navy `#2B3651` #branding
|
||||
- [decision] Accent color is coral `#E89B7A` — warmer and more refined than the originally-chosen orange #branding
|
||||
- [decision] Geist for body, Helvetica Neue for display #typography
|
||||
- [tradeoff] Inter felt neutral but Geist edged it for spacing and modernity #typography
|
||||
- [tradeoff] Orange accent rejected as too aggressive; coral preferred #branding
|
||||
|
||||
## Relations
|
||||
|
||||
- relates_to [[Brand Strategy]]
|
||||
```
|
||||
|
||||
Notice that:
|
||||
- The orange and Inter decisions are **no longer the primary content** — they're acknowledged in prose ("which we tried first," "originally-chosen orange") and in tradeoff observations
|
||||
- There is **no "Changes" section** at the bottom — revisions are integrated where they belong
|
||||
- The note still reads top-to-bottom as a single coherent document
|
||||
- The `thread_id` is unchanged, so the note was updated in place rather than duplicated
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Capture the current state, not the history.** The note represents where the thread has landed.
|
||||
2. **Synthesize, don't log.** Each invocation produces a coherent document, not an accumulating record.
|
||||
3. **Brief prose for revisions.** A sentence in the section that changed is enough — don't add a changelog.
|
||||
4. **Always run the same-thread lookup** before deciding to create or update.
|
||||
5. **Use observations for the structured layer.** Decisions, insights, tradeoffs go in `## Observations` so they're searchable.
|
||||
6. **Link relations liberally.** Notes the user might want to reach from this one.
|
||||
@@ -0,0 +1,148 @@
|
||||
---
|
||||
name: memory-continue
|
||||
description: "Resume prior work by rebuilding context from the Basic Memory knowledge graph — pick up where you left off using memory:// URLs, recent activity, and search. Use when starting a session or when the user says 'continue with...', 'back to...', or 'where were we?'"
|
||||
---
|
||||
|
||||
# Memory Continue
|
||||
|
||||
Resume previous work by reconstructing context from the Basic Memory knowledge graph, so the assistant can pick up across sessions instead of starting cold.
|
||||
|
||||
## When to Use
|
||||
|
||||
- Starting a new session and you need to pick up where you left off
|
||||
- The user references earlier work: "continue with...", "back to...", "where were we on...?"
|
||||
- You need context about an ongoing project or spec
|
||||
- The user asks about something discussed in a previous conversation
|
||||
- You're working on a task that spans multiple sessions
|
||||
|
||||
## Building Context
|
||||
|
||||
### 1. Identify What to Continue
|
||||
|
||||
If it's unclear, ask:
|
||||
- What topic or project should you resume?
|
||||
- What timeframe matters?
|
||||
- Any specific aspect to focus on?
|
||||
|
||||
### 2. Gather Context with MCP Tools
|
||||
|
||||
**Known topic — use `build_context`.** Navigate the graph from a starting point, following relations outward:
|
||||
|
||||
```python
|
||||
build_context(
|
||||
url="memory://topic-or-note-name",
|
||||
depth=2, # how many relation hops to follow
|
||||
timeframe="7d", # bias toward recent changes
|
||||
)
|
||||
```
|
||||
|
||||
**No clear starting point — use `recent_activity`.** See what's changed and let it surface the thread:
|
||||
|
||||
```python
|
||||
recent_activity(timeframe="3d", depth=1)
|
||||
```
|
||||
|
||||
**Looking for something specific — use `search_notes`.** Find candidate notes by keyword:
|
||||
|
||||
```python
|
||||
search_notes(query="async client refactor", page_size=10)
|
||||
```
|
||||
|
||||
### 3. Read the Key Notes
|
||||
|
||||
Once you've identified the relevant notes, read them in full:
|
||||
|
||||
```python
|
||||
read_note(identifier="note-title-or-permalink")
|
||||
```
|
||||
|
||||
### 4. Present Context to the User
|
||||
|
||||
Summarize what you found, incrementally:
|
||||
- Current state of the work
|
||||
- Recent changes or progress
|
||||
- Open items and next steps
|
||||
- Related context that might help
|
||||
|
||||
## Memory URL Reference
|
||||
|
||||
`build_context` and `read_note` both accept `memory://` URLs, which address notes by permalink and support wildcards for gathering groups of notes.
|
||||
|
||||
```
|
||||
memory://note-title # a single note by permalink
|
||||
memory://folder/* # all notes in a folder
|
||||
memory://specs/SPEC-24* # pattern / prefix match
|
||||
memory://project/*/requirements # path wildcards
|
||||
```
|
||||
|
||||
Use a specific note URL to anchor on one starting point; use a wildcard to pull in a whole folder or family of related notes at once.
|
||||
|
||||
## Timeframe Reference
|
||||
|
||||
`build_context` and `recent_activity` accept natural-language timeframes:
|
||||
|
||||
| Timeframe | Meaning |
|
||||
|-----------|---------|
|
||||
| `"today"` | Current day |
|
||||
| `"yesterday"` | Previous day |
|
||||
| `"3d"` or `"3 days"` | Last 3 days |
|
||||
| `"1 week"` or `"7d"` | Last week |
|
||||
| `"2 weeks"` | Last 2 weeks |
|
||||
| `"1 month"` | Last month |
|
||||
|
||||
## Scenario Playbooks
|
||||
|
||||
### Resuming a Spec or Project
|
||||
|
||||
```python
|
||||
# 1. Read the spec / project note
|
||||
read_note(identifier="SPEC-24: Postgres Database Migration")
|
||||
|
||||
# 2. Pull in related context and recent changes via the graph
|
||||
build_context(url="memory://SPEC-24*", timeframe="7d")
|
||||
```
|
||||
|
||||
Then summarize: the goals, what's completed, what's pending, and any blockers or open decisions.
|
||||
|
||||
### Continuing General Work
|
||||
|
||||
```python
|
||||
# 1. Check recent activity
|
||||
recent_activity(timeframe="3d")
|
||||
|
||||
# 2. Read notes from the recent sessions it surfaces
|
||||
read_note(identifier="relevant-note")
|
||||
```
|
||||
|
||||
Then list the modified notes with brief descriptions and ask which thread to dive into.
|
||||
|
||||
### Following Up on a Topic
|
||||
|
||||
```python
|
||||
# 1. Find the topic
|
||||
search_notes(query="topic keywords")
|
||||
|
||||
# 2. Build context from the best match, following its relations
|
||||
build_context(url="memory://found-note-permalink", depth=2)
|
||||
```
|
||||
|
||||
Then present the full picture — the note plus its connected context.
|
||||
|
||||
## Project Discovery
|
||||
|
||||
Project names are user-specific. To discover what's available before scoping a search or `memory://` URL:
|
||||
|
||||
```python
|
||||
list_memory_projects()
|
||||
```
|
||||
|
||||
In multi-project setups, prefix a `memory://` URL with the project name (e.g. `memory://research/papers/crdt`) to scope it.
|
||||
|
||||
## Guidelines
|
||||
|
||||
1. **Start broad, then narrow.** Get an overview with `recent_activity` or a wildcard `build_context`, then drill into specific notes.
|
||||
2. **Present incrementally.** Share what you find as you go rather than holding everything until the end.
|
||||
3. **Follow relations.** The graph's connections are the point — `build_context` with `depth` surfaces context you wouldn't find by reading one note.
|
||||
4. **Check multiple projects.** Specs may live separately from implementation notes; discover projects with `list_memory_projects`.
|
||||
5. **Confirm understanding.** Verify the reconstructed context is what the user actually needs before acting on it.
|
||||
6. **Capture new progress.** As the resumed work advances, write it back to the graph (see the **memory-notes** skill) so the next session can continue too.
|
||||
@@ -0,0 +1,243 @@
|
||||
---
|
||||
name: memory-curate
|
||||
description: "Curate the Basic Memory knowledge graph: find orphan notes and suggest links, propose typed relations, merge duplicates, audit tags and folders, and build hub notes. Use to organize, connect, and improve a knowledge base as notes accumulate."
|
||||
---
|
||||
|
||||
# Memory Curate
|
||||
|
||||
Maintain a healthy, well-connected knowledge graph. As notes accumulate, it pays to periodically organize, link, and curate the knowledge base so isolated notes become a connected graph.
|
||||
|
||||
This skill curates the **knowledge graph** — the notes, relations, and tags that make up the knowledge base. (For hygiene on an agent's own memory *files* — splitting bloated files, pruning stale entries — see **memory-defrag**.)
|
||||
|
||||
## When to Use
|
||||
|
||||
- Asked to organize, clean up, or improve the knowledge base
|
||||
- Asked to find connections between notes, or what isn't linked yet
|
||||
- Orphan or unlinked notes are mentioned
|
||||
- Asked about duplicate or similar notes
|
||||
- Asked for help with folder organization or tag consistency
|
||||
- Phrases like "help me organize", "find related notes", "what's not linked", "clean up my notes"
|
||||
|
||||
## Curation Capabilities
|
||||
|
||||
### 1. Find Orphan Notes
|
||||
|
||||
Orphans have no relations to other notes — they're islands in the graph.
|
||||
|
||||
```python
|
||||
# List notes, then read each to inspect its Relations section
|
||||
search_notes(query="*", page_size=50)
|
||||
read_note(identifier="note-to-check")
|
||||
# Orphans have an empty (or missing) Relations section
|
||||
```
|
||||
|
||||
**What to do with orphans:**
|
||||
- Suggest relations based on content similarity
|
||||
- Ask whether they should connect to existing topics
|
||||
- Propose hub notes to gather related orphans (see capability 6)
|
||||
|
||||
### 2. Suggest Typed Relations
|
||||
|
||||
Analyze a note's content and propose meaningful connections.
|
||||
|
||||
```python
|
||||
read_note(identifier="note-to-analyze")
|
||||
# Pull out key terms, then search for related notes
|
||||
search_notes(query="key terms from the note")
|
||||
```
|
||||
|
||||
Suggest relations based on shared topics, complementary content (problem/solution,
|
||||
question/answer), sequence (part 1 → part 2), or hierarchy (parent concept → detail).
|
||||
|
||||
**Relation-type vocabulary:**
|
||||
- `relates_to` — general topical connection
|
||||
- `extends` — builds upon or elaborates
|
||||
- `implements` — realizes a concept or spec
|
||||
- `depends_on` — requires understanding of
|
||||
- `part_of` — hierarchy or composition
|
||||
- `contrasts_with` — presents an alternative view
|
||||
- `inspired_by` — source of insight
|
||||
- `enables` — makes something possible
|
||||
|
||||
Custom relation types are fine — use whatever verb is descriptive.
|
||||
|
||||
Add a confirmed relation with `edit_note`:
|
||||
|
||||
```python
|
||||
edit_note(
|
||||
identifier="API Design Decisions",
|
||||
operation="append",
|
||||
section="Relations",
|
||||
content="- depends_on [[Rate Limiter]]",
|
||||
)
|
||||
```
|
||||
|
||||
### 3. Identify Similar / Duplicate Notes
|
||||
|
||||
Find notes that may cover the same ground.
|
||||
|
||||
```python
|
||||
search_notes(query="topic keywords")
|
||||
# Compare results for: similar titles, overlapping observations,
|
||||
# shared tags, close-together timestamps
|
||||
```
|
||||
|
||||
**Actions for duplicates:**
|
||||
- **Merge** into a single comprehensive note, then redirect the loser with a relation
|
||||
- Link with `supersedes` / `updates` when one revises the other
|
||||
- **Differentiate** by adding context that clarifies each note's distinct focus
|
||||
|
||||
```python
|
||||
# Point an older note at the one that replaces it
|
||||
edit_note(
|
||||
identifier="DB Schema v1",
|
||||
operation="append",
|
||||
section="Relations",
|
||||
content="- updates [[DB Schema v2]]",
|
||||
)
|
||||
```
|
||||
|
||||
### 4. Folder Organization Review
|
||||
|
||||
```python
|
||||
list_directory(dir_name="/", depth=3)
|
||||
```
|
||||
|
||||
Look for overcrowded folders, single-note folders, inconsistent naming, and notes
|
||||
that belong elsewhere. Suggest grouping related notes into topic folders, adding
|
||||
subfolders for large categories, and a consistent naming convention. Move misplaced
|
||||
notes with `move_note` — the permalink stays stable, so wiki-links keep resolving.
|
||||
|
||||
```python
|
||||
move_note(
|
||||
identifier="API Design Decisions",
|
||||
destination_path="architecture/api-design-decisions.md",
|
||||
)
|
||||
```
|
||||
|
||||
### 5. Tag Consistency
|
||||
|
||||
```python
|
||||
search_notes(query="*", page_size=100)
|
||||
# Inspect tag patterns across results
|
||||
```
|
||||
|
||||
Look for:
|
||||
- **Variant tags** — `architecture` vs `arch`; pick one and standardize
|
||||
- **Unused tags** — present on a single note, no longer carrying weight
|
||||
- **Over-used generic tags** — so broad they don't aid discovery
|
||||
- **Missing tags** — relevant notes lacking an obvious tag
|
||||
|
||||
### 6. Create Index / Hub Notes
|
||||
|
||||
After finding a cluster of related notes, build a navigation hub.
|
||||
|
||||
```python
|
||||
write_note(
|
||||
title="Architecture Decisions Index",
|
||||
directory="indexes",
|
||||
tags=["architecture", "index"],
|
||||
note_type="index",
|
||||
content="""# Architecture Decisions Index
|
||||
|
||||
A hub linking architecture-related decisions and patterns.
|
||||
|
||||
## Decisions
|
||||
- [[Database Selection Decision]]
|
||||
- [[API Design Patterns]]
|
||||
- [[Authentication Architecture]]
|
||||
|
||||
## Patterns
|
||||
- [[Repository Pattern]]
|
||||
- [[Async Client Pattern]]
|
||||
|
||||
## Observations
|
||||
- [index] Central hub for architecture knowledge #navigation
|
||||
|
||||
## Relations
|
||||
- indexes [[Architecture]]""",
|
||||
)
|
||||
```
|
||||
|
||||
### 7. Enrich Sparse Notes
|
||||
|
||||
Find notes lacking structure and fill them in.
|
||||
|
||||
```python
|
||||
read_note(identifier="sparse-note")
|
||||
```
|
||||
|
||||
If the note is missing an Observations section, suggest categories. If it has no
|
||||
Relations, suggest links. If it has no tags, suggest relevant ones. If it lacks
|
||||
context, suggest adding background. Apply with `edit_note`.
|
||||
|
||||
## Curation Workflows
|
||||
|
||||
### Quick Health Check
|
||||
|
||||
A fast overview of knowledge base status:
|
||||
|
||||
1. Count total notes
|
||||
2. Identify orphan count
|
||||
3. List recently modified (`recent_activity`)
|
||||
4. Check for obvious duplicates
|
||||
5. Report folder distribution
|
||||
|
||||
### Deep Organization Session
|
||||
|
||||
Thorough review and improvement:
|
||||
|
||||
1. **Audit** — catalog all notes, identify issues
|
||||
2. **Orphans** — address unlinked notes
|
||||
3. **Relations** — suggest new connections
|
||||
4. **Duplicates** — merge or differentiate similar notes
|
||||
5. **Structure** — reorganize folders if needed
|
||||
6. **Index** — create hub notes for major topics
|
||||
|
||||
### Topic-Focused Organization
|
||||
|
||||
Organize around a specific subject:
|
||||
|
||||
1. Find all notes related to the topic (`search_notes`)
|
||||
2. Map existing relations with `build_context(url="memory://...")`
|
||||
3. Identify gaps in the topic graph
|
||||
4. Suggest new notes to fill them
|
||||
5. Create a topic index note
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Work incrementally.** Don't reorganize everything at once.
|
||||
2. **Confirm before changing.** Always ask before moving, merging, or editing notes.
|
||||
3. **Preserve permalinks.** Moving a note is fine; changing its permalink breaks inbound links.
|
||||
4. **Explain suggestions.** Say *why* a relation or merge makes sense.
|
||||
5. **Respect the existing system.** Enhance the user's organization — don't impose a new taxonomy.
|
||||
6. **Show the graph.** Use `build_context` to help the user see how notes connect.
|
||||
|
||||
## Example Conversations
|
||||
|
||||
**User:** "Help me organize my notes"
|
||||
|
||||
The assistant:
|
||||
1. Runs a health check on the knowledge base
|
||||
2. Reports: "You have 47 notes. I found 12 orphans and 3 potential duplicates."
|
||||
3. Asks: "Want to start by connecting the orphans, or review the duplicates first?"
|
||||
|
||||
**User:** "Find notes that should link to my API design note"
|
||||
|
||||
The assistant:
|
||||
1. Reads the API design note
|
||||
2. Searches for related content
|
||||
3. Suggests: "5 notes could relate —
|
||||
- 'REST Best Practices' → `relates_to`
|
||||
- 'Authentication Flow' → `implements`
|
||||
- 'Rate Limiting Decision' → `extends`
|
||||
Should I add any of these relations?"
|
||||
|
||||
**User:** "Are there notes on similar topics?"
|
||||
|
||||
The assistant:
|
||||
1. Analyzes titles and content for clusters
|
||||
2. Reports: "Possible overlaps —
|
||||
- 'Auth Flow' and 'Authentication Design' cover similar ground
|
||||
- 'DB Schema v1' and 'DB Schema v2' likely want a `supersedes` relation
|
||||
Want to review either?"
|
||||
@@ -276,26 +276,42 @@ Basic Memory auto-generates frontmatter (including the permalink and memory URL)
|
||||
|
||||
### Editing an Existing Note
|
||||
|
||||
Use `edit_note` to append, prepend, or find-and-replace within a note:
|
||||
Use `edit_note` to update a note in place — four operations:
|
||||
|
||||
```python
|
||||
# Append new observations
|
||||
# append / prepend — add to the end or start (use for time-ordered logs)
|
||||
edit_note(
|
||||
identifier="API Design Decisions",
|
||||
operation="append",
|
||||
section="Observations",
|
||||
content="- [decision] Use OpenAPI 3.1 for spec generation #api"
|
||||
)
|
||||
|
||||
# Add a new relation
|
||||
edit_note(
|
||||
identifier="API Design Decisions",
|
||||
operation="append",
|
||||
section="Relations",
|
||||
content="- depends_on [[Rate Limiter]]"
|
||||
operation="prepend",
|
||||
content="> Updated 2026-05-28: auth approach finalized.\n"
|
||||
)
|
||||
|
||||
# replace_section — rewrite a named section (use for living content that stays current)
|
||||
edit_note(
|
||||
identifier="API Design Decisions",
|
||||
operation="replace_section",
|
||||
section="Summary",
|
||||
content="Concise, current summary of the decision and its rationale."
|
||||
)
|
||||
|
||||
# find_replace — swap specific text
|
||||
edit_note(
|
||||
identifier="API Design Decisions",
|
||||
operation="find_replace",
|
||||
find_text="OpenAPI 3.0",
|
||||
content="OpenAPI 3.1"
|
||||
)
|
||||
```
|
||||
|
||||
When an edit is destructive (`replace_section`, `find_replace`), it's good practice to
|
||||
read the note first and confirm the change before applying it.
|
||||
|
||||
### Moving a Note
|
||||
|
||||
Use `move_note` to reorganize notes into different directories:
|
||||
|
||||
Reference in New Issue
Block a user