MindGraph Skill
MindGraph is a structured knowledge graph index for sub-agents, cross-file constraint lookups, and semantic search. Files (MEMORY.md, daily notes) are canonical — MindGraph provides structured relationships and search on top of them.
Setup: Cloud vs Local
MindGraph can run as a cloud API or a local self-hosted server. Set two env vars to choose:
Cloud API (recommended — no server, no binary, embeddings included)
export MINDGRAPH_URL=https://api.mindgraph.cloud
export MINDGRAPH_TOKEN=your-api-key # from mindgraph.cloud/signup
- No binary to install or start
- Embeddings handled server-side — no
OPENAI_API_KEY needed
start.sh is a no-op when MINDGRAPH_URL starts with https://
Local Server (self-hosted)
bash install.sh # downloads pre-built binary from GitHub Releases
bash start.sh # starts server on port 18790
export OPENAI_API_KEY=sk-... # required for semantic/hybrid search
- Runs at
http://127.0.0.1:18790 by default
- Token auto-generated and saved to
data/mindgraph.json on first start
MINDGRAPH_TOKEN is read from data/mindgraph.json automatically
Environment Variables
| Variable |
Required |
Description |
MINDGRAPH_TOKEN |
Always |
Bearer token / API key |
MINDGRAPH_URL |
Cloud only |
Set to https://api.mindgraph.cloud |
OPENAI_API_KEY |
Local only |
Required for semantic/hybrid search |
File Map
All paths relative to skill root (skills/mindgraph/):
| File |
Purpose |
mindgraph-client.js |
Canonical client library. All scripts import from here. Workspace root has a symlink. |
mindgraph-bridge.js |
CLI bridge + batch writer for OpenClaw sessions. Workspace root has a symlink. |
mg-context.js |
Quick mid-conversation retrieval (FTS + semantic + subgraph). Workspace root has a symlink. |
entity-resolution.js |
5-step entity dedup module (cache → aliases → fuzzy_resolve → FTS → semantic) |
extract.js |
LLM-powered extraction from text → structured JSON (nodes + edges) |
import.js |
Import extracted JSON into graph via cognitive layer endpoints |
re-embed.js |
Graph-aware re-embedding (label + summary + neighborhood context) |
dedup.js |
Merge duplicate nodes (case-insensitive label + type grouping) |
flatten_transcript.py |
Flatten JSONL session transcripts to plain text for extraction |
SCHEMA.md |
Full node type + edge type reference (53 node types, 16+ edge types) |
start.sh / install.sh |
Server lifecycle management |
dreaming/ |
Nightly analysis pipeline (dream-analysis.js, apply-proposals.js, etc.) |
Design Conventions
- Agent Identity: Always pass
agent_id: 'jaadu' (or context-appropriate id) for changed_by provenance.
- Atomic Bundling: Use bundle endpoints (
/epistemic/argument, /action/procedure, /agent/plan) to create related nodes and edges in a single transaction.
- Narration: Narrate before writing to
/memory/config or /agent/governance as these modify behavioral rules.
- Session Framing: Call
POST /memory/session (action: open) at the start of each conversation and use the session_uid for trace entries and distillation.
props deep-merge (v0.8.0): All cognitive endpoints accept an optional props field. The server deep-merges user-provided props over its handler-constructed defaults.
- Entity
entity_type in props (v0.8.0): For entity creation, pass entity_type inside the props object. mg.manageEntity({ action: 'create', label, entityType }) handles this automatically.
- Retry logic (v5.0.6): The client automatically retries on 502/503/504 and transient network errors (ECONNRESET, ECONNREFUSED) up to 3 times with exponential backoff.
When to Use Each Tool (Decision Guide)
Retrieval: Reading from the Graph
| Situation |
Tool |
Example |
| Person/company mentioned mid-conversation |
mg-context.js --entity "name" |
node mg-context.js --entity "Aaron Goh" |
| General topic lookup |
mg-context.js "topic" |
node mg-context.js "Iran regime" |
| Exact label search |
mg-context.js --fts "label" |
node mg-context.js --fts "Income Generation" |
| Explore a node's neighborhood |
mg-context.js --neighborhood <uid> |
node mg-context.js --neighborhood 01HRX... |
| Programmatic search (in scripts) |
mg.search(query) or mg.hybridSearch(query) |
— |
| Semantic similarity |
mg.retrieve('semantic', { query }) |
— |
| Active goals/tasks/questions |
mg.retrieve('active_goals') etc. |
— |
Rule: When a named person or company is mentioned, always retrieve before responding. It's cheap (<2s).
Writing: Updating the Graph
| Trigger |
Tool |
Code |
| Decision made/confirmed |
mg.deliberate |
mg.deliberate({ action: 'open_decision', label, description }) then mg.deliberate({ action: 'resolve', decisionUid, resolutionRationale }) |
| Hard rule stated ("never X") |
mg.governance |
mg.governance({ action: 'create_policy', label, policyContent }) |
| Task committed |
mg.plan |
mg.plan({ action: 'create_task', label, description }) |
| Preference expressed |
mg.memoryConfig |
mg.memoryConfig({ action: 'set_preference', label, value }) |
| New person/org/tool |
mg.manageEntity |
mg.manageEntity({ action: 'create', label, entityType }) — dedup-safe |
| Observation worth preserving |
mg.ingest |
mg.ingest(label, content, 'observation') |
| Evidence-backed claim |
mg.addArgument |
mg.addArgument({ claim: { label, content }, evidence: [...], warrant: { label, explanation } }) |
| Anomaly/bug discovered |
mg.addInquiry |
mg.addInquiry(label, details, 'anomaly') |
| Goal progress updated |
mg.evolve |
mg.evolve('update', uid, { propsPatch: { progress: 0.5 } }) |
| Structural pattern/concept |
mg.addStructure |
mg.addStructure(label, content, 'pattern') |
Write threshold: Would this still be useful in 7 days without the chat context? If yes, write it.
Label discipline: Short noun-phrase, max 60 chars. Think Wikipedia article titles.
- ✅ "MindGraph Port Decision"
- ❌ "Decision MindGraph UI Port 8766. Status made..."
Don't write: Routine messages, heartbeat acks, search results, anything already in MEMORY.md verbatim.
Session Framing (main sessions)
// At session start:
const { session_uid } = await mg.sessionOp({ action: 'open', label: 'Session 2026-03-08 20:00', focus: '...' });
// During session — trace key reasoning/decisions:
await mg.sessionOp({ action: 'trace', session_uid, note: 'Decided X because Y' });
// At session end:
await mg.sessionOp({ action: 'close', session_uid, agent_id: 'jaadu' });
Significant Judgments (Arguments)
For market assessments, product framing decisions, job opportunity evaluations:
await mg.addArgument({
claim: { label: 'Iran Regime Fall underpriced at 37%', content: 'Fair value ~50%...' },
evidence: [{ label: 'IRGC interim council = short-term stability', description: '...' }],
warrant: { label: 'Succession contests increase instability', explanation: '...' }
});
Cognitive Layer Endpoints (The 18 Tools)
Reality Layer (Raw Input)
- POST /reality/ingest: Capture
source (web/paper/book), snippet (auto-links to source), or observation. Accepts optional props to deep-merge.
- POST /reality/entity:
create (dedup-safe via find_or_create_entity — checks alias + case-insensitive match, returns {node, created: bool}; pass entity_type inside props), alias, resolve, fuzzy_resolve, merge, or relate (creates edge between source_uid and target_uid with edge_type).
Epistemic Layer (Reasoning)
- POST /epistemic/argument: Atomic Toulmin bundle. Creates
Claim + Evidence + Warrant + Argument nodes and wires edges.
- POST /epistemic/inquiry: Record
hypothesis, anomaly, assumption, question, or open_question.
- POST /epistemic/structure: Crystallize
concept, pattern, mechanism, model, paradigm, analogy, theorem, or equation.
Intent Layer (Commitments)
- POST /intent/commitment: Declare
goal, project, or milestone.
- POST /intent/deliberation: Manage
open_decision, add_option, add_constraint, or resolve (creates DecidedOn edge).
Action Layer (Workflows)
- POST /action/procedure: Design
create_flow, add_step, add_affordance, or add_control.
- POST /action/risk:
assess a node (severity/likelihood) or get_assessments.
Memory Layer (Persistence)
- POST /memory/session:
open, trace (real-time recording), close (sets ended_at), or journal (creates a Journal node, auto-linked to session).
- POST /memory/distill: Synthesis of a session into a durable
Summary node.
- POST /memory/config:
set_preference, set_policy, get_preferences, or get_policies.
Agent Layer (Control)
- POST /agent/plan:
create_task, create_plan, add_step, update_status, or get_plan. Note: update_status uses targetUid (not taskUid).
- POST /agent/governance:
create_policy, set_budget, request_approval, or resolve_approval.
- POST /agent/execution:
start, complete, fail, or register_agent.
Connective Tissue
- POST /retrieve: Unified search:
text, semantic, hybrid (RRF fusion, k=60), active_goals, open_questions, weak_claims, pending_approvals, layer, recent.
- POST /traverse: Navigation:
chain, neighborhood, path, subgraph.
- POST /evolve: Mutation:
update, tombstone (with cascade), restore, decay, history, snapshot.
Client API (mindgraph-client.js)
const mg = require('./mindgraph-client.js');
// Reality
await mg.ingest(label, content, 'observation', { confidence, props });
await mg.manageEntity({ action: 'create', label, entityType: 'Person' });
await mg.manageEntity({ action: 'relate', sourceUid, targetUid, edgeType: 'WorksAt' });
await mg.findOrCreateEntity("Aaron Goh", "Person"); // Dedup-safe wrapper
// Epistemic
await mg.addArgument({ claim: { label, content }, evidence: [...], warrant: { label, explanation } });
await mg.addInquiry(label, content, 'anomaly', { status: 'open' });
await mg.addStructure(label, content, 'pattern', { summary: 'the lesson' });
// Intent
await mg.addCommitment(label, description, 'milestone', { parentUid, dueDate });
await mg.deliberate({ action: 'open_decision', label, description });
await mg.deliberate({ action: 'resolve', decisionUid, resolutionRationale });
// Action
await mg.procedure({ action: 'create_flow', label, description });
await mg.risk({ action: 'assess', label, assessedUid, severity: 'high', likelihood: 'medium' });
// Memory
await mg.sessionOp({ action: 'open', label, focus });
await mg.sessionOp({ action: 'trace', sessionUid, note: '...' });
await mg.sessionOp({ action: 'journal', label, summary, props: { content, journal_type: 'investigation', tags: [] } });
await mg.distill(label, content, { sessionUid });
await mg.memoryConfig({ action: 'set_preference', label, value });
// Agent
await mg.plan({ action: 'create_task', label, description, status: 'pending' });
await mg.plan({ action: 'update_status', targetUid: taskUid, status: 'completed' });
await mg.governance({ action: 'create_policy', label, policyContent });
// Search & Navigate
await mg.search(query, { limit: 10 }); // FTS
await mg.retrieve('semantic', { query, limit: 10 }); // Vector search
await mg.hybridSearch(query, { limit: 10 }); // RRF fusion (best quality)
await mg.traverse('neighborhood', uid, { maxDepth: 2 }); // Graph walk
await mg.retrieve('active_goals'); // Structured queries
// Mutate
await mg.evolve('update', uid, { label, summary, propsPatch: { status: 'active' } });
await mg.evolve('tombstone', uid, { reason: 'completed', cascade: true });
// Low-level (backward compat)
await mg.addNode(label, props, { summary, confidence });
await mg.getNode(uid);
await mg.updateNode(uid, updates, { reason });
await mg.link(fromUid, toUid, 'SUPPORTS');
await mg.getEdges(uid);
await mg.edgesTo(uid, 'SUPPORTS');
Extraction Pipeline
Full pipeline (used by heartbeat and end-of-session writeback):
# 1. Flatten transcript to plain text
python3 flatten_transcript.py <session.jsonl> --since-minutes 60 --output /tmp/conv.txt
# 2. Extract structured nodes/edges via LLM
node extract.js /tmp/conv.txt --output /tmp/extracted.json
# 3. Import into graph via cognitive layer
node import.js /tmp/extracted.json
Extract model selection:
- Files < 20KB →
gemini-3-flash-preview (fast, cheap)
- Files ≥ 20KB →
gemini-3-pro-preview (larger output)
- Files > 40KB → Auto-summarized via Flash first, then extracted
Entity resolution (during extraction):
The pipeline resolves entities post-extraction via entity-resolution.js:
- Known aliases map → 2.
fuzzy_resolve API → 3. FTS exact match → 4. Semantic similarity (0.85 threshold)
Maintenance Scripts
| Script |
What it does |
When to run |
dedup.js |
Merge nodes with identical labels (grouped by node_type::label) |
After bulk imports |
re-embed.js |
Regenerate graph-aware embeddings for all nodes |
After schema changes, periodically |
reindex-search.js |
Rebuild FTS index |
After server upgrades |
maintenance.js |
Batch watchdog + extraction trigger |
Via heartbeat |
Sub-agent Usage
Sub-agents should NOT receive MEMORY.md. Instead:
- Use
mg.retrieve and mg.traverse for context
- Use
mg.search for quick lookups
- Always pass
agentId to track provenance
Full Schema Reference
See SCHEMA.md for complete node type definitions (53 types), edge type definitions, and key distinction rules.
Key Distinctions (most common errors):
- Claim vs Observation: "X happened on date Y" → Observation. "X is currently true" → Claim.
- Claim vs Decision: "BCG X is top priority" → Decision. "BCG X is a consulting firm" → Claim.
- Claim vs Constraint: "Never give salary preemptively" → Constraint (hard=true).
- Claim vs Preference: "Shan prefers concise replies" → Preference.
- Claim vs Pattern: "Axum 0.7 uses :param syntax" → Pattern (generalizable lesson).
FTS Searchability
FTS indexes all user-authored text across 35+ string fields — not just label and summary. Use mg.search() or mg.hybridSearch().
Entity Dedup
Use mg.findOrCreateEntity(label, entityType) for all entity creation. Checks alias + case-insensitive match before creating.
Hybrid Retrieval
mg.hybridSearch(query, opts) performs Reciprocal Rank Fusion of FTS + vector results. Use this instead of separate search() + retrieve() calls.
1---2name: mindgraph-23description: Structured knowledge graph with 18 cognitive tools for agent memory and reasoning (server v0.8.0)4---5
6# MindGraph Skill
7
8MindGraph is a **structured knowledge graph index** for sub-agents, cross-file constraint lookups, and semantic search. Files (MEMORY.md, daily notes) are canonical — MindGraph provides structured relationships and search on top of them.
9
10---
11
12## Setup: Cloud vs Local
13
14MindGraph can run as a **cloud API** or a **local self-hosted server**. Set two env vars to choose:
15
16### Cloud API (recommended — no server, no binary, embeddings included)
17```bash
18export MINDGRAPH_URL=https://api.mindgraph.cloud
19export MINDGRAPH_TOKEN=your-api-key # from mindgraph.cloud/signup
20```
21- No binary to install or start
22- Embeddings handled server-side — no `OPENAI_API_KEY` needed
23- `start.sh` is a no-op when `MINDGRAPH_URL` starts with `https://`
24
25### Local Server (self-hosted)
26```bash
27bash install.sh # downloads pre-built binary from GitHub Releases
28bash start.sh # starts server on port 18790
29export OPENAI_API_KEY=sk-... # required for semantic/hybrid search
30```
31- Runs at `http://127.0.0.1:18790` by default
32- Token auto-generated and saved to `data/mindgraph.json` on first start
33- `MINDGRAPH_TOKEN` is read from `data/mindgraph.json` automatically
34
35### Environment Variables
36| Variable | Required | Description |
37|---|---|---|
38| `MINDGRAPH_TOKEN` | Always | Bearer token / API key |
39| `MINDGRAPH_URL` | Cloud only | Set to `https://api.mindgraph.cloud` |
40| `OPENAI_API_KEY` | Local only | Required for semantic/hybrid search |
41
42---
43
44## File Map
45
46All paths relative to skill root (`skills/mindgraph/`):
47
48| File | Purpose |
49|---|---|
50| `mindgraph-client.js` | **Canonical** client library. All scripts import from here. Workspace root has a symlink. |
51| `mindgraph-bridge.js` | CLI bridge + batch writer for OpenClaw sessions. Workspace root has a symlink. |
52| `mg-context.js` | Quick mid-conversation retrieval (FTS + semantic + subgraph). Workspace root has a symlink. |
53| `entity-resolution.js` | 5-step entity dedup module (cache → aliases → fuzzy_resolve → FTS → semantic) |
54| `extract.js` | LLM-powered extraction from text → structured JSON (nodes + edges) |
55| `import.js` | Import extracted JSON into graph via cognitive layer endpoints |
56| `re-embed.js` | Graph-aware re-embedding (label + summary + neighborhood context) |
57| `dedup.js` | Merge duplicate nodes (case-insensitive label + type grouping) |
58| `flatten_transcript.py` | Flatten JSONL session transcripts to plain text for extraction |
59| `SCHEMA.md` | Full node type + edge type reference (53 node types, 16+ edge types) |
60| `start.sh` / `install.sh` | Server lifecycle management |
61| `dreaming/` | Nightly analysis pipeline (dream-analysis.js, apply-proposals.js, etc.) |
62
63---
64
65## Design Conventions
66
671. **Agent Identity:** Always pass `agent_id: 'jaadu'` (or context-appropriate id) for `changed_by` provenance.
682. **Atomic Bundling:** Use bundle endpoints (`/epistemic/argument`, `/action/procedure`, `/agent/plan`) to create related nodes and edges in a single transaction.
693. **Narration:** Narrate before writing to `/memory/config` or `/agent/governance` as these modify behavioral rules.
704. **Session Framing:** Call `POST /memory/session (action: open)` at the start of each conversation and use the `session_uid` for trace entries and distillation.
715. **`props` deep-merge (v0.8.0):** All cognitive endpoints accept an optional `props` field. The server deep-merges user-provided props over its handler-constructed defaults.
726. **Entity `entity_type` in `props` (v0.8.0):** For entity creation, pass `entity_type` inside the `props` object. `mg.manageEntity({ action: 'create', label, entityType })` handles this automatically.
737. **Retry logic (v5.0.6):** The client automatically retries on 502/503/504 and transient network errors (ECONNRESET, ECONNREFUSED) up to 3 times with exponential backoff.
74
75---
76
77## When to Use Each Tool (Decision Guide)
78
79### Retrieval: Reading from the Graph
80
81| Situation | Tool | Example |
82|---|---|---|
83| Person/company mentioned mid-conversation | `mg-context.js --entity "name"` | `node mg-context.js --entity "Aaron Goh"` |
84| General topic lookup | `mg-context.js "topic"` | `node mg-context.js "Iran regime"` |
85| Exact label search | `mg-context.js --fts "label"` | `node mg-context.js --fts "Income Generation"` |
86| Explore a node's neighborhood | `mg-context.js --neighborhood <uid>` | `node mg-context.js --neighborhood 01HRX...` |
87| Programmatic search (in scripts) | `mg.search(query)` or `mg.hybridSearch(query)` | — |
88| Semantic similarity | `mg.retrieve('semantic', { query })` | — |
89| Active goals/tasks/questions | `mg.retrieve('active_goals')` etc. | — |
90
91**Rule:** When a named person or company is mentioned, always retrieve before responding. It's cheap (<2s).
92
93### Writing: Updating the Graph
94
95| Trigger | Tool | Code |
96|---|---|---|
97| Decision made/confirmed | `mg.deliberate` | `mg.deliberate({ action: 'open_decision', label, description })` then `mg.deliberate({ action: 'resolve', decisionUid, resolutionRationale })` |
98| Hard rule stated ("never X") | `mg.governance` | `mg.governance({ action: 'create_policy', label, policyContent })` |
99| Task committed | `mg.plan` | `mg.plan({ action: 'create_task', label, description })` |
100| Preference expressed | `mg.memoryConfig` | `mg.memoryConfig({ action: 'set_preference', label, value })` |
101| New person/org/tool | `mg.manageEntity` | `mg.manageEntity({ action: 'create', label, entityType })` — dedup-safe |
102| Observation worth preserving | `mg.ingest` | `mg.ingest(label, content, 'observation')` |
103| Evidence-backed claim | `mg.addArgument` | `mg.addArgument({ claim: { label, content }, evidence: [...], warrant: { label, explanation } })` |
104| Anomaly/bug discovered | `mg.addInquiry` | `mg.addInquiry(label, details, 'anomaly')` |
105| Goal progress updated | `mg.evolve` | `mg.evolve('update', uid, { propsPatch: { progress: 0.5 } })` |
106| Structural pattern/concept | `mg.addStructure` | `mg.addStructure(label, content, 'pattern')` |
107
108**Write threshold:** Would this still be useful in 7 days without the chat context? If yes, write it.
109
110**Label discipline:** Short noun-phrase, max 60 chars. Think Wikipedia article titles.
111- ✅ "MindGraph Port Decision"
112- ❌ "Decision MindGraph UI Port 8766. Status made..."
113
114**Don't write:** Routine messages, heartbeat acks, search results, anything already in MEMORY.md verbatim.
115
116### Session Framing (main sessions)
117
118```javascript
119// At session start:
120const { session_uid } = await mg.sessionOp({ action: 'open', label: 'Session 2026-03-08 20:00', focus: '...' });
121
122// During session — trace key reasoning/decisions:
123await mg.sessionOp({ action: 'trace', session_uid, note: 'Decided X because Y' });
124
125// At session end:
126await mg.sessionOp({ action: 'close', session_uid, agent_id: 'jaadu' });
127```
128
129### Significant Judgments (Arguments)
130
131For market assessments, product framing decisions, job opportunity evaluations:
132
133```javascript
134await mg.addArgument({
135 claim: { label: 'Iran Regime Fall underpriced at 37%', content: 'Fair value ~50%...' },
136 evidence: [{ label: 'IRGC interim council = short-term stability', description: '...' }],
137 warrant: { label: 'Succession contests increase instability', explanation: '...' }
138});
139```
140
141---
142
143## Cognitive Layer Endpoints (The 18 Tools)
144
145### Reality Layer (Raw Input)
146- **POST /reality/ingest:** Capture `source` (web/paper/book), `snippet` (auto-links to source), or `observation`. Accepts optional `props` to deep-merge.
147- **POST /reality/entity:** `create` (dedup-safe via `find_or_create_entity` — checks alias + case-insensitive match, returns `{node, created: bool}`; pass `entity_type` inside `props`), `alias`, `resolve`, `fuzzy_resolve`, `merge`, or `relate` (creates edge between `source_uid` and `target_uid` with `edge_type`).
148
149### Epistemic Layer (Reasoning)
150- **POST /epistemic/argument:** Atomic Toulmin bundle. Creates `Claim` + `Evidence` + `Warrant` + `Argument` nodes and wires edges.
151- **POST /epistemic/inquiry:** Record `hypothesis`, `anomaly`, `assumption`, `question`, or `open_question`.
152- **POST /epistemic/structure:** Crystallize `concept`, `pattern`, `mechanism`, `model`, `paradigm`, `analogy`, `theorem`, or `equation`.
153
154### Intent Layer (Commitments)
155- **POST /intent/commitment:** Declare `goal`, `project`, or `milestone`.
156- **POST /intent/deliberation:** Manage `open_decision`, `add_option`, `add_constraint`, or `resolve` (creates `DecidedOn` edge).
157
158### Action Layer (Workflows)
159- **POST /action/procedure:** Design `create_flow`, `add_step`, `add_affordance`, or `add_control`.
160- **POST /action/risk:** `assess` a node (severity/likelihood) or `get_assessments`.
161
162### Memory Layer (Persistence)
163- **POST /memory/session:** `open`, `trace` (real-time recording), `close` (sets `ended_at`), or `journal` (creates a `Journal` node, auto-linked to session).
164- **POST /memory/distill:** Synthesis of a session into a durable `Summary` node.
165- **POST /memory/config:** `set_preference`, `set_policy`, `get_preferences`, or `get_policies`.
166
167### Agent Layer (Control)
168- **POST /agent/plan:** `create_task`, `create_plan`, `add_step`, `update_status`, or `get_plan`. Note: `update_status` uses `targetUid` (not `taskUid`).
169- **POST /agent/governance:** `create_policy`, `set_budget`, `request_approval`, or `resolve_approval`.
170- **POST /agent/execution:** `start`, `complete`, `fail`, or `register_agent`.
171
172### Connective Tissue
173- **POST /retrieve:** Unified search: `text`, `semantic`, `hybrid` (RRF fusion, k=60), `active_goals`, `open_questions`, `weak_claims`, `pending_approvals`, `layer`, `recent`.
174- **POST /traverse:** Navigation: `chain`, `neighborhood`, `path`, `subgraph`.
175- **POST /evolve:** Mutation: `update`, `tombstone` (with cascade), `restore`, `decay`, `history`, `snapshot`.
176
177---
178
179## Client API (mindgraph-client.js)
180
181```javascript
182const mg = require('./mindgraph-client.js');
183
184// Reality
185await mg.ingest(label, content, 'observation', { confidence, props });
186await mg.manageEntity({ action: 'create', label, entityType: 'Person' });
187await mg.manageEntity({ action: 'relate', sourceUid, targetUid, edgeType: 'WorksAt' });
188await mg.findOrCreateEntity("Aaron Goh", "Person"); // Dedup-safe wrapper
189
190// Epistemic
191await mg.addArgument({ claim: { label, content }, evidence: [...], warrant: { label, explanation } });
192await mg.addInquiry(label, content, 'anomaly', { status: 'open' });
193await mg.addStructure(label, content, 'pattern', { summary: 'the lesson' });
194
195// Intent
196await mg.addCommitment(label, description, 'milestone', { parentUid, dueDate });
197await mg.deliberate({ action: 'open_decision', label, description });
198await mg.deliberate({ action: 'resolve', decisionUid, resolutionRationale });
199
200// Action
201await mg.procedure({ action: 'create_flow', label, description });
202await mg.risk({ action: 'assess', label, assessedUid, severity: 'high', likelihood: 'medium' });
203
204// Memory
205await mg.sessionOp({ action: 'open', label, focus });
206await mg.sessionOp({ action: 'trace', sessionUid, note: '...' });
207await mg.sessionOp({ action: 'journal', label, summary, props: { content, journal_type: 'investigation', tags: [] } });
208await mg.distill(label, content, { sessionUid });
209await mg.memoryConfig({ action: 'set_preference', label, value });
210
211// Agent
212await mg.plan({ action: 'create_task', label, description, status: 'pending' });
213await mg.plan({ action: 'update_status', targetUid: taskUid, status: 'completed' });
214await mg.governance({ action: 'create_policy', label, policyContent });
215
216// Search & Navigate
217await mg.search(query, { limit: 10 }); // FTS
218await mg.retrieve('semantic', { query, limit: 10 }); // Vector search
219await mg.hybridSearch(query, { limit: 10 }); // RRF fusion (best quality)
220await mg.traverse('neighborhood', uid, { maxDepth: 2 }); // Graph walk
221await mg.retrieve('active_goals'); // Structured queries
222
223// Mutate
224await mg.evolve('update', uid, { label, summary, propsPatch: { status: 'active' } });
225await mg.evolve('tombstone', uid, { reason: 'completed', cascade: true });
226
227// Low-level (backward compat)
228await mg.addNode(label, props, { summary, confidence });
229await mg.getNode(uid);
230await mg.updateNode(uid, updates, { reason });
231await mg.link(fromUid, toUid, 'SUPPORTS');
232await mg.getEdges(uid);
233await mg.edgesTo(uid, 'SUPPORTS');
234```
235
236---
237
238## Extraction Pipeline
239
240### Full pipeline (used by heartbeat and end-of-session writeback):
241```bash
242# 1. Flatten transcript to plain text
243python3 flatten_transcript.py <session.jsonl> --since-minutes 60 --output /tmp/conv.txt
244
245# 2. Extract structured nodes/edges via LLM
246node extract.js /tmp/conv.txt --output /tmp/extracted.json
247
248# 3. Import into graph via cognitive layer
249node import.js /tmp/extracted.json
250```
251
252### Extract model selection:
253- Files < 20KB → `gemini-3-flash-preview` (fast, cheap)
254- Files ≥ 20KB → `gemini-3-pro-preview` (larger output)
255- Files > 40KB → Auto-summarized via Flash first, then extracted
256
257### Entity resolution (during extraction):
258The pipeline resolves entities post-extraction via `entity-resolution.js`:
2591. Known aliases map → 2. `fuzzy_resolve` API → 3. FTS exact match → 4. Semantic similarity (0.85 threshold)
260
261---
262
263## Maintenance Scripts
264
265| Script | What it does | When to run |
266|---|---|---|
267| `dedup.js` | Merge nodes with identical labels (grouped by `node_type::label`) | After bulk imports |
268| `re-embed.js` | Regenerate graph-aware embeddings for all nodes | After schema changes, periodically |
269| `reindex-search.js` | Rebuild FTS index | After server upgrades |
270| `maintenance.js` | Batch watchdog + extraction trigger | Via heartbeat |
271
272---
273
274## Sub-agent Usage
275
276Sub-agents should NOT receive MEMORY.md. Instead:
277- Use `mg.retrieve` and `mg.traverse` for context
278- Use `mg.search` for quick lookups
279- Always pass `agentId` to track provenance
280
281---
282
283## Full Schema Reference
284
285See `SCHEMA.md` for complete node type definitions (53 types), edge type definitions, and key distinction rules.
286
287### Key Distinctions (most common errors):
2881. **Claim vs Observation:** "X happened on date Y" → Observation. "X is currently true" → Claim.
2892. **Claim vs Decision:** "BCG X is top priority" → Decision. "BCG X is a consulting firm" → Claim.
2903. **Claim vs Constraint:** "Never give salary preemptively" → Constraint (hard=true).
2914. **Claim vs Preference:** "Shan prefers concise replies" → Preference.
2925. **Claim vs Pattern:** "Axum 0.7 uses :param syntax" → Pattern (generalizable lesson).
293
294### FTS Searchability
295FTS indexes **all user-authored text** across 35+ string fields — not just label and summary. Use `mg.search()` or `mg.hybridSearch()`.
296
297### Entity Dedup
298Use `mg.findOrCreateEntity(label, entityType)` for all entity creation. Checks alias + case-insensitive match before creating.
299
300### Hybrid Retrieval
301`mg.hybridSearch(query, opts)` performs Reciprocal Rank Fusion of FTS + vector results. Use this instead of separate `search()` + `retrieve()` calls.