Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ To measure any of this, `qmd bench <fixture.json> -c memories` is usable as ship

**The search call shape is stated in three places, deliberately.** "Typed `lex`+`vec` lines, `rerank: false`, `limit: 6`" appears in `templates/continuous-learning.md` (the only thing that reaches a user's `CLAUDE.md`), `skills/continuous-learning/SKILL.md`, and the `SubagentStart` briefing in `hooks/kb-gate.mts`. No single mechanism reaches all three consumers, so this is three copies rather than one source — change one and check the other two. It matters because the unguided path is measurably worse, not just slower.

**The index's `global_context` is deliberately not a fourth copy.** qmd serves that one string two ways: as the MCP server's `instructions`, once per connection, and as the `context` field of *every* search result. Guidance placed there is therefore paid for per result — at 342 characters it was 38% of a six-result response — while the only consumer it uniquely reaches is a client with no installed `CLAUDE.md` section, which cannot happen because the template is `isRequired`. So it carries identity only ("this is a project memory KB, not external documentation") and the guidance lives in the three copies that are not echoed. Resist putting the call shape back into it.
**The index's `global_context` is deliberately not a fourth copy.** qmd serves that one string two ways: as the MCP server's `instructions`, once per connection, and as the `context` field of *every* search result. Guidance placed there is therefore paid for per result — at 342 characters it was 38% of a six-result response — while the only consumer it uniquely reaches is a client with no installed `CLAUDE.md` section, which cannot happen because a pack installs every template it declares. So it carries identity only ("this is a project memory KB, not external documentation") and the guidance lives in the three copies that are not echoed. Resist putting the call shape back into it.

**The same three copies carry "retrieve before relying on a result", and the reason is only recorded here.** qmd's MCP snippet is at most five lines and 300 characters (`extractSnippet` in `store.js`, called with a hardcoded `300` from `mcp/server.js`), and it is anchored by literal substring matching of the first `lex` sub-query. When those terms are not in the matched text it falls back to the top of the chunk — in practice the file's first three lines, which for a memory is its title and `Applies to:`. Measured on a 527-document corpus, 28% of results came back title-only. So a search result is a lead, and answering from it is guessing; `get`/`multi_get` is the step that makes the answer real. The instruction is phrased as an absolute in all three copies on purpose — stating the failure condition invites the reader to decide a snippet looks complete this time. Do not "simplify" it back into step 2's old wording (`Read matching memories`), which worked only because the previous backend returned a whole chunk.

Expand All @@ -73,7 +73,7 @@ To measure any of this, `qmd bench <fixture.json> -c memories` is usable as ship

`skills/continuous-learning` (capture) and `skills/memory-audit` (audit) encode the same rules at two different times: capture decides whether to write a memory, audit decides whether to keep one.

**Capture is `isRequired: true`; audit is optional.** Capture must therefore stand alone and can never reference the audit skill's content.
**Capture must stand alone.** Audit is manual-only and a fork can drop it, so capture can never reference the audit skill's content.

**Examples must be language-neutral.** The pack installs into projects of any stack, and Swift-specific examples have slipped in more than once. `references/templates.md` is the deliberate exception, since a filled-in example has to be concrete in some language.

Expand Down
13 changes: 0 additions & 13 deletions techpack.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ components:
- id: qmd-install
displayName: qmd
description: Local search engine over markdown — no daemon, bundled SQLite + sqlite-vec
dependencies: [node]
type: configuration
shell: "npm install -g @tobilu/qmd@2.8.3"
doctorChecks:
Expand Down Expand Up @@ -91,7 +90,6 @@ components:
- id: qmd-model
displayName: Embedding model
description: Downloads Qwen3-Embedding-0.6B once (~610 MB, shared across all projects)
dependencies: [qmd-install]
type: configuration
shell: |
d=$(mktemp -d)
Expand Down Expand Up @@ -123,8 +121,6 @@ components:
# keep in sync with hooks/sync-memories.mts — it writes the index this opens.
- id: memory-loop
description: Semantic search over this project's memories, backed by local embeddings
isRequired: true
dependencies: [node, qmd-install, qmd-model]
mcp:
command: /bin/sh
args:
Expand Down Expand Up @@ -203,7 +199,6 @@ components:
- id: skill-continuous-learning
displayName: continuous-learning skill
description: Extracts learnings and decisions from sessions into memory
isRequired: true
skill:
source: skills/continuous-learning
destination: continuous-learning
Expand All @@ -219,15 +214,13 @@ components:
- id: hook-helpers
displayName: Shared hook helpers
description: Shared filesystem and project-path helpers for the hooks
dependencies: [node]
hook:
source: hooks/shared.mts
destination: shared.mts

- id: hook-continuous-learning
displayName: Memory loop activator
description: Reminds to evaluate learnings on each prompt
isRequired: true
hookEvent: UserPromptSubmit
hook:
source: hooks/memory-loop-activator.sh
Expand All @@ -236,7 +229,6 @@ components:
- id: hook-sync-memories
displayName: Sync memories hook
description: Indexes memories into the project's search index on session start
dependencies: [qmd-install, hook-helpers]
hookInterpreter: node --experimental-strip-types --disable-warning=ExperimentalWarning
hookEvent: SessionStart
hookAsync: true
Expand All @@ -249,7 +241,6 @@ components:
- id: hook-reindex-memories
displayName: Reindex memories hook
description: Reindexes memories when they have changed mid-session
dependencies: [qmd-install, hook-helpers]
hookInterpreter: node --experimental-strip-types --disable-warning=ExperimentalWarning
hookEvent: UserPromptSubmit
hookAsync: true
Expand All @@ -268,7 +259,6 @@ components:
- id: hook-kb-gate-turn
displayName: KB gate — turn boundary
description: Marks each new prompt so the KB check is required again per turn
dependencies: [hook-helpers]
hookInterpreter: node --experimental-strip-types --disable-warning=ExperimentalWarning
hookEvent: UserPromptSubmit
hook:
Expand All @@ -287,7 +277,6 @@ components:
- id: hook-kb-gate-record
displayName: KB gate — record searches
description: Records each KB search so delegated discovery can be checked against it
dependencies: [hook-helpers]
hookInterpreter: node --experimental-strip-types --disable-warning=ExperimentalWarning
hookEvent: PostToolUse
hookMatcher: "mcp__memory-loop__query"
Expand All @@ -305,7 +294,6 @@ components:
- id: hook-kb-gate-check
displayName: KB gate — check sub-agent spawns
description: Warns or blocks when a discovery sub-agent is spawned without KB findings in its prompt
dependencies: [hook-helpers]
hookInterpreter: node --experimental-strip-types --disable-warning=ExperimentalWarning
hookEvent: PreToolUse
# The spawn tool is `Agent` in current Claude Code and `Task` in older
Expand All @@ -323,7 +311,6 @@ components:
- id: hook-kb-subagent-brief
displayName: Sub-agent KB brief
description: Tells discovery sub-agents that the KB exists, so they search it instead of sweeping files
dependencies: [hook-helpers]
hookInterpreter: node --experimental-strip-types --disable-warning=ExperimentalWarning
hookEvent: SubagentStart
hook:
Expand Down