Development record
abcd Surfaces the Right Memory at the Right Moment
Press Release
abcd ships scope-aware memory retrieval so the project's accumulated knowledge reaches you exactly when it's relevant — and never floods your context when it isn't. Memory pages carry
recallkeywords. The sameUserPromptSubmithook that injects modular rules (itd-3) also scans each prompt against memory pages across two scopes — the workspace and the user's personal store — and injects only the matching pages. Injection is budget-aware: with a fresh context window abcd surfaces full pages; as the window depletes it falls back to one-line index entries, and stays at them to the end of the session. Memory stops being an all-or-nothing wall and becomes a just-in-time lookup."Our
.abcd/memory/had grown to 140 pages across two years," said Carol, tech lead. "Loading all of it was impossible and loading none of it meant agents kept relearning the same pitfalls. Now a prompt about the auth module pulls the three auth pages and nothing else — and when I'm deep in a long session it quietly drops to titles-only so it never crowds out the actual work."
Why This Matters
abcd's .abcd/memory/ (itd-36) is a strong storage model — typed pages, a curator, quotation budgets, contradiction tracking. But it has no retrieval model beyond /abcd:memory ask, an explicit user query. A working agent gets memory all-or-nothing: either the whole corpus is injected (overflow) or none is (relearning). itd-36 bounds ingest; nothing bounds retrieval or total surfaced size.
This intent closes that gap by reusing infrastructure abcd already has. itd-3's modular rules loader is abcd's in-plugin adoption of CARL's recall engine — a UserPromptSubmit hook with domain-keyed keyword recall, signature dedup, and force-refresh-every-N. CARL's same engine drives two payloads: procedural rules and a decision-logging memory layer. abcd adopted the rules half and skipped the memory half. itd-39 adopts the half abcd skipped — and adds CARL's context brackets (adaptive injection by remaining window) as the overflow control itd-36 lacks.
What's In Scope
- Memory
recallfrontmatter — every.abcd/memory/page'ssource:frontmatter gains arecall:keyword list (the domain-keying CARL applies to rules, applied to memory pages). - Hook extension —
hooks/prompt_router_hook.py(itd-3) is extended from rules-only to rules + memory. Same recall scan, same signature dedup, same force-refresh-every-N. The hook reads two indexes:rules.jsondomains and memory-pagerecall:frontmatter. - Context brackets — injection is gated by remaining context budget, after CARL's model:
FRESH(≥70% window free) injects matched pages in full;MODERATE(40–70%) injects only highest-relevance pages;DEPLETED(<40%) injects matchingindex.mdlines only (titles, not bodies). This is the bounded-retrieval counterpart to itd-36's bounded-ingest quotation budgets. - Two-scope query — the hook queries the
index.mdof both memory scopes (<workspace>/.abcd/memory/and~/.abcd.noindex/memory/). On a recall-keyword conflict, the narrower scope wins (workspace > user). The agent never loads the union of both scopes — it loads keyword-matched, budget-bracketed pages only. abcd memory recall [keyword]CLI subcommand — diagnostic: shows which pages a given prompt/keyword would surface, and in which bracket. Bare-command-as-render discipline (per02-constraints/04-naming.md).
What's Out of Scope
- Session-sticky recall — itd-3 establishes per-prompt independent recall (no cross-prompt chaining). itd-39 inherits that model. A "pin this memory for the rest of the task" mode is a deferred candidate.
- Writing to vendor memory — the hook injects from
.abcd/memory/. It never reads or writes~/.claude/.../memory/; that directory is adev-syncharvest source only (see02-adapters.md). - Automatic scope routing of new pages — which scope a curated page lands in is a
dev-sync/ curator decision (see07-memory.mdscope-routing rule), not a retrieval-hook concern. - A separate memory MCP server — consistent with itd-3, retrieval is hook + JSON/frontmatter only; no runtime memory-editing MCP in this intent.
Reconciliation with itd-3's global-rules rejection
itd-3 explicitly rejects a global ~/.abcd.noindex/rules.json — "a personal cross-repo rules file recreates the scaffolding-accumulates-outside-the-repo failure mode." itd-39 does place a memory scope at ~/.abcd.noindex/memory/. This is deliberate, not a contradiction:
- Rules are procedural and project-shaped. A rule that applies everywhere belongs in the plugin defaults, not a personal file — hence itd-3's per-repo-only stance.
- Memory is observational and inherently cross-project. A personal working preference ("I prefer X phrasing in commit messages") or a principle that improves abcd development itself is not project-scoped knowledge — it has no per-repo home by nature. Forcing it into a repo would lose it on the next project.
The failure mode itd-3 guards against is unbounded scaffolding outside the repo. itd-39's scopes are bounded by the two-scope .abcd/ namespace (see 05-internals/03-configuration.md) and surfaced by bounded retrieval — they do not accumulate silently into every session. The economics differ; the scopes are justified.
Acceptance Criteria
BDD format, per the itd-1 discipline.
- Given an abcd-installed workspace with a memory page declaring
recall: [auth, login], when the user sends a prompt containing "auth", then that page is injected as system context within the turn and non-matching pages are not. - Given a context window below 40% free, when a memory recall matches three pages, then only the matching
index.mdlines are injected (titles, not bodies), per theDEPLETEDbracket. - Given the same prompt repeated within a session, when dedup is enabled, then the matched memory injects once and skips on repeats until the force-refresh interval.
- Given a recall keyword that matches a page in both the workspace and user scope, when the hook resolves the match, then the workspace-scope page is injected and the user-scope page is suppressed (narrower scope wins).
- Given any prompt, when the hook runs, then
~/.claude/.../memory/is never read or written by the retrieval path.
Scope Conditions
None stated.
SOTA
Surveyed on 2026-10-23; sources, evidence tiers and the local fit risks are in the memory-knowledge SOTA note.
- Harnesses recall on files, not prompt words. Claude Code's
.claude/rules/with apaths:glob loads "only when Claude works with matching files"; Cursor's "Apply to Specific Files" auto-attaches on a matching file in context and "Apply Intelligently" lets the agent pull a rule in by its description; Copilot's.github/instructions/*.instructions.mdcarries anapplyToglob (vendor docs). abcd's keyword-on-prompt recall is the outlier; a file trigger needs a tool hook the loader does not run, so it is a later seam, not a step. - Lexical ranking is the strong baseline at this size. On a six-project benchmark an information-retrieval detector from a decade ago beat the deep-learning ones by 22.3% average RR@10 "for most projects" (Zhang et al., TOSEM; duplicate-report detection, so an analogy for note recall); the context-window note already records agentic search over RAG at this scale. The spec's BM25F with no embedding stands.
- The fill signal is documented. The status line payload carries
session_id,transcript_pathandcontext_window.used_percentage(input tokens only), which "may benullearly in the session", whilecurrent_usageis null after/compactuntil the next API call (Claude Code status line docs); the spec's "unknown fill" row is the right default. - Memory systems with evaluations consolidate on write. Mem0 (Chhikara et al., arXiv 2504.19413, 2025) judges each new fact against its ten nearest memories as ADD, UPDATE, DELETE or NOOP; the hard classes in LongMemEval (ICLR 2025) are knowledge updates and abstention, not lookup. The stale page recalled with confidence is the failure to design against.
- The benchmarks are contested. Zep's rebuttal of Mem0's LoCoMo numbers (75.14% corrected against 65.99% reported), Mem0's own table showing the full-context baseline (72.90) above Mem0 (66.88, graph 68.44), and Zep's note that LoCoMo conversations fit a modern context window and lack knowledge-update questions say the leaderboard settles nothing for abcd.
- Path 2: the native design the spec holds, with Mem0's write discipline carried by the ledger's existing match primitive as an advisory echo on
memory add(see the notes intent), and the file-scoped trigger recorded as the seam. The independent fit-challenge is still owed before the build, and the questions below are kept for it.
Questions this pass raised for the fit-challenge before the build. They are kept here, not under Open Questions, so they do not hold a build the record already rules ready:
- Should a page's
recall:list later gain an optional file glob, matched against the files a session touches, as every surveyed harness scopes rules? It needs a hook the loader does not run today; the question is whether to reserve the field now or add it when a tool hook exists.
Open Questions
None open; the three questions first left here are settled under Decisions (2026-10-11), and the technical questions the plan leaves open are in the bundle's spec.
Audit Notes
Empty. Populated by intent-fidelity-reviewer when intent moves to shipped/.
Decisions
- 2026-10-11, product thinker: "Build both together". Memory pages (this intent) and memory notes (itd-2610091918433290) share one recall and are planned as one bundle. Where this intent's criteria overlap the notes intent's (the brackets; never reading the host's memory files), both criteria stand and one mechanism serves both.
- 2026-10-11, technical facilitator, the first question first left here: "Share the brackets". Memory recall uses the rules loader's context brackets (itd-3); there are no thresholds tuned separately for memory.
- 2026-10-11, technical facilitator, the second question first left here: "A relevance ranking". When the context is short and only some matching titles fit, a relevance ranking chooses the ones that stay, not the raw count of matching recall words. The spec designs a simple ranking whose choice can be explained, cites its prior art, and adds no dependency unless the person signs off.
- 2026-10-11, technical facilitator, how recall ends: "never send nothing". Recall goes full, then one-line index entries, and stays at them to the end of the session; there is no bracket in which matched pages come back as nothing, because a compaction or a new session resets recall anyway, so the one-line entries cost little and a session never loses sight of a page that matches. The press release's earlier wording, "then to nothing", was accepted into the plan with this bundle on 2026-10-11 and changed the same day by this ruling. The
DEPLETEDbracket under What's In Scope already ends at index lines and is unchanged. - 2026-10-11, technical facilitator, the diagnostic: the
abcd memory recall [keyword]subcommand under What's In Scope isabcd rules --prompt "<text>", on the existingrulesverb, showing the rules, notes and pages one prompt would bring back, in which bracket, with the ranking's reasons. Since the verb split,memoryis the agents' notes command and the rules verb already renders what the loader injects. - 2026-10-11, settled on the record, the third question first left here: release placement no longer waits. itd-36's storage model has shipped, and its store is now reached as
library ingest,library askandlibrary lint(itd-2610090831227812).
References
- Deferred to by:
itd-42(coherence-aware grill) — itd-42's Tier 3 is index-level only; full-body cross-intent comparison at scale is this intent's selective-retrieval problem.
Grounds
- pursued: We expect the right page to reach an agent when it matters, without crowding the context. Shown wrong if matched pages are mostly irrelevant, or if recall crowds out the work.
Frontmatter
| id | itd-39 |
|---|---|
| type | intent |
| lifecycle | planned |
| kind | bundle-member |
| severity | minor |
.abcd/development/intents/planned/itd-39-scope-aware-memory-retrieval.md
open on GitHub ↗ · commit history ↗
References1
- itd-2610091918433290Agents keep memory notes with /abcd:memory, recalled when they matterrelated
Referenced by23
- adr-2610091918443997What may enter abcd's memory notes without the person's yes, and how a note reaches the recordrelated
- iss-2610262031560983itd-39 extends a Python hook, hooks/prompt_router_hook.py; 02-dependencies says abcd ships as a single Go binary with no required external tools.related
- iss-261026203156590604-tradeoffs records /abcd:memory as the curated store's command with ingest/ask/lint; itd-39 says memory is now the agents' notes command and the store is reached through library.related
- iss-2610262033124129itd-39 extends a Python prompt-router hook; the ahoy chapter says every hook event command is a shim that finds and runs the abcd binaryrelated
- iss-2610262033126804itd-39 names a 'workspace' memory scope; the ahoy chapter says abcd has no workspace layer, only the repository and the user scoperelated
- iss-2610262034370169itd-39's hook queries a user-scope memory store at ~/.abcd.noindex/memory/; the library chapter lists user-scope memory outside the repo as not built.related
- iss-2610262034384038The library chapter says the memory command merged into library; itd-39 uses memory as the live name of the agents' notes command.related
- iss-2610262039325628itd-39 extends a Python hook file `hooks/prompt_router_hook.py`; the configuration chapter says the prompt router is the binary's `abcd hook prompt-router` entrypointrelated
- iss-2610262039330569itd-39 reuses the rules loader's context brackets (itd-3); the configuration chapter's loader has no context brackets and attributes the budget bracket to itd-39 itselfrelated
- iss-2610262039345320itd-39 has the prompt hook inject `.abcd/memory/` pages automatically on a prompt match; the surfaces register says library material comes back only when the person asksrelated
- iss-2610262041226231The memory chapter names the recall diagnostic a `recall` sub-verb of `abcd library`; itd-39 rules that the same diagnostic is `abcd rules --prompt` on the rules verbrelated
- iss-2610262041234230itd-39 extends a Python script `hooks/prompt_router_hook.py`; the memory chapter says the prompt router is a binary sub-command, not a script file in `hooks/`related
- iss-2610262041245870itd-39 keeps the prompt router's force-refresh-every-N; the verification matrix says the refresh is event-driven and nothing counts promptsrelated
- iss-2610262043026422itd-26 names the knowledge-ingest verb '/abcd:memory ingest'; itd-39 records that 'memory' is now the agents' notes command.related
- iss-2610262043030522The sources-corpus draft names its ingest, consult and lint 'source add', a consult verb and a corpus lint; itd-39 says the store is already reached as library ingest, ask and lint.related
- iss-2610262044561718itd-39 reuses the rules loader's context brackets from itd-3, but itd-3's loader defines no bracketsrelated
- iss-2610262044572933itd-39 plans to extend a Python prompt-router hook; itd-105 says the plugin's hooks call the abcd binaryrelated
- iss-2610262045091104itd-39 extends a Python hook, hooks/prompt_router_hook.py; itd-66 says the payload has no Python and hooks/ ships shellrelated
- iss-2610262045100283The prompt router is the Python file hooks/prompt_router_hook.py in itd-39 and the shipped hidden verb `hook prompt-router` in itd-89related
- iss-2610262045119850abcd's user-level home is ~/.abcd.noindex/ in itd-39 and ~/.abcd/ in itd-76related
- iss-2610262045183188itd-42 defers full-body comparison of intents to itd-39; itd-39 recalls keyword-matched memory pages and compares no intent bodiesrelated
- itd-44A Capture-Time `decision` Verdict That Routes Infrastructure Choices Into The Existing ADR Storebuilt on by
- spc-2610111627213138memory-recallimplemented by
mentions15
- dcn-26110113322914222026-11-01 — The product thinker's ruling of 2026-11-01 on iss-2610312234315875: abcd intent ready gates on the claim_sections start check, so READY means abcd build will start. That check binds both claim rows, an unanswered or empty Mechanism and unrecorded Scope Conditions, so this reverses the earlier ruling on iss-2609091009111294 for both rows; the ruling's stated ground, that READY means the build will start, holds only if both gate, so the scope was read from it rather than asked again. A Scope Conditions section holding the token None stated. satisfies its half. Grounds: on 2026-10-31 intent ready called itd-39 READY and the build then refused it at claim_sections. Reverse by a later ruling that makes either row advisory again.
- iss-2608221254560250docs/reference/terminology.md Memory row describes retrieval as 'recall-matched and budget-bracketed', but no retrieval engine exists: the recall: frontmatter field is parsed and round-tripped yet never consumed, and the budget brackets live only in itd-39 (draft). The row overstates shipped behaviour.
- iss-261025221540886707-memory.md:181-195 describes memory-page recall with FRESH/MODERATE/DEPLETED brackets as shipped behaviour; itd-39 is in intents/planned/, the shipped router recalls memory.json notes (03-configuration.md:976; internal/core/rules/rules.go:394-395), and no bracket exists in the code
- iss-2610262040213900The memory chapter gives the prompt router a refresh every N prompts; the verification matrix says the refresh is event-driven and nothing counts prompts.
- iss-2610311224587853The board's Next list, which the product thinker picks build runs from, shows as ready two intents that abcd build refuses from the record alone, before any reservation is read: itd-50, whose spec spc-2609211924346308 has no ## Footprint packages line, and itd-39, whose ## Open Questions section the build counts as asking one question. The pick-order head skips such intents, but Next lists them unmarked, so a person who chooses from Next gets a refusal instead of a run and cannot tell the two kinds of ready apart.
- iss-2610311224596015itd-39's ## Open Questions section is one bullet, 'None for the product thinker. The three questions first left here are settled under Decisions (2026-10-11); …', and the fail-closed reader in internal/core/intent/questions.go counts every list item without a resolved or deferred marker as a question, so abcd build itd-39 refuses at open_questions (itd-2610091918433290, which shares spec spc-2610111627213138, reads only its own section and was refused at the reservation instead). The record says it is settled in a form the reader does not recognise.
- iss-2610311501473953abcd intent ready itd-39 reported the intent READY on 2026-10-31, listing scope_conditions as an advisory row ('no ## Scope Conditions section — the context claim is unrecorded'), and abcd build itd-39 then refused it at claim_sections for the same missing section. ReadyWithQuestions (internal/core/intent/ready.go) appends only the open-questions start check to the readiness verdict, so READY still does not mean the build will start, the defect iss-2610101610446956 fixed for open questions alone.
- iss-2610312234315875Whether abcd intent ready gates on the claim_sections start check was ruled on 2026-11-01 (dcn-2611011332291422): it gates. Before that ruling, gating it would have reversed their ruling on iss-2609091009111294, which kept the mechanism and scope-condition rows advisory, so intent ready can report READY on a record that abcd build then refuses at claim_sections, as itd-39 showed on 2026-10-31. Split from iss-2610311501473953 so its drain-buildable half carries no ruling.
- iss-2611012202511008The claude runner kills a routed role at its default one-hour bound (internal/core/runner/runner.go, DefaultTimeout), and an implementer's work in this repository can outlast it: on 2026-11-01 the routed implementer of run-2611012100266247 committed its fix, wrote its report and, running its definition of done over the whole internal tree after the loop package alone took 1,459 seconds, was killed at 1h0m0s before writing its receipt. The kill counted as a failed start, the role fell back to the host and the lane parked, with finished, tested work stranded behind a missing receipt. The same night two more routed implementers, on itd-39 and itd-2610142145236613, were killed at the hour (22:52 and 22:53 UTC) partway through make preflight, which their briefs named as the definition of done, each with its work committed and its report written, and each fell back to the host. A killed launch reports no result and so no total_cost_usd, so all three launches' spend is missing from every tally. A receipt the host writes after such a kill also loses whatever the implementer meant to resolve beyond the issue it was handed: one killed implementer's report asked its landing to resolve a second issue, the host's receipt left it out, and an accepted receipt cannot gain a resolve, so that issue waits for a separate records change.
- itd-1Every Intent Has Acceptance Criteria; Every Audit Verifies Them
- itd-3abcd Loads Its Own Rules On Demand
- itd-36Knowledge That Compounds, Not Knowledge That Re-Derives
- itd-42Grill Reads an Intent Against the Brief and Its Siblings, Not Just the Glossary
- itd-2609292109214516Rule injection is a seam: the native loader stays the default, and an opt-in CARL back end can take it over
- itd-2610090831227812A person who types `/abcd:` sees the commands people use