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:

FieldTypeRequiredDescription
textstringOne of text or messagesDenoised session text (plain string)
messagesarrayOne of text or messagesDenoised session as a message array ([{"role": "user", "content": "..."}])
session_idstringNoSession identifier for deduplication (see below).
segment_idstringNoIdentifies 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_datestringNoISO 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_agentstringNoMachine/agent identifier (default: "unknown")
projectstringNoProject name for filtering and domain routing
privacystringNoOne 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:

StatusMeaning
200Already distilled (dedup hit). Body: {"skipped": true, "existing_count": N}
201Distilled 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.
400Neither text nor messages supplied.
503No 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_id400.

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 id400; 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:

OpParamsReturns
neighborsid (required), limit, relationshipMemories linked to the given memory
hubslimit, domainThe most highly connected memories
pathid, target_idShortest link path between two memories
exportdomain, type, tag, minStrength, limitFull 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:

FieldTypeRequiredDescription
contentstringYesMemory content (distilled markdown)
source_agentstringNoMachine/agent identifier
projectstringNoProject name for filtering
memory_typestringNoOne of: episode, lesson, fact, decision (default: episode)
privacystringNoOne of: PUBLIC, WORK, PERSONAL, SENSITIVE (default: WORK)
source_sessionstringNoSession ID for deduplication
session_datestringNoISO 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 config searchLimit, 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 config recentLimit, 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.