Add development plan with 13 milestone specifications
- 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
This commit is contained in:
238
docs/milestones/03-context-injection.md
Normal file
238
docs/milestones/03-context-injection.md
Normal file
@@ -0,0 +1,238 @@
|
||||
# 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<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
|
||||
|
||||
```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 <name>` | 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)
|
||||
Reference in New Issue
Block a user