Evolver for Cursor, powered by Evolver (@evomap/evolver) and
EvoMap: before each prompt it recalls one proven strategy, grades how the turn reused it on
evidence (the checks the turn ran, whether its edits were kept, your next reply), reports that back to the EvoMap
network, and distills the chat's verified work into a new Gene when the chat closes.
The plugin runs entirely from Cursor hooks. It ships no MCP server, no skill and no rule, so nothing of
Evolver enters the model's context but the recalled steps, which end with Apply them where they fit. — no
instruction to search, report or distill. Reports and distillation run on hook events; the /evolver-* commands
are answered by the plugin itself, before any model sees them.
| Cursor hook | What the plugin does |
|---|---|
sessionStart (a new chat) |
Reports the previous chat's kept or reverted edits (retention) and the open strategies of a chat whose Cursor process is gone (aborted), starts Evolver if it is missing or too old, and distills leftover candidates — all in a detached background worker. Adds no context, except a one-off notice when it installed, upgraded or could not start Evolver. |
beforeSubmitPrompt |
Answers a typed /evolver-* command itself (see Commands). Otherwise recalls by the prompt text (POST /asset/fetch {text} on the local Proxy) and adds the best strategy as additional_context, which Cursor sends with that same request; labels the previous turn's reuse from this prompt (correction or praise) and drops its candidate on a correction. Inline edits (Cmd-K), which carry no composer_mode and drop added context, are left alone. |
preToolUse (Write, Delete) |
Hashes the file an edit is about to change, for the retention report. |
postToolUse, postToolUseFailure |
Notes the turn's commands, checks (test, build, lint, type check) with pass or fail, and touched paths. |
afterFileEdit |
Notes the text each edit wrote in. |
afterAgentResponse |
Notes the turn's final answer. |
stop |
Counts what a reused strategy saved the turn (see Tokens saved) and reports every strategy injected into the turn, with the turn's end as Cursor gives it (completed, aborted, error); makes the turn the chat's distillation candidate when it completed verified. Cursor sends the next prompt without waiting for this hook, so that prompt waits up to 3 s for the turn to settle before it labels the reuses or drops the candidate; a turn whose stop never comes is closed then as an error. |
sessionEnd (chat or window closed) |
Reports a turn still running as aborted, and anything left unreported too; closes the candidate and starts its distillation in the background. Keeps the chat's turn counter, so a reopened chat never repeats a task id. |
Each hook does nothing when it runs inside the plugin's own headless distillation (EVOLVER_HEADLESS=1), which
loads this plugin too.
Search for Evolver in the Cursor plugin marketplace and install, then reload Cursor. Local memory works with zero config — no account, no key, no node id.
git clone https://github.com/EvoMap/evolver-cursor-plugin
ln -s "$(pwd)/evolver-cursor-plugin" ~/.cursor/plugins/local/evolverReload the window; Settings → Hooks lists the plugin's hooks.
- Cursor with hooks (3.x).
beforeSubmitPrompt'sadditional_context, which carries the recalled strategy, is read by Cursor 3.27 but not yet in Cursor's hook docs. - Cursor's Include Third-Party Plugins, Skills, and Other Configs setting on (the default). Cursor 3.27 loads a
plugin's hooks only while it is on (
loadPluginHooksreturns early otherwise), so with it off the plugin is listed but none of its hooks runs. The same setting also imports Claude Code hooks from~/.claude/settings.json; if those include Evolver's own (evolver inject prompt-recall), a prompt is recalled for twice. - Node.js 20 or newer on the
PATHCursor's hooks see. - Evolver 2.0.44 or newer. The plugin installs it under
~/.evolver/state/cursor-engineand starts its Proxy in the background when it is missing;npm install -g @evomap/evolver@latestworks too. - For session-end distillation: the Cursor agent CLI (
cursor-agent, installed bycurl https://cursor.com/install -fsS | bash), signed in withcursor-agent loginorCURSOR_API_KEY. Without it the candidate stays on disk and nothing else changes.
The plugin reads the live Proxy URL and token from ~/.evolver/settings.json (written by the Proxy), else
http://127.0.0.1:19820 (EVOMAP_PROXY_PORT changes the port).
- Leave any node id blank. The first run registers a fresh node for you and prints a claim link.
- Open that link while signed in to evomap.ai.
/evolver-statusshows a pending link.
Cursor commands are prompts for the model, so the plugin answers its commands itself: when a prompt starts with
one, the beforeSubmitPrompt hook runs it and stops the prompt with the answer (continue: false,
user_message), and no model sees either. The command files in commands/ exist for the slash menu.
| Command | What it does |
|---|---|
/evolver-status |
Leads with the tokens reused strategies saved in this chat and in all chats, then the Proxy, engine setup, the latest recall, recent reuse reports with the Hub's verdict, waiting candidates, claim link. |
/evolver-search <text> |
Searches the EvoMap network (POST /asset/search). |
/evolver-distill [focus] |
Distills this chat's latest verified turn now, through the Cursor agent CLI. |
/evolver-evolve [focus] |
An evolution checkpoint for the agent, dsh's text as is (Cursor appends the focus): the only command that is a prompt. It is recalled for like any prompt, and is no verdict on the turn before it, whose reuses wait for the next prompt. |
/evolver-sync, /evolver-review, /evolver-run, /evolver-solidify |
Run the evolver CLI (npx -y @evomap/evolver@^2.0.44 when it is not installed) with the arguments quoted as a shell would, ten minutes at most. |
Cursor shows a command's answer in the chat as a message the hook blocked the prompt with.
/evolver-status opens with what reusing EvoMap strategies saved:
SAVED by reusing EvoMap strategies — this chat: ~33k tokens (≈$0.30) over 1 reused turn · all chats: ~124k tokens (≈$1.12) over 4 reused turns
turn 3 · "Guide Xiaohongshu operations from account positioning…" (sha256:3fccd18…) · last check passed · ~33k saved
Below it, one line for each strategy this chat reused (the latest 20): the turn, the asset's name and id, how the
turn's last check went, and what was saved, or no saving counted.
A turn counts only when it reused an injected strategy and its last check passed. Its saving is the reference-reuse
estimate of @evomap/evolver-core's savingsCore (spec 0.3.0), the one the Claude Code and Codex plugins show, from
the lines the turn's edits changed (afterFileEdit), capped at the tokens the turn spent itself: stop's
input_tokens + output_tokens + cache_write_tokens, without cache reads. Dollars use the same blended $9 per
million tokens. Cursor's hooks have no message that reaches only the person (stop can only send the model a
follow-up), so the figures are shown on demand rather than after each turn. They are kept in
~/.evolver/state/cursor-savings.json: a running total, and per chat (with its reuses) for chats seen in the last 3 days.
A turn that ended completed, used tools and passed its last check leaves a candidate in ~/.evolver/state/cursor-distill-pending.json; a later verified turn replaces it, and a next prompt
that reads as a correction drops it (a distillation already running sees that and stops). When the chat closes,
a detached worker runs the Cursor agent CLI headless on the chat's model —
cursor-agent -p --output-format json --mode ask --trust --workspace <empty scratch dir> --model <model> <prompt>,
read-only, without --force so nothing is applied — to write a Gene from a digest of that turn (task, commands,
touched paths, checks, final answer — never the whole history), and sends it to the Proxy's
POST /conversation/distill with platform: 'cursor', trigger: 'session_end', persist: true and
publish: false. The CLI reports no token usage, so no distill_usage is sent. Keys and tokens are stripped from
the candidate first, paths and a manual focus included. A turn that reused an injected strategy is a candidate
too: the engine's Gene intake drops a Gene that repeats one it already has.
A candidate stays on disk until it is distilled; three failed tries (no cursor-agent, not signed in, an
unparsed answer, a Proxy error) give it up. One whose chat is over — closed, or left by a Cursor process that is
gone — is claimed by the next session start, one process at a time, while an idle chat keeps its own.
Owner. Cursor starts hooks from its extension host (the editor) or its own process (the CLI), sometimes through
a shell. The owner recorded with a candidate or an injection is the nearest ancestor process whose executable path
(from ps, or /proc/<pid>/exe on Linux) names Cursor; it goes away with the window or CLI that runs the chat (a
window reload counts). Where no process table can be read (Windows) no owner is recorded, and such entries are only
reported or distilled once their chat closes.
Windows. Only a cursor-agent.exe (or an agent.exe inside the CLI's install) is run, without a shell: a
.cmd shim would need cmd.exe, whose 8191-character command line the prompt argument overruns. With neither, the
candidate is kept and given up after three tries.
Every strategy injected into a turn is reported through the Proxy's POST /asset/reuse-result as
{asset_id, outcome, task_id, reason, evidence}:
| Report | When | task_id |
evidence |
|---|---|---|---|
| Turn end | stop, or the next prompt after a turn whose stop never came |
cursor:<conversation>:<turn> |
tier L1 when the turn ran a test, build, lint or type check, else none; applied: used; check {kind, passed, fail_then_pass} of the last check; aborted; stage: immediate |
| Correction | the next prompt says the answer did not hold, or approves it | …:correction |
tier: L3, applied: used, stage: correction |
| Retention | the next chat in the same project finds the turn's edits kept or reverted | …:retention |
tier: L2, applied: used, stage: retention |
| Aborted | the chat closes, or its Cursor process goes away, before the turn ends (those of a process that is gone go out at the next session start) | cursor:<conversation>:<turn> |
tier: none, applied: used, aborted: true, stage: immediate |
appliedis alwaysused: the model follows a strategy injected into its turn. Whether it helped is judged by the outcome (the last check, or how the turn ended), the next prompt and whether the edits were kept.- Checks are
Shellcommands that run tests, builds, linters or type checkers. A non-zero exit code (postToolUse'sexitCode, or apostToolUseFailurefor an error or a timeout) fails one; with exit code 0 the output is read too, since a failing suite piped throughtailexits zero. A command the person interrupted has no verdict, and one that was denied never ran. A command moved to the background before it finished has no verdict either where Cursor fails it withUnknown error; its streaming Shell executor instead reports such a command as exit code 0 with the output so far and nothing to tell it apart, so there the output alone decides. - Delivery. Reports wait in
~/.evolver/state/cursor-reports-outbox.jsonand are retried by the background worker at every turn end, follow-up prompt and session start for 3 days. One the Hub refuses as invalid is settled as rejected and never resent. Reports with evidence are also written once to the local root event log. - Reasons name the turn and the check kind, never the prompt, a command or code, and the prompt loses keys and tokens before recall sends it.
Every state file is prefixed cursor-, so another host's Evolver plugin never claims or reports this one's.
npm testRemove the plugin from Cursor's plugin settings. Local Evolver memory under ~/.evolver/ is left intact.
MIT © EvoMap. Installing @evomap/evolver (GPL) is a separate step the plugin performs as a package install; its
code is not part of this repository. See LICENSE.
