- 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
400 lines
12 KiB
Markdown
400 lines
12 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```bash
|
|
# 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 tool
|
|
- `cortex-mcp.exe` / `cortex-mcp` — MCP server for Claude Code integration
|
|
|
|
### Running Standalone
|
|
|
|
```bash
|
|
# 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) |
|
|
|
|
```bash
|
|
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`) |
|
|
|
|
```bash
|
|
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`) |
|
|
|
|
```bash
|
|
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`) |
|
|
|
|
```bash
|
|
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) |
|
|
|
|
```bash
|
|
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 |
|
|
|
|
```bash
|
|
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` |
|
|
|
|
```bash
|
|
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. |
|
|
|
|
```bash
|
|
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`) |
|
|
|
|
```bash
|
|
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) |
|
|
|
|
```bash
|
|
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) |
|
|
|
|
```bash
|
|
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)
|
|
|
|
1. Build the project: `npm run build`
|
|
2. Ensure `.mcp.json` exists in the project root:
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"memory": {
|
|
"command": "node",
|
|
"args": ["./dist/mcp/index.js"]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
3. Restart Claude Code — the memory tools will appear automatically.
|
|
|
|
### Setup (Standalone Executable)
|
|
|
|
1. Build the MCP server: `npm run package:win` (or `package:linux`/`package:mac`)
|
|
2. Configure `.mcp.json` to use the standalone executable:
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"memory": {
|
|
"command": "./build/cortex-mcp.exe"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Or with an absolute path for use from any directory:
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"memory": {
|
|
"command": "C:/path/to/cortex-mcp.exe"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
3. 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
|
|
|
|
```bash
|
|
# 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
|
|
```
|