# Milestone 3: Context Injection ## Overview Automatically inject relevant memories into Claude's context at session start. Claude begins every conversation already "knowing" relevant history. ## Motivation - Eliminates "Claude doesn't remember" frustration - No manual "let me search my notes" workflow - Supermemory's most impactful feature - Makes memory system invisible to users ## Features ### 3.1 Session Start Hook ```json // .claude/settings.json { "hooks": { "session_start": { "command": "cortex context-hook", "timeout": 3000 } } } ``` ### 3.2 Context Selection Intelligently select what to inject: ```typescript interface ContextSelection { recentWork: Node[]; // Last 24-48 hours of activity projectContext: Node[]; // Indexed codebase info relevantMemories: Node[]; // Semantic match to current directory userPreferences: Node[]; // User's stated preferences openTasks: Node[]; // Incomplete tasks } ``` ### 3.3 Context Budget Manage token usage with configurable limits: ```typescript interface ContextConfig { maxTokens: number; // Default: 4000 maxNodes: number; // Default: 20 includeRecent: boolean; // Include recent work includeProject: boolean; // Include project index includeTasks: boolean; // Include open tasks customQuery?: string; // Additional filter query } ``` ### 3.4 Priority Ranking Rank memories for inclusion: 1. **Project-specific** — Nodes tagged with current project 2. **Recent** — Accessed in last 48 hours 3. **Tasks** — Open todos/tasks 4. **High-relevance** — Semantic match to project files 5. **Decisions** — Past architectural decisions ### 3.5 MCP Resource Expose context as an MCP resource: ```typescript // MCP resource for context { uri: "memory://context/current", name: "Current Context", description: "Relevant memories for this session" } ``` ## Implementation ### Context Hook ```typescript // src/cli/commands/context-hook.ts export async function contextHook(): Promise { const cwd = process.cwd(); const projectName = path.basename(cwd); // Gather context candidates const candidates = await gatherCandidates(cwd, projectName); // Rank and select within budget const selected = selectWithinBudget(candidates, config.maxTokens); // Format for Claude return formatContext(selected); } async function gatherCandidates(cwd: string, project: string): Promise { const results: RankedNode[] = []; // Recent work (last 48h) const recent = await listNodes({ limit: 10, // Custom: accessed in last 48h }); results.push(...recent.map(n => ({ node: n, score: 0.8, reason: 'recent' }))); // Project-tagged nodes const projectNodes = await listNodes({ tags: [project] }); results.push(...projectNodes.map(n => ({ node: n, score: 0.9, reason: 'project' }))); // Open tasks const tasks = await listNodes({ kind: 'task', status: 'todo' }); results.push(...tasks.map(n => ({ node: n, score: 0.7, reason: 'task' }))); // Semantic search on README/package.json const projectContext = await getProjectContext(cwd); if (projectContext) { const semantic = await query(projectContext, { limit: 10 }); results.push(...semantic.map(n => ({ node: n.node, score: n.score, reason: 'semantic' }))); } return dedupeAndRank(results); } ``` ### Context Formatting ```typescript function formatContext(nodes: RankedNode[]): string { const sections: string[] = []; // Group by reason const byReason = groupBy(nodes, 'reason'); if (byReason.project?.length) { sections.push(`## Project Context\n${formatNodes(byReason.project)}`); } if (byReason.recent?.length) { sections.push(`## Recent Work\n${formatNodes(byReason.recent)}`); } if (byReason.task?.length) { sections.push(`## Open Tasks\n${formatNodes(byReason.task)}`); } if (byReason.semantic?.length) { sections.push(`## Related Memories\n${formatNodes(byReason.semantic)}`); } return sections.join('\n\n'); } ``` ### Configuration ```bash # Configure context injection cortex config set context.maxTokens 4000 cortex config set context.maxNodes 20 cortex config set context.includeRecent true cortex config set context.includeTasks true ``` ## CLI Commands | Command | Description | |---------|-------------| | `cortex context-hook` | Hook handler (outputs context to stdout) | | `cortex context` | Preview what context would be injected | | `cortex context --project ` | Show context for specific project | ## MCP Integration ```typescript // MCP resource server.resource({ uri: 'memory://context/current', name: 'Session Context', mimeType: 'text/markdown', async read() { const context = await generateContext(); return { text: context }; } }); // MCP tool server.tool('memory_context', 'Get relevant context for current session', { project: z.string().optional(), maxTokens: z.number().optional() }, async ({ project, maxTokens }) => { const context = await generateContext({ project, maxTokens }); return { content: [{ type: 'text', text: context }] }; }); ``` ## Testing - [ ] Hook outputs valid markdown - [ ] Context respects token budget - [ ] Project-specific nodes ranked highest - [ ] Recent nodes included - [ ] Open tasks included - [ ] No duplicate nodes in output - [ ] Performance <500ms ## Acceptance Criteria - [ ] Context auto-injected at session start - [ ] Relevant memories appear without user action - [ ] Token budget respected - [ ] Configurable what to include - [ ] Works in any project directory - [ ] Graceful when no relevant memories ## Estimated Effort - Hook implementation: 3 hours - Context gathering: 4 hours - Ranking algorithm: 3 hours - Configuration: 2 hours - MCP integration: 2 hours - Testing: 2 hours - **Total: ~16 hours** ## Dependencies - Milestone 4 (Codebase Indexing) enhances this but not required ## References - [Claude-Supermemory context injection](https://github.com/supermemoryai/claude-supermemory) - [RAG best practices](https://www.anthropic.com/research/rag)