- Add npm scripts for building Windows/Linux/macOS executables - Replace uuid package with crypto.randomUUID() for ESM compatibility - Use esbuild to pre-bundle code before pkg (fixes MCP SDK subpath exports) - Update CLI name from 'memory' to 'cortex' - Update USAGE.md with build instructions and standalone setup - Add bundle/ and build/ to .gitignore
12 KiB
Cortex — AI Project Memory & Knowledge Graph
Overview
Cortex is a CLI tool and web server for storing, linking, and searching project knowledge as a graph of typed nodes and edges. It supports hybrid search (BM25 + vector similarity + freshness), auto-decay of stale nodes, and a web portal for visualization.
Data is stored in .memory/cortex.db (SQLite) in the current working directory.
Installation & Building
Development Mode
# Install dependencies
npm install
# Build TypeScript
npm run build
# Run CLI (development)
node dist/cli/index.js <command>
# Run MCP server (development)
node dist/mcp/index.js
Standalone Executables
Build self-contained executables that don't require Node.js:
# Build for Windows (creates cortex.exe and cortex-mcp.exe)
npm run package:win
# Build for Linux
npm run package:linux
# Build for macOS
npm run package:mac
# Build all (CLI + MCP for current platform)
npm run package
Output files (in build/ directory):
cortex.exe/cortex— CLI toolcortex-mcp.exe/cortex-mcp— MCP server for Claude Code integration
Running Standalone
# CLI
./build/cortex.exe list
./build/cortex.exe query "authentication"
./build/cortex.exe serve --port 3100
# MCP server (for Claude Code)
./build/cortex-mcp.exe
CLI Reference
All commands are invoked as cortex <command> (standalone) or node dist/cli/index.js <command> (dev).
cortex add <kind>
Add a node to the knowledge graph.
| Argument / Option | Required | Description |
|---|---|---|
<kind> |
yes | Node kind: memory, component, task, decision |
-t, --title <title> |
yes | Node title |
-c, --content <content> |
no | Node content/description |
--tags <tags> |
no | Comma-separated tags |
--status <status> |
no | Status (e.g. todo, doing, done, active, deprecated) |
--section <section> |
no | Structured section as "Label: body" (repeatable) |
cortex add memory -t "Auth flow design" -c "OAuth2 PKCE flow for SPA" --tags auth,security --status active
cortex add memory -t "add command" --section "Arguments: <kind> — memory, component, task, decision" --section "Options: -t title, -c content, --tags, --status"
cortex add task -t "Implement login page" --status todo
cortex add decision -t "Use PostgreSQL" -c "Chose Postgres over MySQL for JSON support"
cortex add component -t "UserService" -c "Handles user CRUD operations" --tags backend
cortex query <text>
Search the knowledge graph using natural language. Uses hybrid BM25 + vector + freshness scoring.
| Argument / Option | Required | Description |
|---|---|---|
<text> |
yes | Natural language search query |
--kind <kind> |
no | Filter by node kind |
--limit <n> |
no | Max results (default: 10) |
--format <fmt> |
no | Output format: text or json (default: text) |
cortex query "authentication"
cortex query "database decisions" --kind decision
cortex query "user service" --limit 5 --format json
cortex show <id>
Show a node's full details, structured sections, inline children, and connections. The <id> can be a full UUID or a unique prefix.
Each call to show updates the node's lastAccessedAt timestamp, which affects freshness scoring.
If the node has metadata.sections, they render as labeled blocks. If the node has outgoing contains edges, children are listed inline before other connections.
| Argument / Option | Required | Description |
|---|---|---|
<id> |
yes | Node ID or unique prefix |
--format <fmt> |
no | Output format: text or json (default: text) |
cortex show abc123
cortex show abc123 --format json
cortex list
List nodes in the knowledge graph.
| Option | Required | Description |
|---|---|---|
--kind <kind> |
no | Filter by kind |
--status <status> |
no | Filter by status |
--tags <tags> |
no | Comma-separated tags to filter |
--limit <n> |
no | Max results |
--stale |
no | Include stale/decayed nodes |
--format <fmt> |
no | Output format: text or json (default: text) |
cortex list
cortex list --kind task --status todo
cortex list --tags auth,security
cortex list --stale
cortex list --format json
cortex update <id>
Update an existing node's fields.
| Argument / Option | Required | Description |
|---|---|---|
<id> |
yes | Node ID or unique prefix |
-t, --title <title> |
no | New title |
-c, --content <content> |
no | New content |
--status <status> |
no | New status |
--tags <tags> |
no | Replace tags (comma-separated) |
--stale |
no | Mark as stale |
--section <section> |
no | Structured section as "Label: body" (repeatable, replaces by label) |
cortex update abc123 --status done
cortex update abc123 -t "Updated title" -c "New content"
cortex update abc123 --tags newtag1,newtag2
cortex update abc123 --section "Notes: Updated implementation notes"
cortex remove <id>
Remove a node. Default is soft delete (marks as stale). Use --hard for permanent deletion.
| Argument / Option | Required | Description |
|---|---|---|
<id> |
yes | Node ID or unique prefix |
--hard |
no | Permanently delete instead of marking stale |
cortex remove abc123
cortex remove abc123 --hard
cortex link <fromId> <toId>
Create a directed edge between two nodes.
| Argument / Option | Required | Description |
|---|---|---|
<fromId> |
yes | Source node ID or prefix |
<toId> |
yes | Target node ID or prefix |
--type <type> |
yes | Edge type: depends_on, contains, implements, blocked_by, subtask_of, relates_to, supersedes, about |
cortex link abc123 def456 --type depends_on
cortex link abc123 def456 --type contains
cortex graph [id]
Visualize the knowledge graph as an ASCII tree. Optionally root at a specific node.
| Argument | Required | Description |
|---|---|---|
[id] |
no | Root node ID or prefix. Omit for full graph. |
cortex graph
cortex graph abc123
cortex children <id>
List child nodes connected via outgoing contains edges from the given node.
| Argument / Option | Required | Description |
|---|---|---|
<id> |
yes | Parent node ID or prefix |
--kind <kind> |
no | Filter children by kind |
--format <fmt> |
no | Output format: text or json (default: text) |
cortex children abc123
cortex children abc123 --kind task
cortex children abc123 --format json
cortex decay
Run auto-decay to mark old untouched nodes as stale. Nodes whose lastAccessedAt exceeds the threshold are marked stale and hidden from default listings and search.
| Option | Required | Description |
|---|---|---|
--days <number> |
no | Max age in days before decay (default: 180) |
cortex decay
cortex decay --days 90
cortex decay --days 0 # decay all nodes not accessed today
cortex serve
Start the Cortex Portal web server. Auto-decay runs on startup and every 24 hours.
| Option | Required | Description |
|---|---|---|
-p, --port <number> |
no | Port number (default: 3100) |
cortex serve
cortex serve --port 8080
Node Kinds
| Kind | Purpose |
|---|---|
memory |
General knowledge, notes, context |
component |
Code components, services, modules |
task |
Work items, todos |
decision |
Architectural or design decisions |
Edge Types
| Type | Meaning |
|---|---|
depends_on |
Source depends on target |
contains |
Source contains target |
implements |
Source implements target |
blocked_by |
Source is blocked by target |
subtask_of |
Source is a subtask of target |
relates_to |
General relationship |
supersedes |
Source supersedes/replaces target |
about |
Source is about target |
Structured Sections
Nodes can have structured content via metadata.sections. Each section has a label and body. Use the --section "Label: body" flag on add or update to create sections.
When displayed with cortex show, sections render as:
── Arguments ──
<kind> — memory, component, task, decision
── Options ──
-t title, -c content, --tags, --status
The show command also displays inline children (nodes linked via contains edges). Use cortex children <id> to list only children.
Search Scoring
Search combines three signals:
- BM25 (weight 0.25) — text relevance
- Vector similarity (weight 0.60) — semantic similarity via embeddings (requires Ollama)
- Freshness (weight 0.15) — exponential decay based on
lastAccessedAt
Freshness multiplier: e^(-0.01 * ageDays) — half-life ~69 days. Recently accessed nodes are boosted; old untouched nodes are penalized but not zeroed.
REST API
The web server exposes these endpoints under /api:
| Method | Path | Description |
|---|---|---|
GET |
/api/nodes |
List nodes. Query params: kind, status, tags, limit, includeStale |
GET |
/api/nodes/:id |
Get node + connections |
POST |
/api/nodes |
Create node. Body: { kind, title, content?, status?, tags?, metadata? } |
PATCH |
/api/nodes/:id |
Update node. Body: { title?, content?, status?, tags?, metadata?, isStale? } |
DELETE |
/api/nodes/:id |
Delete node. Query param: hard=true for permanent delete |
POST |
/api/edges |
Create edge. Body: { fromId, toId, type, metadata? } |
DELETE |
/api/edges/:id |
Delete edge |
GET |
/api/graph |
Get full graph (nodes + edges) for visualization |
POST |
/api/search |
Search. Body: { text, options?: { kind?, tags?, limit?, includeStale? } } |
MCP Server (Claude Code Integration)
Cortex includes an MCP (Model Context Protocol) server that exposes memory tools directly to Claude Code.
Setup (Development)
- Build the project:
npm run build - Ensure
.mcp.jsonexists in the project root:
{
"mcpServers": {
"memory": {
"command": "node",
"args": ["./dist/mcp/index.js"]
}
}
}
- Restart Claude Code — the memory tools will appear automatically.
Setup (Standalone Executable)
- Build the MCP server:
npm run package:win(orpackage:linux/package:mac) - Configure
.mcp.jsonto use the standalone executable:
{
"mcpServers": {
"memory": {
"command": "./build/cortex-mcp.exe"
}
}
}
Or with an absolute path for use from any directory:
{
"mcpServers": {
"memory": {
"command": "C:/path/to/cortex-mcp.exe"
}
}
}
- Restart Claude Code — the memory tools will appear automatically.
MCP Tools
| Tool | Description | Parameters |
|---|---|---|
memory_query |
Hybrid search (BM25 + vector + freshness) | text, kind?, limit? |
memory_show |
Show node by ID or prefix with connections | id |
memory_list |
List nodes with filters | kind?, status?, tags?, limit? |
memory_children |
List children of a node | id, kind? |
memory_add |
Add a new node | kind, title, content?, tags?, status?, sections? |
memory_link |
Create an edge between nodes | fromId, toId, type |
memory_split |
Break a large node into smaller children | id, pieces, summary? |
memory_merge |
Merge multiple nodes into one | nodeIds, title, content, kind? |
memory_dedupe |
Find similar/duplicate nodes | threshold?, kind?, limit? |
memory_prune |
Clean up stale nodes or orphans | mode, maxAgeDays? |
memory_reorganize |
Move a node under a new parent | nodeId, newParentId |
memory_bulk_tag |
Add/remove tags on multiple nodes | action, tags, nodeIds?, filter? |
memory_stats |
Get graph statistics | — |
memory_summary |
Get hierarchical summary of the graph | refresh? |
memory_prompt |
Execute natural language instruction | prompt |
Manual Testing
# Development
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"0.1"}}}' | node dist/mcp/index.js
# Standalone
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"0.1"}}}' | ./build/cortex-mcp.exe