Files
cortex/docs/milestones/09-multi-graph.md
omigamedev d484f61b29 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
2026-02-03 09:36:08 +01:00

6.4 KiB

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

# 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

# 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
# Search across all graphs
cortex query "auth" --all-graphs

# Search specific graphs
cortex query "auth" --graphs work,personal

9.4 Graph Linking

# 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

# 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

// 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

// 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

// 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

// 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

memory_graphs       // List available graphs
memory_use_graph    // Switch active graph
memory_query        // Add optional 'graph' parameter

Project Config File

// .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