haki
CLI — pure generation, nothing is ever written to disk on your behalf.
MCP server — 4 tools, never more
Mounted inside the FastAPI app itself on/mcp (Streamable HTTP
transport) — a single server to run.
1
Click the deeplink
Add Haki to Cursor — installs the MCP server in one click.2
Paste the Project Rule
Into
.cursor/rules/haki.mdc — tells the agent when to
memorize and when to recall.3
That's it
Cursor retains your decisions, conventions and resolved errors
across sessions.
The four tools
query, budget_tokens=900
Recalls the project memory relevant to a task. Call it before
planning or editing code. Returns a ready-to-inject block (
context),
the raw facts, warnings, token_count and trace_id.content, kind='agent.observation'
Memorizes a durable fact: a technical decision, a convention, a
resolved error. Call it at the end of a task. Idempotent by content
(
sha256(kind + content), no timestamp) — calling it twice with the
same memory never creates a duplicate. Consolidation is synchronous
in dev (HAKI_MCP_AUTOCONSOLIDATE=true, default), so the fact is
immediately recallable.trace_id
Why a memory was used: which facts were included, excluded or blocked,
and each one’s
reason_code.mode='disable'
Forgets all memory of the subject configured for this server, in
this project.
mode="disable" (reversible) or mode="delete" (real
erasure). Returns the receipt (forget_id) and the counters.Configuration
Honest limit, measured not promised
This is exactly the gap that Cursor Hooks, below, close for capture: they depend on no cooperation from the model at all.Cursor Hooks — guaranteed capture and session recall
Added and tested against a real, running local server
(
prj_demo/org_demo): haki hooks writes nothing to disk;
hook-session-start correctly writes haki-session.mdc with the real
memorized content (a fact + an episode recalled via /v1/context), and
the “nothing memorized yet” fallback for a blank subject;
hook-capture creates an agent.observation event retrievable via
/v1/timeline, deduplicated when replayed with the same
conversation_id/generation_id; the fail-open contract was verified
across 6 scenarios (unreachable API, no config, invalid stdin JSON,
empty stdin, empty text, .mdc write failure) — always
stdout "{}" and exit code 0.haki mcp): the .cursor/hooks.json, the initial
.cursor/rules/haki-session.mdc template, and the install instructions.
Why this mechanism exists alongside MCP
Cursor Hooks are local processes that Cursor itself spawns (JSON in/out over stdio, not an HTTP server), configured in.cursor/hooks.json. Two hooks are packaged:
- afterAgentResponse — guaranteed capture
- sessionStart — session recall
Purely observational on Cursor’s side (no known bugs at the time of
writing) — the most reliable of the three hooks Cursor exposes.
Captures every agent response with no cooperation from the model
required, unlike
haki_capture (MCP), which the model can simply
choose not to call. Idempotent by
conversation_id + generation_id.beforeSubmitPrompt (the third existing Cursor hook) can only allow or
deny a submission — its documented output schema has no
content-injection field, unlike sessionStart. It is therefore not
used for memory recall.Generated .cursor/hooks.json
subject_id/project_id/org_id) is baked into the command at
generation time, never inferred at runtime — the same invariant as for
MCP. The generated command never carries the API key: it is resolved
by the already-installed haki CLI, from ~/.haki/config.json.
Fail-open contract
Installation
1
Paste the JSON
Into
.cursor/hooks.json at the project root.2
Create the rule file
.cursor/rules/haki-session.mdc with the printed template — once
only: the sessionStart hook rewrites it on every subsequent
session.3
Verify the CLI install
haki status — the hooks invoke haki directly, they carry no
hardcoded API key.4
Open a new Cursor session
hook-session-start updates the .mdc file; hook-capture
memorizes every agent response automatically, with no action on your
part.Roadmap
OAuth for Cursor (replacing the dev bearer
HAKI_API_KEY) is still on
the roadmap — see the status table in the root README.
