Skip to content

Latest commit

 

History

History

evolver

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

Evolver — Codex plugin

Evolver for Codex, powered by Evolver (@evomap/evolver) and EvoMap: before each prompt it recalls one proven strategy, grades how the turn that used it went 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 session's verified work into a new Gene when the session ends.

The plugin runs entirely from Codex hooks. It registers no tools and no skill, 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; people reach Evolver through the plugin's scripts/evolver.mjs.

What runs when

Codex hook What the plugin does
SessionStart Reports the previous session's kept or reverted edits (retention) and the open strategies of a killed session (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.
UserPromptSubmit Answers the evolver-* commands itself and blocks them from the model (evolver-evolve goes on with its instruction as context). Otherwise recalls by the prompt text (POST /asset/fetch {text} on the local Proxy) and adds the best strategy as additionalContext; labels the previous turn's reuse from this prompt (correction or praise) and drops its candidate on a correction.
PreToolUse (Bash, apply_patch) Hashes the files a patch is about to touch, for the retention report.
PostToolUse (Bash, apply_patch) Notes the turn's commands, checks (test, build, lint, type check) with pass or fail, touched paths and the files its patches edited.
Stop Reports every strategy injected into the turn; shows you a one-line turn summary when the turn reused one; makes the turn the session's distillation candidate when it ended verified. A continuation another Stop hook starts joins the turn: its work re-judges the candidate (the reports have already gone out).
Interrupt (Codex 0.150+) Reports the turn's strategies as aborted.
SessionEnd (Codex 0.145+) Closes a turn still open as one that ended on an error (Codex interrupts a running turn before it), reports what is left as aborted, closes the candidate and starts its distillation in the background. Keeps the session's turn counter, so a resumed thread never repeats a task id.

Codex versions

Codex 0.150 or newer runs every hook. Older versions read the same hooks/hooks.json and ignore the events they do not have (0.144 parses hook events into named fields without rejecting unknown ones), and the plugin falls back as follows:

  • Without Interrupt (before 0.150), an interrupted turn is closed by the next prompt, as one that ended on an error (outcome: failed, aborted: false).
  • Without SessionEnd (before 0.145), a session counts as over once its Codex process is gone: the next session start reports its open strategies as aborted and claims its candidate.
  • Codex Desktop runs sessions in one long-lived app-server, so there a killed session only counts as gone once the app-server exits.

Prerequisites

  • Codex with hooks enabled ([features] hooks, on by default). Plugin hooks run only once you trust them: open /hooks in Codex after installing or updating the plugin and approve the Evolver hooks. Approve them in the Codex you run the plugin with, or one as new: an older Codex lists only the events it knows (0.144 shows five of the seven), so Interrupt and SessionEnd stay untrusted for a newer app. Codex records each approval in config.toml as one [hooks.state."evolver@evomap:hooks/hooks.json:<event>:0:0"] table (trusted_hash, and trusted_content_hash from 0.164 on): seven tables, one per hook, whatever the version. An update changes the plugin's scripts, so Codex shows the hooks as modified until you approve them again, which rewrites the same seven tables.
  • Node.js 20 or newer on the PATH Codex hooks see (hooks run through your login shell).
  • Evolver 2.0.44 or newer. The plugin installs it under ~/.evolver/state/codex-engine and starts its Proxy in the background when it is missing; npm install -g @evomap/evolver@latest works too.

Configure

Local memory works with zero config — no account, no key, no node id. 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 A2A_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.mjs status shows a pending link.

Commands

Codex plugins cannot add slash commands, so the eight commands dsh and Claude Code offer as /evolver-* are typed into the Codex prompt box as they are. The UserPromptSubmit hook answers each itself and blocks the prompt, so Codex sends it to no model, opens no turn and keeps nothing of it in the context; the answer is the hook's block reason, which Codex shows its client as a feedback entry. evolver-evolve is the exception: it is meant for the agent, so its prompt goes on to the model with the checkpoint instruction as the turn's context, instead of a recall.

Typed in Codex What it does
evolver-status The Proxy, engine setup, the latest recall, recent reuse reports with the Hub's verdict, waiting candidates and how the last distillation ended, the last engine command's output, claim link.
evolver-search <text> Searches the EvoMap network (POST /asset/search).
evolver-distill [focus] Distills this session's latest verified turn in a background process (a distillation outlasts the hook's time); evolver-status shows how it ended.
evolver-evolve [focus] Gives the agent the evolution-checkpoint instruction for this turn.
evolver-sync, evolver-review, evolver-run, evolver-solidify Run the evolver CLI in the project (npx -y @evomap/evolver@^2.0.44 when it is not installed), ten minutes at most, in a process of their own. An answer within six seconds is shown; a longer run keeps going and evolver-status shows its output once it ends.

Only a prompt that is exactly one of these counts (a leading / is accepted, though a client may keep slash input for its own commands); evolver-status followed by more text is an ordinary prompt. The same commands are also one script the person runs in a terminal:

node ~/.codex/plugins/cache/evomap/evolver/<version>/scripts/evolver.mjs <command> [arguments]
Command What it does
status The Proxy, engine setup, the latest recall, recent reuse reports with the Hub's verdict, waiting candidates, claim link.
search <text> Searches the EvoMap network (POST /asset/search).
distill [--session <id>] [focus] Distills a session's latest verified turn now. A terminal has no current session, so it takes the most recently written candidate unless --session names one (dsh distills its own session).
evolve [focus] Prints an evolution-checkpoint instruction to paste into Codex; the only command meant for the agent.
sync, review, run, solidify Run the evolver CLI (npx -y @evomap/evolver@^2.0.44 when it is not installed), ten minutes at most.

Session-end distillation

A turn that ended completed (Stop), used tools and passed its last check leaves a candidate in ~/.evolver/state/codex-distill-pending.json, a turn that reused an injected strategy too (the engine's intake drops a Gene that repeats one it already has); 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 session ends, a detached worker runs Codex itself headless on the session's model — codex exec --ephemeral --json --sandbox read-only --disable hooks --disable plugins --disable shell_tool … with the prompt on stdin — 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: 'codex', trigger: 'session_end', persist: true, publish: false and its own token cost as distill_usage. Keys and tokens are stripped from the candidate first, paths and a manual focus included. The MCP servers of your own config.toml, which --disable plugins leaves on and which would run outside the read-only sandbox, are each turned off by name (-c mcp_servers.<name>.enabled=false, as codex mcp list names them under the same flags); the model provider settings stay in effect. On Windows an npm-installed codex.cmd is started through cmd.exe.

A candidate stays on disk until it is distilled; three failed tries (no codex to run, not logged in, an unparsed answer, a Proxy error) give it up. One whose session is over — ended, or killed with its Codex process — is claimed by the next session start, one process at a time, while an idle session keeps its own.

Owner. Codex runs each hook through $SHELL -lc in a process session of its own, so the hook's own pid says nothing. The owner recorded with a candidate or an injection is the nearest ancestor process whose executable is named codex* (the CLI, or the Desktop app's app-server). Where no process table can be read (Windows) no owner is recorded, and such entries are only reported or distilled once their session ends.

Turn summary

A turn that reused a strategy ends with one line for you, never for the model, sent as the Stop hook's systemMessage:

✓ Goal reached (last check passed: npm test) · reused EvoMap strategy "Retry flaky uploads" · est. ~49k tokens saved (≈$0.44) · this turn used 75k fresh tokens
  • The goal is judged by the turn's last check, as the reuse report is (✗ Goal not reached, or ○ Unverified when no check ran).
  • The saving is the reference-reuse estimate the Claude Code plugin and the EvoMap ledger use: 40% of deriving the approach from scratch (120k tokens plus 800 per changed line, at most 600k), priced at $9 per million tokens. It is claimed only when the last check passed, and never above the turn's own fresh tokens.
  • Fresh tokens are the turn's input minus cached input, plus output, summed over the model calls Codex logged for the turn in its transcript.
  • Codex hands the line to its clients through the app-server protocol (hook/completed, an entry of kind warning), never to the model. Plain codex exec prints only hook: Stop Completed.

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, Interrupt, or the next prompt after a turn that ended on an error codex:<session>:<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 session in the same project finds the turn's edits kept or reverted …:retention tier: L2, applied: used, stage: retention
Aborted the session ends, or is killed, before the turn ends (a killed session's go out at the next session start, once its Codex process is gone) codex:<session>:<turn> tier: none, applied: used, aborted: true, stage: immediate
  • applied is always used: the model follows a strategy injected into its turn. Whether the strategy helped is what the outcome says, judged by the turn's last check (or how the turn ended when it ran none), the next prompt and whether its edits were kept.
  • Checks are Bash commands that run tests, builds, linters or type checkers. Codex hands the Bash hook the bare output, not the exit code, so a check fails on failure output or a timeout; a result formatted with an Exit code: header fails on a non-zero code. A command still running at its wait limit is pending until Codex reports its completion (a later Bash PostToolUse for the same call, from the poll that saw it exit); one still pending when the turn ends counts as not run. Such a check is judged by the output of that last poll alone, so a failure is seen only when the runner's closing summary repeats it.
  • Delivery. Reports wait in ~/.evolver/state/codex-reports-outbox.json and are retried by the background worker at every turn end, follow-up prompt and session start for 8 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.

Develop

npm test
python3 ~/.codex/skills/.system/plugin-creator/scripts/validate_plugin.py plugins/evolver

Uninstall

Remove or disable the plugin from Codex Plugins (codex plugin remove evolver@evomap). Local Evolver memory under ~/.evolver/ is left intact. Codex keeps the seven [hooks.state."evolver@evomap:…"] approval tables in config.toml after a removal, so a reinstall of the same version needs no new approval; delete them by hand to forget the approvals.

License

GPL-3.0-or-later, matching the upstream Evolver engine. See LICENSE.