- docs/plan.md: Master roadmap with phases and priorities - docs/milestones/01-13: Detailed specs for each feature - Updated CLAUDE.md with plan references and build commands Milestones cover: - Phase 1: Temporal versioning, auto-capture, context injection, codebase indexing - Phase 2: Daily journal, content ingestion, graph visualization, import/export - Phase 3: Multi-graph, smart retrieval, TUI dashboard, browser extension, shell completions
6.0 KiB
6.0 KiB
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
// .claude/settings.json
{
"hooks": {
"session_start": {
"command": "cortex context-hook",
"timeout": 3000
}
}
}
3.2 Context Selection
Intelligently select what to inject:
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:
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:
- Project-specific — Nodes tagged with current project
- Recent — Accessed in last 48 hours
- Tasks — Open todos/tasks
- High-relevance — Semantic match to project files
- Decisions — Past architectural decisions
3.5 MCP Resource
Expose context as an MCP resource:
// MCP resource for context
{
uri: "memory://context/current",
name: "Current Context",
description: "Relevant memories for this session"
}
Implementation
Context Hook
// src/cli/commands/context-hook.ts
export async function contextHook(): Promise<string> {
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<RankedNode[]> {
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
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
# 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 <name> |
Show context for specific project |
MCP Integration
// 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