Skip to main content
Haki ships two complementary Cursor integration mechanisms, both installable together: the MCP server (the agent chooses to call tools) and Cursor Hooks (Cursor invokes commands automatically, with no cooperation from the model required). Both are packaged by the 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.
No tool accepts a subject_id parameter. Scope (both project_id and subject_id) comes entirely from server configuration (HAKI_MCP_PROJECT_ID, HAKI_MCP_SUBJECT_ID), never from the model — this is the “the client must not let the model choose these values” security invariant. A team sharing one Cursor deployment needs one server configuration per person, exactly the same way every install already gets its own project.

Configuration

Honest limit, measured not promised

MCP does not intercept 100% of Cursor conversations: the server only sees the tool calls Cursor decides to make. The Project Rule instructs the agent on the when — actual coverage is measured, never promised (see research/Haki_Memory_Runtime.md).
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.
Prints three blocks to paste (pure generation, never an automatic write — same principle as 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:
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

Scope (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.
.cursor/hooks.json and .cursor/rules/haki-session.mdc are code that runs automatically — review them before committing, the same way you would review a CI config. Writing them automatically (from an agent, or on repo open) is exactly the pattern behind a real Cursor sandbox-escape CVE (“a workspace file writes a hook config that then runs unapproved”). The hooks_setup.py module only generates and prints — you paste it in yourself.

Fail-open contract

A Cursor hook must never crash the agent loop. On any error (missing config, unreachable API, invalid stdin JSON, empty text, .mdc write failure…), haki hook-capture and haki hook-session-start print a harmless empty JSON ({}) and exit with code 0 — never a Python traceback, never a non-zero code. The failure reason is logged to stderr only, never mixed into the stdout JSON that Cursor parses.

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.