evolutionary-cli-wrapper
v3.7.0
Published
CLI wrapper that scores and guides LLM collaboration efficiency without depending on token access.
Downloads
168
Maintainers
Readme
EvoPet lives in your Claude Code statusline. On every render it shows three things: a context / rate-limit gauge, a mood line from a little pixel pet, and a short, actionable prompt-engineering tip — sometimes with a ❌ before / ✅ after example. Write sharper prompts and the pet levels up; drift into vague requests or fix-loops and it notices and nudges you back.
It runs entirely locally. No Claude API calls, no token consumption, no telemetry, and nothing about your sessions is ever uploaded. The statusline that evo install-statusline deploys makes no network calls of its own; the only optional network access is a once-a-day npm-registry check for an "update available" notice, performed by the evo CLI's own renderer and disabled with EVO_NO_UPDATE_CHECK=1.
There are two ways to use this repository:
- As an npm user — install the package and wire only the statusline into Claude Code. This is the supported path for most people.
- As a developer — clone the repo to hack on the code, run the test suite, or use the in-repo proxy machinery that records and scores whole sessions (not shipped to npm).
Quick install
Prerequisites: Node.js 20 or newer (the statusline is now rendered by the
evoCLI itself). Python is no longer required for a fresh install; it's only needed if you keep a legacy Python statusline or the dev split-wrapper construction.
npm install -g evolutionary-cli-wrapper
evo install-statuslineevo install-statusline is interactive by default and does exactly one thing:
- Sets
statusLinein~/.claude/settings.jsonto{ "type": "command", "command": "evo statusline --full" }, preserving every other key. This wires Claude Code straight at the built-in TypeScript renderer, which draws the complete statusline — the token/model/context line and the EvoPet block — in one process. Your existingsettings.jsonis backed up to~/.claude/settings.json.bak.<timestamp>first, and if the currentstatusLinepoints at a non-EvoPet command you're prompted before it's replaced. (evomust be on yourPATH— it is after a global install.)
Then restart your Claude Code session to pick up the new statusline. Prefer a no-prompt run for CI or provisioning? Add --yes.
Upgrading from an older version? If a previous install wired
python "…/base_statusline.py", it keeps working untouched until you re-runevo install-statusline. Re-running migrates you to theevo statusline --fullwiring and removes the now-orphanedbase_statusline.py. Nothing changes until you choose to re-run it.
Note — two statusline constructions.
evo install-statuslinewires the single-file TS renderer (evo statusline --full), which is the right choice for most people. Advanced/dev setups instead use a split "wrapper" construction — a token-only base plusevo statusline(EvoPet-only), joined by a small wrapper script (this is whatnpm run setupdeploys). To avoid rendering EvoPet twice,evo install-statuslinedetects an existing wrapper setup and leaves it untouched (it prints a one-line notice and makes no changes) rather than overwriting your wiring — while still recognizing its ownevo statusline --fullcommand so re-running stays idempotent.
Don't want to install globally? Run it once with npx:
npx evolutionary-cli-wrapper install-statuslineTroubleshooting
| Symptom | Fix |
|---|---|
| Statusline is blank after install | Restart the Claude Code session. The default display mode has been expansion since v3.5.0; if you're on an older deploy, run evo display expansion then evo install-statusline --yes. |
| Statusline shows nothing / evo: command not found on render | The renderer is now the evo CLI. Make sure evo resolves on your PATH (it does after npm install -g evolutionary-cli-wrapper); evo doctor reports whether the shim is found. |
| Tips didn't change after npm update -g | The TS renderer reads the tips straight from the installed package, so a global update takes effect on the next render — no redeploy needed. (Legacy Python installs still deployed a copy; re-run evo install-statusline --yes to migrate to the TS wiring.) |
| The ⚠ update: notice is noisy / you're offline | The notice comes from the evo renderer. Set EVO_NO_UPDATE_CHECK=1 to suppress the registry check and the notice. |
| You want your old statusline back | evo install-statusline --uninstall restores the most recent settings.json backup (and removes a legacy base_statusline.py if one was left behind). |
Getting started
Once the statusline is live, EvoPet works with no further setup — every prompt you type is scored and the pet reacts. A few commands are worth knowing:
evo stats # your current rank, growth gauge, and recent history
evo pet list # browse the 10 pet species
evo pet choose fox # pick the one you like
evo display toggle # switch between the compact and expanded statuslineUninstalling is symmetric:
evo install-statusline --uninstall # remove the statusline, restore your backup
npm uninstall -g evolutionary-cli-wrapperCommand reference
Commands most users touch:
| Command | What it does |
|---|---|
| evo install-statusline | Deploy statusline.py to ~/.claude/ and wire it into settings.json. --yes skips prompts, --uninstall reverts. |
| evo stats | Show your EvoPet rank, growth gauge, and episode history. |
| evo status [--watch] [--interval N] | Read-only one-screen status: EvoPet identity + growth gauge, current quality/streak, live session binding, quick health summary, and recent-episode summary. --watch re-renders every N seconds (default 5) until Ctrl+C. Never writes any state. |
| evo pet list | List the available EvoPet species. |
| evo pet choose <id> | Set your pet species (e.g. evo pet choose cat). |
| evo display [mode] | Toggle the statusline layout: minimum, expansion, or toggle. No arg prints the current mode. |
| evo doctor | Print a one-page health report — versions, environment, file checks, recent errors, and live-state freshness (--json for machine-readable output). |
| evo doctor --quick | Fast self-check only — bundle present, native dependencies present, native components loadable, and the real claude resolvable. Exits non-zero on any failure; handy for diagnosing a broken wrapper or as a pre-release check. |
| evo logs [--tail N] [--since 30m] [--bundle] | Tail recent Evo log lines, or --bundle a redacted zip of the last 7 days of logs + doctor output for a bug report. |
Developer / power-user commands (mostly relevant after npm run setup from a clone):
| Command | What it does |
|---|---|
| evo init | Create a local .evo/config.json with sensible defaults. |
| evo setup-shell | Install the terminal integration and proxy shims so claude routes through Evo. |
| evo undo-shell | Remove the managed shell-integration block. |
| evo shell on \| off \| status | Enable, disable, or inspect shell integration for new terminals. |
| evo pause / evo resume | Temporarily stop / re-enable the auto-proxy for new sessions. |
| evo mode <auto\|active\|quiet> | Set the default advice verbosity for proxied sessions. |
| evo proxy --cli claude -- <args> | Run claude through the Evo proxy for one invocation. |
| evo run -- <command> | Run any LLM CLI command with episode tracking and scoring. |
| evo explain <episodeId> | Explain how a recorded episode was scored. |
| evo storage | Show the local database footprint and retention status. |
| evo compact | Archive old raw episodes while keeping learned rollups. |
| evo export-knowledge --output <path> | Export learned local stats to a portable JSON bundle. |
| evo import-knowledge --input <path> | Merge a knowledge bundle back into local stats. |
| evo issue show <number> [--repo owner/name] | Print a GitHub issue summarized for AI-agent intake. |
| evo forget | Delete the local .evo history for a project folder. |
| evo uninstall [--purge-data] | Remove shell integration and, optionally, local Evo data. |
| evo statusline | Render the EvoPet portion of the statusline from JSON on stdin (used internally). |
How it works
The Python statusline script is invoked by Claude Code on every render — no polling, no background process. It reads the JSON Claude Code passes on stdin plus, when a developer is running through the in-repo proxy, an optional ~/.claude/.evo-live.json live-state file.
- When the proxy is active, EvoPet reflects real session signals: a per-session turn counter, detected loops, prompt-quality scores, and the current mood.
- When it isn't (the default npm path), the statusline self-tracks call counts in
~/.claude/.evo-self-state.jsonand rotates through the whole tip library — a curated set plus every tip auto-synced from Anthropic's public Claude Code docs — using a tier-weighted round-robin (core / default / niche, weighted 5 : 2 : 1).
The turn counter is scoped to the current Claude Code session ID, so sub-agent dispatches and parallel sessions in the same directory don't inflate or clobber each other's numbers. Since v3.4.0, per-session state lives in <cwd>/.evo/sessions/<sessionId>.json and files older than 7 days are pruned automatically.
Documentation
A full map of everything under docs/ lives in docs/README.md. Highlights:
| Doc | What's inside | |---|---| | CHANGELOG.md | Release history and per-version behavior changes. | | docs/VERSIONING.md | Semantic-versioning policy and release-line layout. | | docs/CONTRIBUTING.md | Commit style, labels, and the PR checklist. | | docs/ROADMAP.md | Planned work and shared-risk areas. | | docs/ai/ | Agent workflow, decision logs, project map, review playbook, and Windows/Zellij notes. |
Configuration
The deployed statusline (base_statusline.py) needs no configuration and reads no environment variables of its own. These variables affect the evo CLI — specifically its built-in evo statusline renderer and its update check:
| Variable | Default | Effect |
|---|---|---|
| EVO_NO_UPDATE_CHECK | unset | When 1, disables the evo CLI's npm-registry update check and its ⚠ update: notice. |
| EVO_HOME | ~ | Overrides where the update-check cache lives (<EVO_HOME>/.evo/update-check.json). |
When the statusline is rendered through the evo CLI (evo statusline), it performs a lightweight update check: with no fresh cache it fires one non-blocking GET to registry.npmjs.org (stale-while-revalidate) and, when a newer version is published, appends an ⚠ update: <current> → <latest> notice. The Python statusline that evo install-statusline deploys does not do this.
| Variable | Default | Effect |
|---|---|---|
| EVO_CONFIG | <cwd>/.evo/config.json | Which config the evo CLI reads (set by the shell shims). |
| EVO_LOG_LEVEL | INFO | ERROR / WARN / INFO / DEBUG. DEBUG also mirrors to stderr. |
| EVO_LOG_DIR | <cwd> | Base dir for logs (<EVO_LOG_DIR>/.evo/logs/session-YYYYMMDD.log). |
| EVO_LOG_DISABLE | 0 | When 1, all log emission is a no-op. |
| EVO_PROXY_ACTIVE | unset | Set to 1 by the proxy when spawning the real claude, used for re-entry detection. |
| EVO_FORCE_NORMAL | unset | Force full (non-lightweight) tracking regardless of cwd heuristics. Wins over EVO_FORCE_LIGHT. |
| EVO_FORCE_LIGHT | unset | Force lightweight tracking regardless of cwd heuristics. |
| EVO_BIND_SESSION_ID | unset | When 1, the proxy injects --session-id <uuid> into the launched claude so the tracker binds to that exact session — best precision when you run several Claude Code windows in one folder. Requires a claude that accepts --session-id; skipped for claude subcommands (mcp/config/doctor/…). |
| EVO_DISABLE_STICK_HARD | unset | When 1, restores the pre-3.6.9 behavior where the tracker may re-attach to a newer session's transcript in the same folder (escape hatch; not recommended). |
Privacy / Data at rest
Evo scores your collaboration locally. Nothing is sent anywhere — the only network call is the optional npm update check (disable with EVO_NO_UPDATE_CHECK=1).
What is stored. Per turn, a capped preview of the input you sent the wrapped CLI (at most 500 characters), a sha256 hash and length of the full input (so repeated prompts can be recognized without keeping the text), a short output preview (~160 characters), plus derived metrics (detected file paths, token counts, friction/complexity scores).
Where. Under <project>/.evo/ — the SQLite database .evo/evolutionary.db, redacted logs in .evo/logs/, and per-session counters in .evo/sessions/. Session-owner markers under .evo/sessions/.owners/ (used to keep concurrent windows from claiming each other's session) hold only a session id, process id, and timestamp — no prompt or output data. A small live-status file is also written to ~/.claude/.evo-live.json for the statusline.
Retention. Logs older than 7 days are pruned automatically; the database is compacted on a size/age policy (evo storage shows the footprint, evo compact archives old raw episodes into rollups).
How to disable prompt-text capture. Set capture.promptText to false in <project>/.evo/config.json. Evo then stores only the sha256 hash and length of your input — no input text, no input previews, and no output previews (the wrapped CLI's output can echo your input back, so it is covered too).
{ "capture": { "promptText": false } }How to purge. evo forget deletes the local .evo/ history for the current project; evo uninstall --purge-data removes the shell integration and deletes the project's .evo/ data.
The Pet
EvoPet is what makes this a companion and not just another linter. It has an identity that reacts to how you drive Claude Code.
Ten species to choose from — the pet starts as 🐣 chick, and you can switch anytime with evo pet choose <id>:
🐣 chick · 🐱 cat · 🐶 dog · 🦊 fox · 🐰 rabbit · 🐻 bear · 🐼 panda · 🐨 koala · 🐯 tiger · 🐧 penguin
Five evolution stages. Crucially, the stage is driven by the Ideal State Gauge (ISG) — a rolling measure of sustained prompt quality — not by cumulative experience. Keep writing clear, structured prompts and your pet climbs; let quality slip and it can drop back down. That's the whole point.
| Stage | Rank | ISG band |
|---|---|---|
| 🥚 egg | Beginner | < 25 |
| 🌱 sprout | Apprentice | 25 – 45 |
| 🐾 buddy | Practitioner | 45 – 65 |
| 🧙 wizard | Skilled | 65 – 82 |
| 👑 legend | Master | 82+ |
Five moods that shift with the session: chill when idle, good on a clean first pass, fired up when a nudge could save real tokens, worried when it spots an edit- or search-loop, and proud when your prompt structure is genuinely dialed in.
Combos and the growth gauge. A "good" prompt — structured, first-pass green, no loops — extends a combo streak, with celebrations at 3, 5, 10, and 20 in a row. The growth gauge you see (育成度) is the Ideal State Gauge: it only pins near 100% when recent prompt quality is high and your last few episodes were loop-free.
Under the hood, a signal detector watches for patterns like prompt_too_vague, same_function_revisit, scope_creep, no_success_criteria, and approval_fatigue, then turns the top one into a single, concrete suggestion — often with a before/after rewrite of your own request.
Contributing
Contributions are welcome. In short:
- Daily development happens on
main; stable lines live onrelease/vX. - One issue = one branch (
codex/<issue-or-topic>) = one PR. Keep docs and implementation in the same PR and don't widen scope mid-branch. - Before touching shared-risk areas (
src/proxyRuntime.ts,src/index.ts,src/scoring.ts,src/db.ts,scripts/setup.mjs), leave a note in the issue or docs/ROADMAP.md. - All docs are UTF-8.
Build and test from a clone:
git clone https://github.com/1-10maru/evolutionary-cli-wrapper.git
cd evolutionary-cli-wrapper
npm install
npm run build # tsc → dist/
npm test # vitestnpm run setup additionally deploys the shell shims and statusline for full developer mode; evo undo-shell or evo uninstall reverts it. Full guidelines: docs/CONTRIBUTING.md.
License
ISC © 1-10maru
