5.6 KiB
5.6 KiB
Phase 1 PR #3 Checklist: Memory Category Structure
Created: 2026-02-12 Owner: Flynn core Status: ready to implement
Goal
Introduce structured memory categories while preserving current memory behavior.
Categories:
factspreferencesdecisionsprojects
This PR is infrastructure-only: no new user-facing commands yet.
PR Boundary
In scope:
- Add category types/constants/utilities
- Add category-aware
MemoryStoreAPIs - Keep existing
read/write/search/getContextForPromptbehavior intact - Add category-aware retrieval helpers for follow-on PRs
- Unit tests for compatibility and correctness
Out of scope:
- Auto-categorization/extraction heuristics
- New slash commands (
/memory add --category ...) - Migration CLI that rewrites existing files
- UI/dashboard for category browsing
Compatibility Model
Existing flat namespaces remain valid:
userglobalsessions/<id>
Category namespaces are additive and path-based:
user/factsuser/preferencesglobal/decisionssessions/<id>/projects
No destructive migration in this PR.
File-by-File Diff Plan
src/memory/categories.ts(new)
- Add category constants and helpers.
export const MEMORY_CATEGORIES = ['facts', 'preferences', 'decisions', 'projects'] as const;
export type MemoryCategory = (typeof MEMORY_CATEGORIES)[number];
export function isMemoryCategory(value: string): value is MemoryCategory {
return (MEMORY_CATEGORIES as readonly string[]).includes(value);
}
export function categoryNamespace(baseNamespace: string, category: MemoryCategory): string {
return `${baseNamespace}/${category}`;
}
src/memory/store.ts(modify)
- Add category-aware methods without changing existing API behavior.
New methods:
readCategory(baseNamespace: string, category: MemoryCategory): stringwriteCategory(baseNamespace: string, category: MemoryCategory, content: string, mode: 'append' | 'replace'): voidlistCategories(baseNamespace: string): MemoryCategory[]readAllCategories(baseNamespace: string): Partial<Record<MemoryCategory, string>>search(query: string, opts?: { categories?: MemoryCategory[]; baseNamespacePrefix?: string }): SearchResult[]
Notes:
- Keep old
search(query: string)call pattern working via optionalopts. - Ensure dirty namespace tracking marks category namespaces too.
- Keep
getContextForPrompt()backward compatible: include legacy sections first, then category sections if present and token budget allows.
src/memory/index.ts(modify)
- Export category types/utilities.
export * from './categories.js';
src/memory/categories.test.ts(new)
- Validate category constants/helpers:
isMemoryCategorytrue/false paths- namespace composition correctness
src/memory/store.test.ts(modify/add)
- Add category coverage:
- category read/write/append/replace
- list/readAll categories
- filtered search by category
- backward compatibility for legacy namespaces
getContextForPrompt()includes legacy + category content under token budget
src/tools/builtin/memory.ts(modify docs-only or no-op code)
- If tool schemas/docs mention namespaces, document category namespace pattern so next PR can add command-level category args cleanly.
Implementation Steps
- Add
categories.tswith constants/types/helpers. - Extend
MemoryStorewith category methods (additive only). - Extend
searchto support optional category filters. - Update prompt context composition to include categories safely.
- Export new memory APIs from memory index barrel.
- Add unit tests for category + compatibility behavior.
- Run full validation.
Validation Commands
pnpm typecheck
pnpm test:run src/memory/categories.test.ts
pnpm test:run src/memory/store.test.ts
pnpm test:run
pnpm lint
pnpm build
Acceptance Criteria
- Existing memory paths (
user,global,sessions/<id>) still work unchanged. - Category APIs function for all four categories.
- Search works both with and without category filters.
- No data loss or rewrite required for existing memory files.
getContextForPrompt()remains stable and token-bounded.- Dirty namespace/indexing behavior remains correct for new category paths.
- All existing tests pass; new memory tests added.
Quality Gates
- Backward compatibility:
- Legacy reads/writes/searches unchanged.
- Old memory files remain readable with zero migration.
- Retrieval correctness:
- Category-filtered searches return only matching namespaces.
- Unfiltered searches still span all namespaces.
- Performance:
- No meaningful regression for unfiltered search/list operations.
- Category filtering avoids unnecessary extra scans where possible.
- Reliability:
- Missing category files return empty strings (not errors).
- Invalid categories are rejected at type-level and guarded in runtime helper paths.
Risks and Mitigations
- Risk: subtle prompt-context ordering changes.
- Mitigation: preserve legacy section order, append category sections after legacy content.
- Risk: token budget overrun from extra sections.
- Mitigation: enforce existing truncation logic after composing all sections.
- Risk: search API break due to signature change.
- Mitigation: keep
optsoptional and maintain old call contract.
- Mitigation: keep
Suggested Commit Message
feat(memory): add structured category namespaces with backward-compatible APIs
Follow-up PRs
- Add category-aware memory tool arguments and slash command UX.
- Add auto-extraction into categories during compaction/memory pipeline.
- Add migration/normalization utility for legacy memory into categories.