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 capture 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. The capture watchdog 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",
"source_agent_id": "a1b2c3d4-1234-5678-9abc-def012345678",
"source_domain": "Work",
"project": "myproject"
}'
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") |
source_agent_id | string | No | Stable UUID of the capturing agent (from its config agentId). Attribution/provenance only — not used for filtering. (0.16.2+) |
source_domain | string | No | The capturing agent's declared topic (from its config sourceDomain). Provenance only — not used for filtering. (0.16.2+) |
project | string | No | Project name for filtering and domain routing |
privacy | string | No | Deprecated. Historically PUBLIC/WORK/PERSONAL/SENSITIVE; the distiller no longer classifies privacy and nothing filters on it — for isolation, run a separate server. Still accepted for backward compatibility. |
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 the distill endpoint is unreachable. The server is in strict mode by default — it does not fall back to a lower-quality path. The client retries on the next capture; the session watermark is not advanced on 503, so nothing is lost. |
GET /health
Health check. No auth required.
curl http://localhost:8787/health
Response:
{
"status": "ok",
"version": "0.17.1",
"memories": 3026,
"links": 4272,
"db_size_kb": 10528,
"llm": "ollama/qwen3.5:14b"
}
The version reflects the current release. 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).
POST /recall-index pushed recall
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 and OpenClaw plugins call the same endpoint per turn. The body also accepts optional project scoping: "project": "<name>" is pushed into retrieval. (A privacy field is still accepted but ignored — privacy is no longer filtered; use a separate server for isolation.)
# 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
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.
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: agents are instructed to cite memories that shape their answers. Missing id → 400; unknown id → 404. The memory object also includes source_agent_id and source_domain when the capturing client set them.
GET /recent
Queryless recall of the latest memories by project, ranked by importance (strength + connections + recency). No embedding needed — fast. The /recent path serves this; the older GET /context path was repurposed in 0.12 to the standing identity layer (now /identity — see below; /context remains as a backcompat alias).
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).
GET /identity PUT /identity identity layer; per-agent
The standing identity layer — hand-edited Markdown ("who you are + how to work") stored as files at <hicortex-home>/identity/*.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 identityClients (see Configuration). (/context remains as a backcompat alias for this endpoint.)
# read all sections
curl "http://localhost:8787/identity" \
-H "Authorization: Bearer <your-auth-token>"
# write a section (partial upsert — omitted sections are left untouched)
curl -X PUT "http://localhost:8787/identity" \
-H "Authorization: Bearer <your-auth-token>" \
-H "Content-Type: application/json" \
-d '{"sections": {"rules": "## How to work\n..."}}'
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 identityClients 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 /identity return 400 pointing at /recent (catches stale callers expecting the old recall behavior).
Per-agent scope: ?agent=<id> on both verbs selects an agent's scope. The server resolves the mode (identityAgents 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. PUT ?agent= writes to identity/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 /identity/ui identity layer
Self-contained web editor for the identity layer — one tab per section, Save writes via PUT /identity. Same shell-served-without-auth pattern as /viz (all data goes through the bearer-only /identity endpoint). From localhost no token is needed; from a remote browser paste the token into the in-page prompt or open /identity/ui?token=<your-auth-token>.
open "http://localhost:8787/identity/ui"
GET /learnings /lessons alias
Returns the Learnings block and memory index. Used by the CC SessionStart hook to inject Learnings into context at session start. /lessons is a backcompat alias for the same handler (existing hooks keep working unchanged).
curl "http://localhost:8787/learnings" \
-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.
GET /dashboard analytics
A view-only analytics page (alongside /viz) showing the health of your agents’ shared memory: growth over time, domain composition, recall adoption, and a nightly digest. The headline metric is uses-per-showing — whether the memories Hicortex surfaces are the ones agents actually reach for. Strictly read-only: no approval queues, no edits, no data leaves the server. Like /viz, the page shell is served without auth and all data flows through the auth-gated /dashboard/data endpoint below.
open "http://localhost:8787/dashboard"
GET /dashboard/data auth required
The JSON backing the analytics dashboard — the current memory/Learnings/link counts, growth series, domain composition, and recall-adoption aggregates. Requires the bearer token from non-localhost callers; localhost bypasses auth.
curl "http://localhost:8787/dashboard/data" \
-H "Authorization: Bearer <your-auth-token>"
GET /account auth required
Account identity for the console navigation: { "account": { "name", "org", "plan" } }, read from the optional displayName / orgName / planLabel config keys (absent keys are null; typically only a display name is set — see Configuration). The lightweight twin of the account block inside /dashboard/data, so pages that need only the nav element skip the metric payload. Requires the bearer token from non-localhost callers; localhost bypasses auth.
curl "http://localhost:8787/account" \
-H "Authorization: Bearer <your-auth-token>"
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": "experience",
"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: knowledge, experience, decisions, learnings (default: experience). Legacy values episode, lesson, fact, decision also accepted. |
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
10 canonical tools available via MCP (plus hicortex_lessons as a backcompat alias of hicortex_learnings). 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 — 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.
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 Knowledge, Decisions, or Learnings 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: knowledge, experience, decisions, learnings (default: experience). Legacy values episode, lesson, fact, decision also accepted.
Returns: Memory ID confirmation.
hicortex_learnings hicortex_lessons alias
Retrieve actionable Learnings from past sessions. Auto-generated during nightly consolidation from both successes and failures. (hicortex_lessons is kept as a backcompat alias for the same handler.)
- days
number(optional, default: 7) — Look back N days- project
string(optional) — Filter by project name
Returns: Array of Learnings (Learnings-type memories) with content and metadata.
hicortex_identity
Fetch your standing identity — the hand-edited “who you are + how you work” layer (personality, rules, preferences). Use this to re-read your identity after context compaction or to look up a specific rule. Returns the same sections the SessionStart hook injects.
- name
string(optional) — Fetch a specific identity section by name (e.g.rules). Omit for all sections.
Returns: Identity sections rendered as Markdown (### <Name> per section), or No identity sections configured. when none exist.
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/Learnings 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: knowledge, experience, decisions, learnings. Legacy: 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.