- 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
295 lines
6.4 KiB
Markdown
295 lines
6.4 KiB
Markdown
# Milestone 9: Multi-Graph Support
|
|
|
|
## Overview
|
|
|
|
Support multiple separate knowledge graphs, one per project or context. Switch between them seamlessly.
|
|
|
|
## Motivation
|
|
|
|
- Different projects have different knowledge domains
|
|
- Prevents cross-contamination of contexts
|
|
- Enables project-specific memory without noise
|
|
- Clean separation of concerns
|
|
|
|
## Features
|
|
|
|
### 9.1 Graph Management
|
|
|
|
```bash
|
|
# List all graphs
|
|
cortex graphs
|
|
|
|
# Create new graph
|
|
cortex graphs create work
|
|
cortex graphs create personal
|
|
|
|
# Switch active graph
|
|
cortex use work
|
|
cortex use personal
|
|
|
|
# Delete graph
|
|
cortex graphs delete old-project
|
|
```
|
|
|
|
### 9.2 Automatic Project Detection
|
|
|
|
```bash
|
|
# Auto-detect based on .cortex file or git remote
|
|
cd ~/projects/myapp
|
|
cortex query "auth" # Automatically uses 'myapp' graph
|
|
|
|
# Explicit override
|
|
cortex query "auth" --graph personal
|
|
```
|
|
|
|
### 9.3 Cross-Graph Search
|
|
|
|
```bash
|
|
# Search across all graphs
|
|
cortex query "auth" --all-graphs
|
|
|
|
# Search specific graphs
|
|
cortex query "auth" --graphs work,personal
|
|
```
|
|
|
|
### 9.4 Graph Linking
|
|
|
|
```bash
|
|
# Link nodes across graphs
|
|
cortex link abc123 --to def456 --graph work
|
|
|
|
# Reference external graph nodes
|
|
cortex show work:abc123 # graph:nodeId syntax
|
|
```
|
|
|
|
### 9.5 Graph Configuration
|
|
|
|
```bash
|
|
# Set default graph
|
|
cortex config set default-graph work
|
|
|
|
# Project-specific graph mapping
|
|
# In .cortex.json or .cortex file:
|
|
{
|
|
"graph": "myapp"
|
|
}
|
|
```
|
|
|
|
## Implementation
|
|
|
|
### Storage Structure
|
|
|
|
```
|
|
~/.cortex/
|
|
├── graphs/
|
|
│ ├── default/
|
|
│ │ └── cortex.db
|
|
│ ├── work/
|
|
│ │ └── cortex.db
|
|
│ └── personal/
|
|
│ └── cortex.db
|
|
├── config.json
|
|
└── graph-links.db # Cross-graph references
|
|
```
|
|
|
|
### Graph Manager
|
|
|
|
```typescript
|
|
// src/core/graphs.ts
|
|
export interface GraphInfo {
|
|
name: string;
|
|
path: string;
|
|
nodeCount: number;
|
|
lastAccessed: number;
|
|
createdAt: number;
|
|
}
|
|
|
|
export function listGraphs(): GraphInfo[] {
|
|
const graphsDir = path.join(getConfigDir(), 'graphs');
|
|
const dirs = fs.readdirSync(graphsDir);
|
|
|
|
return dirs.map(name => ({
|
|
name,
|
|
path: path.join(graphsDir, name),
|
|
...getGraphStats(path.join(graphsDir, name, 'cortex.db')),
|
|
}));
|
|
}
|
|
|
|
export function createGraph(name: string): void {
|
|
const graphPath = path.join(getConfigDir(), 'graphs', name);
|
|
fs.mkdirSync(graphPath, { recursive: true });
|
|
initializeDatabase(path.join(graphPath, 'cortex.db'));
|
|
}
|
|
|
|
export function useGraph(name: string): void {
|
|
const graphPath = path.join(getConfigDir(), 'graphs', name);
|
|
if (!fs.existsSync(graphPath)) {
|
|
throw new Error(`Graph '${name}' does not exist`);
|
|
}
|
|
setActiveGraph(name);
|
|
}
|
|
|
|
export function getActiveGraph(): string {
|
|
// Check project-local .cortex file
|
|
const localConfig = findLocalConfig();
|
|
if (localConfig?.graph) return localConfig.graph;
|
|
|
|
// Check git remote for auto-detection
|
|
const gitRemote = getGitRemote();
|
|
if (gitRemote) {
|
|
const projectName = extractProjectName(gitRemote);
|
|
if (graphExists(projectName)) return projectName;
|
|
}
|
|
|
|
// Fall back to default
|
|
return getConfig().defaultGraph || 'default';
|
|
}
|
|
```
|
|
|
|
### Database Connection Manager
|
|
|
|
```typescript
|
|
// src/core/db.ts
|
|
let activeDb: Database | null = null;
|
|
let activeGraph: string = 'default';
|
|
|
|
export function getDb(): Database {
|
|
const currentGraph = getActiveGraph();
|
|
|
|
if (activeDb && activeGraph === currentGraph) {
|
|
return activeDb;
|
|
}
|
|
|
|
// Close previous connection
|
|
if (activeDb) {
|
|
activeDb.close();
|
|
}
|
|
|
|
// Open new connection
|
|
const dbPath = path.join(getConfigDir(), 'graphs', currentGraph, 'cortex.db');
|
|
activeDb = new Database(dbPath);
|
|
activeGraph = currentGraph;
|
|
|
|
return activeDb;
|
|
}
|
|
```
|
|
|
|
### Project Detection
|
|
|
|
```typescript
|
|
// src/core/graphs.ts
|
|
function findLocalConfig(): LocalConfig | null {
|
|
// Walk up directory tree looking for .cortex or .cortex.json
|
|
let dir = process.cwd();
|
|
while (dir !== path.dirname(dir)) {
|
|
const configPath = path.join(dir, '.cortex');
|
|
if (fs.existsSync(configPath)) {
|
|
return JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
}
|
|
const jsonPath = path.join(dir, '.cortex.json');
|
|
if (fs.existsSync(jsonPath)) {
|
|
return JSON.parse(fs.readFileSync(jsonPath, 'utf-8'));
|
|
}
|
|
dir = path.dirname(dir);
|
|
}
|
|
return null;
|
|
}
|
|
```
|
|
|
|
### Cross-Graph References
|
|
|
|
```typescript
|
|
// Parse graph:nodeId syntax
|
|
function parseNodeRef(ref: string): { graph?: string; nodeId: string } {
|
|
if (ref.includes(':')) {
|
|
const [graph, nodeId] = ref.split(':');
|
|
return { graph, nodeId };
|
|
}
|
|
return { nodeId: ref };
|
|
}
|
|
|
|
// Get node from any graph
|
|
async function getNodeFromAnyGraph(ref: string): Promise<Node | null> {
|
|
const { graph, nodeId } = parseNodeRef(ref);
|
|
if (graph) {
|
|
const originalGraph = getActiveGraph();
|
|
useGraph(graph);
|
|
const node = await getNode(nodeId);
|
|
useGraph(originalGraph);
|
|
return node;
|
|
}
|
|
return getNode(nodeId);
|
|
}
|
|
```
|
|
|
|
## CLI Commands
|
|
|
|
| Command | Description |
|
|
|---------|-------------|
|
|
| `cortex graphs` | List all graphs |
|
|
| `cortex graphs create <name>` | Create new graph |
|
|
| `cortex graphs delete <name>` | Delete graph |
|
|
| `cortex use <name>` | Switch active graph |
|
|
| `cortex <cmd> --graph <name>` | Run command on specific graph |
|
|
| `cortex query --all-graphs` | Search all graphs |
|
|
|
|
## MCP Tools
|
|
|
|
```typescript
|
|
memory_graphs // List available graphs
|
|
memory_use_graph // Switch active graph
|
|
memory_query // Add optional 'graph' parameter
|
|
```
|
|
|
|
## Project Config File
|
|
|
|
```json
|
|
// .cortex or .cortex.json in project root
|
|
{
|
|
"graph": "myproject",
|
|
"autoCapture": true,
|
|
"contextInjection": {
|
|
"maxTokens": 4000,
|
|
"includeTasks": true
|
|
}
|
|
}
|
|
```
|
|
|
|
## Testing
|
|
|
|
- [ ] Create/list/delete graphs
|
|
- [ ] Switch between graphs
|
|
- [ ] Auto-detect from .cortex file
|
|
- [ ] Auto-detect from git remote
|
|
- [ ] Cross-graph search works
|
|
- [ ] Cross-graph references resolve
|
|
- [ ] Concurrent access handles graph switching
|
|
|
|
## Acceptance Criteria
|
|
|
|
- [ ] Each project can have isolated graph
|
|
- [ ] Auto-detection based on directory
|
|
- [ ] Cross-graph search available
|
|
- [ ] Graph switching is fast (<100ms)
|
|
- [ ] No data leakage between graphs
|
|
- [ ] MCP tools respect active graph
|
|
|
|
## Estimated Effort
|
|
|
|
- Storage structure: 2 hours
|
|
- Graph manager: 4 hours
|
|
- DB connection manager: 2 hours
|
|
- Project detection: 3 hours
|
|
- Cross-graph search: 3 hours
|
|
- CLI commands: 2 hours
|
|
- Testing: 3 hours
|
|
- **Total: ~19 hours**
|
|
|
|
## Dependencies
|
|
|
|
- None (can implement independently)
|
|
|
|
## References
|
|
|
|
- [Git worktrees](https://git-scm.com/docs/git-worktree) for multi-project inspiration
|