cc-os/docs/memory-system/04-build-plan.md

8.8 KiB
Raw Blame History

Build Plan

How a human builds this system, step by step, and answers to the operational questions: which scripts and hooks, how the AI knows when to write and what conventions to follow, how and when it queries, the CRUD hooks, and how it's packaged as a global Claude Code plugin with skills.

This is a build outline, not the implementation plan. The next session should turn this into a proper implementation plan (writing-plans skill) and execute it.


Part A — Build order (human builder's path)

Build bottom-up: the vault and CLI first (usable standalone), then the hooks, then the plugin that packages it.

Step 1 — Vault skeleton & conventions

  • Decide the vault location (default: a synced home dir, e.g. ~/brain; symlink into ~/.claude/memory only if a tool insists). Vault is the single source of truth.
  • Write CONVENTIONS.md in the vault: the frontmatter contract and the tag namespaces (tool/, client/, domain/, convention/, scope/). This doubles as the spec the skills teach the AI.
  • Seed a few real notes (e.g. tool/semrush global + a client/<x> project note) to test against.

Step 2 — The Ruby tag-index CLI (the core build)

  • Ruby project, sequel + sqlite3 gems. SQLite file in a cache dir (e.g. ~/.cache/memory-index/index.sqlite) — disposable, never synced.
  • Schema / migrations: files(id, path, mtime, summary, scope), tags(id, name), files_tags(file_id, tag_id); many_to_many between files and tags.
  • Frontmatter parser: read YAML frontmatter from a .md file → {summary, scope, tags[]}. Fail loudly (or quarantine) notes missing the required summary/tags so the contract is enforced.
  • Commands (a thin CLI dispatch — thor/optparse or plain):
    • index update --since <iso8601|auto> — find .md with mtime > last-cache-time, upsert them; reconcile: delete rows for paths no longer on disk.
    • index update --file <path> — upsert a single file (used by the write hook); prune if the path is gone.
    • index update --rebuild (default off) — drop & rebuild from a full vault scan.
    • index query --client X --tool Y [--domain Z] [--scope global] — AND the filters; output JSON lines of {path, summary, tags[]} (option C).
    • index tags [--namespace tool/] — enumerate the vocabulary (virtual index).
  • Store last_cache_time (a tiny meta table or a stamp file) so --since auto works.
  • Tests: create/edit/delete/rename a note, assert the index reflects it; rebuild equals incremental.

Step 3 — Hooks (maintenance + retrieval)

See Part C for exact mapping. Implement as small shell wrappers that call the Ruby CLI:

  • pre-tool-memory style PostToolUse updater (write path → index update --file).
  • SessionStart reconcile + inject (index overview + resolved convention/* files + journal pointer).
  • SessionEnd journal appender (daily note with pointers).

Step 4 — Episodic layer (memsearch)

  • Install memsearch (/plugin marketplace add zilliztech/memsearch, then plugin install memsearch), local to start. Verify daily memory files appear after a few conversations.
  • Decide whether memsearch indexes our session-end journal notes or its own capture (likely its own; our journal can point into the knowledge vault).

Step 5 — Sync

  • Pick git (versioned, hourly push/pull) or Syncthing (continuous, zero-thought) for the vault → VPS. Configure on each machine. Do not sync the SQLite/Milvus caches.

Step 6 — Package as a global plugin (Part D)

  • Wrap Steps 23 into a Claude Code plugin with skills; install at user level.

Step 7 (deferred) — QMD semantic layer

  • Only when structured-only retrieval misses notes you know exist: qmd over the vault, optionally as an MCP server the AI can query.

Part B — The AI's write & query conventions (skills teach these)

When the AI WRITES to the vault

Trigger writes when the AI learns something evergreen and reusable across projects — not project-ephemeral state (that's the episodic layer / project files). Concretely:

  • It worked out how a tool/API behaves (e.g. SEMrush auth, rate limits, an endpoint quirk).
  • It established a convention, decision, or preference that should apply beyond this task.
  • It discovered a client-specific fact worth reusing (how this client uses a tool).

What conventions to follow when writing (enforced by the frontmatter contract):

  • One concept per note; keep notes small (the L1 "under ~200 lines / one topic" discipline).
  • Required frontmatter: a one-line summary (written now, not deferred), scope/global or scope/project, and namespaced tags (tool/…, client/…, domain/…, optionally convention/…).
  • Scope rule: default new tool/domain knowledge to scope/global; mark scope/project + a client/<name> tag when it's specific to how a client uses something.
  • Write only to the vault, never silently into a project repo.
  • Promotion to global (project → global) and consolidation are not done inline — they happen in the reorganize step (Part C), in plan mode, for human review.

When & how the AI QUERIES

  • At session start: the injected index overview + resolved convention/* files tell it what's available without reading everything.
  • On demand, during a task: when the task touches a tool/client/domain, run index query --tool semrush --client sesame3g → get {path, summary, tags} → open only the files whose summary matches. This is the progressive-disclosure loop that keeps tokens low.
  • Cross-client lookups: query by --tool alone (omit client) to surface what was learned with any client; tags in the output show provenance.
  • "What happened" questions go to the episodic layer (memsearch) in natural language, not the tag index.

Part C — Hooks & CRUD mapping

CRUD over the knowledge vault, and which hook/command services each operation:

Operation Trigger Mechanism
Create AI writes a new note AI writes .md (Write tool) → PostToolUse hook → index update --file
Read / query AI needs knowledge AI calls index query … (no hook; on-demand CLI)
Update AI/user edits a note AI edit → PostToolUse hook → index update --file; user edit → SessionStart reconcile
Delete / rename note removed/renamed covered by --file (prune) on AI ops; by SessionStart reconcile (prune vanished paths) on manual ops
Inject new session/sub-agent starts SessionStart hook injects index overview + resolved convention/* + journal pointer
Journal session ends SessionEnd hook appends a dated journal note with pointers
Reorganize periodic, user-invoked reorganize memory run in plan mode: dedupe, merge, split, re-tag, promote scope/global, rebuild index — human approves

Hooks are thin shell wrappers over the Ruby CLI so the logic lives in one place.

Hooks summary:

  • SessionStart — reconcile (index update --since auto) + inject context.
  • PostToolUse (on Write/Edit of vault .md) — index update --file.
  • SessionEnd — append daily journal note.
  • (memsearch brings its own UserPromptSubmit + capture hooks for the episodic layer.)

Part D — Claude Code plugin with skills (global install)

Goal: one global install so every project/machine knows the vault, conventions, hooks, and CLI.

Plugin contents:

  • Hooks registered in settings: SessionStart, PostToolUse, SessionEnd (the shell wrappers from Part C), pointed at a configurable vault path + cache dir.
  • The Ruby CLI (the tag index) bundled or installed as a dependency, on PATH.
  • Skills (these carry the know-how to the model):
    • memory-write — when to record evergreen knowledge, the frontmatter contract, scope rules, "vault not repo." (Part B write section.)
    • memory-query — how/when to query the tag index vs the episodic layer; the progressive- disclosure loop; cross-client lookups. (Part B query section.)
    • memory-reorganize — the plan-mode consolidation/promotion procedure + guardrails.
  • Config: vault path, cache path, sync method — set once at user level.

Why a plugin + skills (not just CLAUDE.md): hooks must be registered by the harness (the plugin does that), and the conventions are taught as skills so they load on demand without bloating every project's context. A single global install keeps the conventions themselves a single source of truth — edit the skill once, every project follows.

Open question for build time: do the coding-convention/* notes live in the vault (data, edited freely, resolved by the SessionStart hook) while the memory-system skills live in the plugin (behavior, versioned)? Recommended: yes — conventions are data in the vault; the skills are the mechanism.