Skip to content

About

Official Evolver plugin for Cursor — self-evolving agent memory: recall what worked, detect improvement signals, record outcomes (session hooks + skill). MIT.

Topics

Resources

Stars

5 stars

Watchers

0 watching

Forks

Repository files navigation

Evolver

Evolver — Cursor plugin

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.

What runs when

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.

Install

From the Cursor Marketplace

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.

Local development

git clone https://github.com/EvoMap/evolver-cursor-plugin
ln -s "$(pwd)/evolver-cursor-plugin" ~/.cursor/plugins/local/evolver

Reload the window; Settings → Hooks lists the plugin's hooks.

Prerequisites

  • Cursor with hooks (3.x). beforeSubmitPrompt's additional_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 (loadPluginHooks returns 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 PATH Cursor's hooks see.
  • Evolver 2.0.44 or newer. The plugin installs it under ~/.evolver/state/cursor-engine and starts its Proxy in the background when it is missing; npm install -g @evomap/evolver@latest works too.
  • For session-end distillation: the Cursor agent CLI (cursor-agent, installed by curl https://cursor.com/install -fsS | bash), signed in with cursor-agent login or CURSOR_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).

Connecting to the EvoMap network (optional)

  1. Leave any node id blank. The first run registers a fresh node for you and prints a claim link.
  2. Open that link while signed in to evomap.ai. /evolver-status shows a pending link.

Commands

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.

Tokens saved

/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.

Session-end distillation

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.

Reuse reports

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
  • applied is always used: 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 Shell commands that run tests, builds, linters or type checkers. A non-zero exit code (postToolUse's exitCode, or a postToolUseFailure for an error or a timeout) fails one; with exit code 0 the output is read too, since a failing suite piped through tail exits 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 with Unknown 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.json and 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.

Develop

npm test

Uninstall

Remove the plugin from Cursor's plugin settings. Local Evolver memory under ~/.evolver/ is left intact.

License

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.

About

Official Evolver plugin for Cursor — self-evolving agent memory: recall what worked, detect improvement signals, record outcomes (session hooks + skill). MIT.

Topics

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages