8.5 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.
CLI Reference
All commands are invoked as memory <command>.
memory 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) |
memory add memory -t "Auth flow design" -c "OAuth2 PKCE flow for SPA" --tags auth,security --status active
memory add memory -t "add command" --section "Arguments: <kind> — memory, component, task, decision" --section "Options: -t title, -c content, --tags, --status"
memory add task -t "Implement login page" --status todo
memory add decision -t "Use PostgreSQL" -c "Chose Postgres over MySQL for JSON support"
memory add component -t "UserService" -c "Handles user CRUD operations" --tags backend
memory 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) |
memory query "authentication"
memory query "database decisions" --kind decision
memory query "user service" --limit 5 --format json
memory 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) |
memory show abc123
memory show abc123 --format json
memory 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) |
memory list
memory list --kind task --status todo
memory list --tags auth,security
memory list --stale
memory list --format json
memory 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) |
memory update abc123 --status done
memory update abc123 -t "Updated title" -c "New content"
memory update abc123 --tags newtag1,newtag2
memory update abc123 --section "Notes: Updated implementation notes"
memory 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 |
memory remove abc123
memory remove abc123 --hard
memory 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 |
memory link abc123 def456 --type depends_on
memory link abc123 def456 --type contains
memory 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. |
memory graph
memory graph abc123
memory 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) |
memory children abc123
memory children abc123 --kind task
memory children abc123 --format json
memory 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) |
memory decay
memory decay --days 90
memory decay --days 0 # decay all nodes not accessed today
memory 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) |
memory serve
memory 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 memory 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 memory 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? } } |