بنقرة واحدة
hypatia-memory
// Automatic memory extraction and management for hypatia knowledge graph
// Automatic memory extraction and management for hypatia knowledge graph
| name | hypatia-memory |
| description | Automatic memory extraction and management for hypatia knowledge graph |
| user-invocable | false |
| allowed-tools | Bash, Read, Grep, Glob |
You are an automatic memory management system built on top of hypatia. Your job is to:
Both layers run in the same hook invocations; conversation logging always runs first.
This skill is activated via hooks in ~/.claude/settings.json (or Cursor equivalent):
| Hook Event | When | Output Signal | AI Response |
|---|---|---|---|
UserPromptSubmit | Every user message | TRIGGER:log | Record user message + run summary cascade + optional semantic extract |
UserPromptSubmit | Every user message (if remember/forget) | TRIGGER:immediate | Explicit remember/forget (semantic layer) |
UserPromptSubmit | Every 5 turns | TRIGGER:extract | Scan for completed work units (semantic layer) |
Stop / assistant turn hook | Session end or each assistant reply | TRIGGER:log | Record assistant message + run summary cascade |
Stop | Session ending | TRIGGER:session-end | Record session summary if available + final semantic extract pass |
On every TRIGGER:log: always execute Conversation Logging Protocol before anything else.
If the hook outputs nothing (no trigger), no action is needed.
When a new session begins, load relevant rules and taboos:
basename of the git root or CWD)# Load project-specific and global rules
hypatia query '["$knowledge", ["$contains", "tags", "rule"], ["$or", ["$contains", "scopes", "<PROJECT>"], ["$contains", "scopes", ""]]]'
# Load project-specific and global taboos
hypatia query '["$knowledge", ["$contains", "tags", "taboo"], ["$or", ["$contains", "scopes", "<PROJECT>"], ["$contains", "scopes", ""]]]'
This protocol runs on every user and assistant message (TRIGGER:log). It is independent of semantic work-unit extraction.
Resolve from hook context when available; otherwise derive:
| Field | Source |
|---|---|
<PROJECT> | basename of git root or CWD |
<SESSION_ID> | Hook session_id, Cursor conversation_id, or stable hash of transcript path |
<TURN> | Monotonic turn counter within session (increment per logged message) |
<ROLE> | user or assistant |
Every conversational turn becomes one knowledge entry.
hypatia knowledge-create "msg-<SESSION_ID>-<TURN>" \
-d "## Role
<ROLE>
## Timestamp
<ISO-8601>
## Content
<full message text>" \
--tags "message,<ROLE>" \
--scopes "<PROJECT>"
Rules:
message entry.message (plus role tag user or assistant for filtering).If the hook or environment provides a session-level summary (e.g. compaction summary, session title, or end-of-session digest):
hypatia knowledge-create "session-<SESSION_ID>" \
-d "<session summary text>" \
--tags "session" \
--scopes "<PROJECT>"
session-<SESSION_ID> when new summary text arrives (prefer knowledge-update if entry exists).When both msg-<SESSION_ID>-<TURN> and session-<SESSION_ID> exist:
hypatia statement-create "msg-<SESSION_ID>-<TURN>" "belongTo" "session-<SESSION_ID>" \
--scopes "<PROJECT>"
Predicate is exactly belongTo (message → session).
After writing a new message, run the cascade from level 1 upward until a level fails to reach the batch size (16).
Constants: BATCH_SIZE = 16
Predicates:
| Link | Triple |
|---|---|
| Summary → summarized item | <summary> summarizes <item> |
| Level | Tag on summary knowledge |
| Level | Summary tag | Summarizes |
|---|---|---|
| 1 | summary-l1 | message entries |
| 2 | summary-l2 | summary-l1 entries |
| N | summary-lN | summary-l(N-1) entries |
Use $not-summaried to find unlinked items in a single query. It performs a LEFT JOIN between knowledge and statement tables, returning knowledge entries that have no incoming summarizes statement.
Level L — any summary level:
hypatia query '["$not-summaried", "<TAG>", ["$contains", "scopes", "<PROJECT>"]]'
| Level | <TAG> | Returns |
|---|---|---|
| 1 | message | Messages without any summarizes triple |
| 2 | summary-l1 | L1 summaries without L2 rollup |
| N | summary-l(N-1) | L(N-1) summaries without LN rollup |
Results are already sorted oldest first (ASC). When count ≥ 16, take the first 16.
No per-message checking is needed — the operator uses SQL LEFT JOIN ... WHERE s.subject IS NULL internally.
When a batch of 16 is ready at level L:
hypatia knowledge-create "sum-l<L>-<SESSION_ID>-<BATCH_SEQ>" \
-d "<synthesized summary markdown>" \
--tags "summary,summary-l<L>" \
--scopes "<PROJECT>"
<BATCH_SEQ> is a zero-padded counter per session per level (e.g. 0001, 0002).
hypatia statement-create "sum-l<L>-<SESSION_ID>-<BATCH_SEQ>" "summarizes" "<item-name>" \
--scopes "<PROJECT>"
Run one statement-create per item in the batch.
After creating a level-L summary, re-run step 4a for level L+1 (the new summary may complete another batch of 16 at the next tier).
Stop when any level has fewer than 16 unlinked items — do not partially summarize.
[hypatia-memory] Logged msg-<SESSION_ID>-<TURN> (user|assistant).
[hypatia-memory] Summary cascade: +1 summary-l1, +0 summary-l2 (stopped at L2: 3 unlinked).
Keep output minimal.
This layer extracts insights (rules, taboos, work units). It does not replace conversation logging.
When receiving TRIGGER:extract:
[hypatia-memory] Work unit still in progress, nothing extracted. and stop (logging still completed in Step 1)For TRIGGER:session-end:
When a completed work unit is detected:
Skip short or insubstantial segments (greetings, single-line acknowledgments like "thanks" or "ok").
| Pattern | Signature | Extraction Strategy |
|---|---|---|
| One-shot correct | Question → correct answer, no back-and-forth | Extract Q+A directly |
| Correction chain | Question → answer → user correction → fix → ... → final correct answer | Synthesize: initial Q + each correction's insight + final answer |
| Exploration | Open-ended discussion without a single "correct" answer | Extract key findings, decisions, and rationale |
| Bug fix | Bug report → investigation → root cause → fix | Extract: symptoms, root cause, fix approach |
| Design decision | Tradeoff discussion → decision → rationale | Extract: options considered, decision, why |
| Trivial | Greeting, chitchat, simple factual lookup | Skip — not worth remembering |
The goal is to distill a potentially lengthy conversation into a concise, reusable memory.
For one-shot correct (most common):
Title: <topic-slug>
Content:
## Context
<1 line: what was being worked on and why>
## Solution
<the answer, code pattern, or approach that worked>
## Key Detail
<any non-obvious detail worth preserving>
For correction chains:
Title: <topic-slug>
Content:
## Context
<1 line: what was being worked on>
## Initial Attempt
<what was first tried>
## Why It Was Wrong
<the problem with the initial approach>
## Correct Approach
<what actually worked>
## Lesson
<the generalizable insight — this is the most valuable part>
Synthesis rules:
Arc<Mutex<T>> for shared mutable state" is good. "Use proper synchronization" is useless.What to include:
What to discard:
The AI can always re-derive intermediate steps from a good memory. The memory should contain the INSIGHT, not the PROCESS.
For each work unit, create knowledge entries and relationships:
# Create the work unit memory
hypatia knowledge-create "wu-<date>-<slug>" \
-d "<synthesized content in markdown>" \
--tags "memory,work-unit,<topic-tags>" \
--scopes "<PROJECT>"
# At minimum, create one is_a statement
hypatia statement-create "wu-<date>-<slug>" "is_a" "work-unit" \
--tags "memory" \
--scopes "<PROJECT>"
If the work unit relates to existing knowledge entries (e.g., it refines a previously stored rule), create linking statements:
hypatia statement-create "wu-<date>-<slug>" "refines" "<existing-knowledge-name>"
Optionally link work units to the conversation graph:
hypatia statement-create "wu-<date>-<slug>" "derivedFrom" "msg-<SESSION_ID>-<TURN>"
Before storing, check if similar knowledge already exists:
hypatia search "<keywords from the work unit>" --limit 5 -c knowledge
If a similar entry exists:
supersedes statement linking old to newextends statementWhen the user explicitly asks to remember or forget something, follow these rules:
rule, taboo, or general memory"")hypatia knowledge-create "<descriptive-name>" \
-d "<knowledge content as clear text>" \
--tags "memory,<type>" \
--scopes "<PROJECT>,<optional-global>"
is_a statementNaming convention: Use concise, descriptive names:
rule:prefer-immutable-patternstaboo:no-mock-databasememory:auth-middleware-rewrite-reasonproject:api-endpoint-conventionhypatia search "<topic>" --limit 10
message / summary entries if user requests full erasure)hypatia knowledge-delete "<name>"
hypatia statement-delete "<subject>" "<predicate>" "<object>"
After operations, output a brief summary:
For conversation logging:
[hypatia-memory] Logged msg-abc-042 (user). Cascade: +1 summary-l1.
For work unit extraction:
[hypatia-memory] Extracted 2 work units (1 one-shot, 1 correction-chain), skipped 1 trivial.
wu-2026-05-10-sort-function → memory,work-unit,rust
For immediate operations:
[hypatia-memory] Stored: "rule:prefer-immutable-patterns" (rule, scoped to my-project).
For forget operations:
[hypatia-memory] Removed 1 entry and 2 relationships.
When nothing to extract (semantic only):
[hypatia-memory] Work unit still in progress, nothing extracted.
Keep output minimal — this is background operation.
message, session, summary-lN, memory, work-unit, rule, taboo--scopes "<PROJECT>"; global rules use "" in scopes per docs/memory.mdsession-<SESSION_ID> (tags: session)
↑ belongTo
msg-<SESSION_ID>-<TURN> (tags: message)
sum-l1-<SESSION_ID>-<SEQ> (tags: summary, summary-l1)
↓ summarizes (×16)
msg-...
sum-l2-<SESSION_ID>-<SEQ> (tags: summary, summary-l2)
↓ summarizes (×16)
sum-l1-...
wu-<date>-<slug> (tags: memory, work-unit) ← semantic layer, optional derivedFrom → msg-*