API Reference
REST endpoints and MCP tools reference
Authentication
All endpoints except /health require a bearer token:
Authorization: Bearer <your-auth-token>
The token is generated during npx @gamaze/hicortex init and stored in ~/.hicortex/config.json. To find it on a running server:
npx @gamaze/hicortex status
Localhost bypass: Requests from 127.0.0.1 / ::1 bypass auth. The token is only enforced for remote callers (clients on other machines).
REST Endpoints
POST /distill canonical capture
Submit a denoised session for server-side distillation. The server runs the LLM distillation pipeline, embeds the resulting memories, and stores them. Raw session content is discarded after processing.
This is the endpoint used by the nightly pipeline on both server-mode and client-mode machines. Client machines denoise locally (no LLM — strip tool noise, truncate bulk I/O) then POST here; raw session content never leaves the originating machine. Since 0.13.2 the nightly ships a session as one or more segments (the unseen delta since the last run), each with its own segment_id — see the dedup note below.
curl -X POST http://localhost:8787/distill \
-H "Authorization: Bearer <your-auth-token>" \
-H "Content-Type: application/json" \
-d '{
"text": "# Session transcript (denoised)\n\n...",
"session_id": "8036fb63",
"segment_id": "40-120",
"session_date": "2026-07-01",
"source_agent": "mymachine/claude",
"project": "myproject",
"privacy": "WORK"
}'
Request fields:
| Field | Type | Required | Description |
|---|---|---|---|
text | string | One of text or messages | Denoised session text (plain string) |
messages | array | One of text or messages | Denoised session as a message array ([{"role": "user", "content": "..."}]) |
session_id | string | No | Session identifier for deduplication (see below). |
segment_id | string | No | Identifies one slice of a session (0.13.2+). Enables segment-exact dedup so a failed segment can be retried with the same id without re-storing an already-ingested one. Omit for a whole-session POST (legacy ≤0.13.1 behavior). |
session_date | string | No | ISO date when the session happened (default: today). Used as created_at on stored memories. Per-night capture dates each segment from its own delta. |
source_agent | string | No | Machine/agent identifier (default: "unknown") |
project | string | No | Project name for filtering and domain routing |
privacy | string | No | One of: PUBLIC, WORK, PERSONAL, SENSITIVE (default: WORK) |
Body size limit: 25 MB.
Deduplication: When segment_id is present, the server skips only if that exact <session_id>#<segment_id> is already stored — so a retried segment is idempotent and a later segment of the same session is never blocked. When segment_id is absent (legacy whole-session POST), it skips if any memory for that session_id exists (unchanged pre-0.13.2 behavior).
Responses:
| Status | Meaning |
|---|---|
| 200 | Already distilled (dedup hit). Body: {"skipped": true, "existing_count": N} |
| 201 | Distilled and stored. Body: {"ids": [...], "distilled": N, "dropped": [...]}. dropped lists content-free fragments the distiller's substance gate rejected (0.13.1+) — an audit trail the nightly writes to its log. |
| 400 | Neither text nor messages supplied. |
| 503 | No LLM configured, or distillFallback: "strict" and remote distill endpoint unreachable. Client should retry on the next nightly run — the watermark is not advanced on 503. |
GET /health
Health check. No auth required.
curl http://localhost:8787/health
Response:
{
"status": "ok",
"version": "0.14.2",
"memories": 3026,
"links": 4272,
"db_size_kb": 10528,
"llm": "ollama/qwen3.5:14b"
}
When no LLM is configured (recall-only operation): "llm": "not configured".
GET /search
Semantic memory search. Used by MCP tools and the Hermes/OC plugins for recall.
curl "http://localhost:8787/search?query=authentication+architecture&limit=5&project=myproject" \
-H "Authorization: Bearer <your-auth-token>"
Query params: query (required), limit (default: the server's searchLimit config, 8), project (optional filter), privacy (optional filter).
POST /recall-index pushed recall (0.14)
The per-prompt recall index: send a session id and the user's prompt, get back a compact markdown block — one line per relevant memory — for injection into the agent's context (see Usage). The Claude Code recall-hook calls this on every prompt; the Hermes plugin (0.7.0) and the OpenClaw plugin (package 0.14.3) call the same endpoint per turn. The body also accepts optional scoping (0.14.3): "project": "<name>" and "privacy": "WORK,PERSONAL" (CSV or array) are pushed into retrieval — this is how a scoped plugin (e.g. a Hermes profile with a privacy_filter) keeps out-of-scope memories out of the injected index.
# per-prompt index
curl -X POST http://localhost:8787/recall-index \
-H "Authorization: Bearer <your-auth-token>" \
-H "Content-Type: application/json" \
-d '{"session_id": "8036fb63", "prompt": "how did we set up auth for the billing service?"}'
# session start / compaction: clear the session's dedup state
curl -X POST http://localhost:8787/recall-index \
-H "Authorization: Bearer <your-auth-token>" \
-H "Content-Type: application/json" \
-d '{"session_id": "8036fb63", "reset": true}'
Response (index form): { "block": "<markdown>" | null, "shown": [ids], "turn": N } — block is the ready-to-inject ## Memory recall (auto) index. When nothing passes the relevance gates (or every candidate was recently shown — memories are suppressed for recallReshowTurns turns), block is null with shown: []. A prompt shorter than recallMinPromptChars is skipped entirely: { "block": null, "skipped": "short-prompt" }, with no shown/turn. Reset form: { "ok": true, "reset": true }. Missing session_id → 400.
Exposure, not use: appearing in the index marks a memory as shown (its decay clock refreshes) but never as used — durable strengthening happens only on fetch via GET /memory / hicortex_get.
GET /memory lazy-load (0.14)
Fetch one memory's full content by id — the lazy-load counterpart of /recall-index. Fetching marks the memory as used (strengthens it), so clients should fetch only what the agent actually needs. Both the full id and a unique short prefix (e.g. the 8-character id used in citations) are accepted (0.14.3). An optional privacy query parameter (CSV) scopes the fetch: an out-of-scope memory answers the same 404 as an unknown id, and is not strengthened.
curl "http://localhost:8787/memory?id=8470ef8f-3c21-4d9a-b1e7-5f0c2a6d4e11" \
-H "Authorization: Bearer <your-auth-token>"
Response: { "memory": { ... }, "citation": "(memory 8470ef8f, 2026-07-01, from mymachine/claude)" } — citation is a server-rendered provenance string (short id, date, origin agent), so REST clients (the Hermes and OpenClaw plugins) inherit the same citing norm with no client-side work (0.14.1): agents are instructed to cite memories that shape their answers. Missing id → 400; unknown id → 404.
GET /recent renamed in 0.12
Queryless recall of the latest memories by project, ranked by importance (strength + connections + recency). No embedding needed — fast. Renamed from GET /context in 0.12 (the /context path now serves the standing context layer, below).
curl "http://localhost:8787/recent?project=myproject&limit=10" \
-H "Authorization: Bearer <your-auth-token>"
Query params: project (optional filter), limit (default: the server's recentLimit config, 12), privacy (optional filter).
GET /context PUT /context context layer (0.12); per-agent (0.13)
The standing context layer — hand-edited Markdown ("who you are + how to work") stored as files at <hicortex-home>/context/*.md (one file per section). It lives outside episodic memory: never distilled, scored, or decayed. Injected verbatim at session start into the harnesses listed in contextClients (see Configuration).
# read all sections
curl "http://localhost:8787/context" \
-H "Authorization: Bearer <your-auth-token>"
# write a section (partial upsert — omitted sections are left untouched)
curl -X PUT "http://localhost:8787/context" \
-H "Authorization: Bearer <your-auth-token>" \
-H "Content-Type: application/json" \
-d '{"sections": {"rules": "## How to work\n..."}}'
Since 0.14.4 the response also carries a synthetic read-only memory section — the product-owned memory instructions (how agents should use recall, citing, and capture), rendered from server code and versioned with the server. It overrides any file of the same name, PUT rejects the name memory as reserved, and memoryInstructions: false in server config disables it.
GET returns { sections: { "<name>": "<md>" }, updated_at, clients, agents } — clients is the resolved contextClients list so each harness self-gates; agents maps known agent ids to their resolved mode. PUT body is { sections: { "<name>": "<md>" } }; section names must match ^[a-z0-9][a-z0-9_-]*$ (max 64 chars), any invalid name → 400 and nothing is written. Deletion is filesystem-only. Recall-style query params (project, limit, privacy) on GET /context return 400 pointing at /recent (catches stale pre-0.12 recall callers).
Per-agent scope (0.13): ?agent=<id> on both verbs selects an agent's scope. The server resolves the mode (contextAgents config → agents/<id>/ dir presence → global) and GET returns the merged result — { sections, updated_at, clients, agent, mode }, plus origins (per section: "global" or "agent") in override mode. The agent echo is present in every mode; clients that sent an id can gate on it to detect pre-0.13 servers, which ignore the param (the Hermes/OC adapters and the CLI do; the CC hook intentionally does not). PUT ?agent= writes to context/agents/<id>/; if config forces that agent to off/global the write is refused with 409 (the sections could never be served). The agent id is on the same allowlist as section names; an invalid id → 400, never a silent fall-through to global.
GET /context/ui context layer (0.12)
Self-contained web editor for the context layer — one tab per section, Save writes via PUT /context. Same shell-served-without-auth pattern as /viz (all data goes through the bearer-only /context endpoint). From localhost no token is needed; from a remote browser paste the token into the in-page prompt or open /context/ui?token=<your-auth-token>.
open "http://localhost:8787/context/ui"
GET /lessons
Returns the lessons block and memory index. Used by the CC SessionStart hook to inject lessons into context at session start.
curl "http://localhost:8787/lessons" \
-H "Authorization: Bearer <your-auth-token>"
GET /index
The knowledge domain index — which domains exist and how many memories and lessons each holds. Useful for an agent to orient before searching.
curl "http://localhost:8787/index" \
-H "Authorization: Bearer <your-auth-token>"
GET /graph
Knowledge-graph queries. The op parameter selects the operation:
| Op | Params | Returns |
|---|---|---|
neighbors | id (required), limit, relationship | Memories linked to the given memory |
hubs | limit, domain | The most highly connected memories |
path | id, target_id | Shortest link path between two memories |
export | domain, type, tag, minStrength, limit | Full graph slice for visualization: {nodes, edges, domains, types, meta} |
curl "http://localhost:8787/graph?op=export&domain=Work&limit=1000" \
-H "Authorization: Bearer <your-auth-token>"
For export: nodes are ranked by effective (decayed) strength and capped by limit (default 5000, max 10000); edges are included only when both endpoints made the cut. Each node carries its domain tags ordered by association weight. domain= filters by a memory's primary domain; tag= matches any tag at any weight — "everything touching X".
GET /viz
The interactive knowledge-graph page (3D with a 2D toggle) — feeds on /graph?op=export. Fully self-contained: all rendering libraries are served by your own daemon from GET /viz/vendor/<file> (strict allowlist), zero external requests.
open "http://localhost:8787/viz"
The page shell itself contains no data, so it is served without auth (like /health); all memory content comes from the bearer-only /graph endpoint. From localhost no token is needed. From a remote browser, paste the auth token into the in-page prompt once (stored in localStorage), or open /viz?token=<your-auth-token> — the page strips the token from the URL on load.
POST /ingest legacy
Ingest a single pre-distilled memory. Retained for backward compatibility with older client-mode installs. New integrations should use /distill instead.
curl -X POST http://localhost:8787/ingest \
-H "Authorization: Bearer <your-auth-token>" \
-H "Content-Type: application/json" \
-d '{
"content": "# Session Memory: 2026-03-27 - myproject\n\n## Decisions Made\n- Adopted event-driven architecture",
"source_agent": "mymachine/claude",
"project": "myproject",
"memory_type": "episode",
"privacy": "WORK",
"source_session": "8036fb63",
"session_date": "2026-03-27"
}'
Request fields:
| Field | Type | Required | Description |
|---|---|---|---|
content | string | Yes | Memory content (distilled markdown) |
source_agent | string | No | Machine/agent identifier |
project | string | No | Project name for filtering |
memory_type | string | No | One of: episode, lesson, fact, decision (default: episode) |
privacy | string | No | One of: PUBLIC, WORK, PERSONAL, SENSITIVE (default: WORK) |
source_session | string | No | Session ID for deduplication |
session_date | string | No | ISO date when the session happened (default: now) |
Response (201):
{ "id": "8470ef8f-64ab-4e28-bfc8-1624b195b2be", "message": "Memory ingested" }
Deduplication: If source_session is provided and memories already exist for that session:
{ "id": null, "skipped": true, "existing_count": 3 }
MCP Transport
MCP tools are exposed via SSE transport at GET /sse + POST /messages. Your agent uses them automatically through the registered MCP connection — you do not call these endpoints directly.
MCP Tools Reference
9 tools available via MCP (and in the plugins: Hermes 0.7.0, OpenClaw since package 0.14.3). Used automatically by the agent; you can also invoke them explicitly.
hicortex_search
Semantic search across all memories. Uses BM25 + 384-dim vector embeddings with RRF fusion and knowledge graph traversal.
- query
string(required) — Natural language search query- limit
number(optional, default: server configsearchLimit, 8) — Max results to return- project
string(optional) — Filter by project name
Returns: Memories with content, composite score, effective strength, memory type, project, and connection count.
hicortex_get
Fetch one memory's full content by id (0.14) — the lazy-load counterpart of the per-prompt recall index. Fetching marks the memory as used (durable strengthening), so agents fetch only what they actually need.
- id
string(required) — Memory ID as shown in the recall index
Returns: The memory's full content behind a provenance header (id, type, project, origin agent, date) plus the citation format the agent uses when the memory shapes its answer (0.14.1).
hicortex_recent
Queryless recall of the latest memories by project, ranked by importance. Useful to catch up on what happened recently. No embedding needed — fast. (Renamed in 0.12 — see the changelog.)
- project
string(optional) — Filter by project name- limit
number(optional, default: server configrecentLimit, 12) — Max memories to return
Returns: Recent memories with scores and connections.
hicortex_ingest
Store a new memory. Use for important facts, decisions, or lessons the agent wants to remember explicitly.
- content
string(required) — The memory content to store- project
string(optional) — Project this memory belongs to- memory_type
string(optional) — One of: episode, lesson, fact, decision (default: episode)
Returns: Memory ID confirmation.
hicortex_lessons
Retrieve lessons learned from past sessions. Auto-generated during nightly consolidation from both successes and failures.
- days
number(optional, default: 7) — Look back N days- project
string(optional) — Filter by project name
Returns: Array of lesson memories with content and metadata.
hicortex_index
Get the knowledge domain index — shows what topics and projects are stored in memory, grouped by domain. Useful before searching to understand what knowledge is available.
Returns: Domain listing with memory/lesson counts, project groupings, and keywords.
hicortex_graph
Query the memory knowledge graph — find connected memories, hub nodes, or paths between memories.
- operation
"neighbors" | "hubs" | "path"(required) — Graph operation to perform- id
string(optional) — Memory ID (required for neighbors and path)- target_id
string(optional) — Target memory ID (required for path)- limit
number(optional, default: 10) — Max results- domain
string(optional) — Filter hubs by domain
Returns: Connected memories with relationships, hub nodes with link counts, or shortest path between memories.
hicortex_update
Update an existing memory. If content changes, the embedding is re-computed. Returns before/after diff.
- id
string(required) — Memory ID (first 8 chars or full UUID from search results)- content
string(optional) — New content text- project
string(optional) — New project name- memory_type
string(optional) — New type: episode, lesson, fact, decision
Returns: Confirmation with changed fields (before → after).
hicortex_delete
Permanently delete a memory, its vector embedding, and all associated links. Returns the deleted content for audit.
- id
string(required) — Memory ID (first 8 chars or full UUID)
Returns: Confirmation with preview of deleted content.
Server Configuration
Default port is 8787. Override via CLI:
npx @gamaze/hicortex server --port 9000 --host 0.0.0.0
Or set in ~/.hicortex/config.json. See Configuration for all options.