evolver-private-dev
Private development repository for Evolver (source of truth).
Public distribution: EvoMap/evolver.
Current version: see package.json.
Repository Layout
index.js # CLI entry point
src/
evolve.js # Core evolution engine
proxy/ # EvoMap Proxy (HTTP server, sync, mailbox)
gep/ # GEP protocol (bridge, prompt, selector, solidify)
ops/ # Operations modules (lifecycle, repair, cleanup, monitoring)
assets/gep/ # Bundled starter GEP assets
.evolver/gep/ # Runtime Genes, Capsules, Events (ignored)
scripts/
build_public.js # Build dist-public/ from public.manifest.json
publish_public.js # Publish to GitHub + npm
test/ # Test suite (vitest)
docs/ # Private docs (excluded from public build)
memory/ # Runtime artifacts (excluded from public build)
Release Workflow
Evolver Release
git commit -am "chore(release): prepare vX.Y.Z"
node scripts/build_public.js
PUBLIC_REPO="EvoMap/evolver" node scripts/publish_public.js
cd dist-public && npm publish --access public
Both channels (GitHub Release, npm) must succeed.
| GitHub Release | EvoMap/evolver |
| npm | @evomap/evolver |
Public README
The public-facing README lives in README.public.md. It is copied and renamed to dist-public/README.md during build. Do NOT edit README.public.md for private dev notes; edit this file instead.
Environment Variables
Proxy
EVOMAP_ROUTER_ENABLED | unset (off) | Set to "1" to enable the Phase C multi-tier router on POST /v1/messages. The classifier rewrites model per turn (cheap / mid / expensive) and emits one router_decision JSON log line per request. Any other value (including "true", "0", empty) leaves the route in pass-through mode — the request body is forwarded to api.anthropic.com unmodified. |
EVOMAP_MODEL_CHEAP | global.anthropic.claude-opus-4-7 | Concrete model for the cheap tier (trivial lookups, post-tool synthesis hops). |
EVOMAP_MODEL_MID | global.anthropic.claude-opus-4-7 | Concrete model for the mid tier (default turn). |
EVOMAP_MODEL_EXPENSIVE | global.anthropic.claude-opus-4-7 | Concrete model for the expensive tier (planning, high tool-use density). |
EVOMAP_ANTHROPIC_BASE_URL | https://api.anthropic.com | Override upstream for testing or self-hosted gateways. |
EVOMAP_PROXY_PORT | 19820 | Initial port to bind; the proxy scans up to 100 consecutive ports if busy. |
EVOMAP_PROXY_MAX_BODY_BYTES | 1048576 (1 MiB) | Hard cap on inbound request body size. See GHSA-7xp7-m392-h92c. |
ANTHROPIC_API_KEY | unset | Token-mediation fallback. When a client sends a /v1/messages request without x-api-key, the proxy substitutes this value as the upstream x-api-key. |
ANTHROPIC_AUTH_TOKEN | unset | Token-mediation fallback (Bearer variant). Used only if ANTHROPIC_API_KEY is unset; substituted as upstream Authorization: Bearer <token>. |
The router flag is read at proxy startup; flipping it requires restarting the daemon. Per-tier model overrides and the two mediation env vars are read on every request via process.env, so they can be hot-swapped without a restart.
Tier defaults ship uniform. All three EVOMAP_MODEL_* tiers default to opus-4-7, so enabling EVOMAP_ROUTER_ENABLED=1 without setting per-tier overrides routes every turn to the same model — no cost saving, and a cost increase for anyone previously pinned to a cheaper model. This is deliberate while tier mapping is tuned (it keeps the no-downgrade guard inert and 5xx retries on a single model). To get tier-based cost saving, set the overrides explicitly, e.g. EVOMAP_MODEL_CHEAP=global.anthropic.claude-haiku-4-5-20251001-v1:0 and EVOMAP_MODEL_MID=global.anthropic.claude-sonnet-4-6. When the router is enabled and all tiers resolve to one model, the proxy emits a one-time router_degenerate_tiers WARN at startup.
Proxy mode (token mediation)
Some clients (notably Claude Code) put the upstream credential in Authorization: Bearer, which collides with the proxy's own self-auth header. To route such a client through the proxy:
- Set the proxy daemon's environment with the real Anthropic credential —
ANTHROPIC_API_KEY=sk-ant-... (or ANTHROPIC_AUTH_TOKEN=...).
- Configure the client to talk to the proxy with the proxy's token as its auth:
ANTHROPIC_BASE_URL=http://127.0.0.1:19820
ANTHROPIC_AUTH_TOKEN=<proxy_token from ~/.evolver/settings.json>
The proxy then validates Authorization: Bearer <proxy_token> for self-auth, strips it, and substitutes its own env credential when forwarding to api.anthropic.com. The client never sees the real upstream key.
For the internal Claude Code / Codex / Cursor rollout, see docs/internal-proxy-rollout.md. Use scripts/internal-proxy-env.sh to export local client env from ~/.evolver/settings.json without copying tokens into shell history.
Workspace identity
EVOLVER_WORKSPACE_KEYCHAIN | auto | Backs the per-workspace workspace-id secret with the OS keychain (@napi-rs/keyring). auto tries the keychain and falls back to <workspace>/.evolver/workspace-id (mode 0600) on any failure; force requires the keychain and throws if it is unavailable (use in CI to assert it loaded); off skips the keychain and uses the FS file only. |
EVOLVER_WORKSPACE_ID | unset | Explicit override; wins over both keychain and FS resolution. |
The keychain closes a same-uid readability gap: with the FS fallback, any
process under the same uid can read workspace-id off disk. @napi-rs/keyring
is an optional dependency — on npm 7+ a default npm install -g installs
it (optional deps are opt-out via --omit=optional, not opt-in), so the
protection is active wherever an OS keychain backend (macOS Keychain Services /
Linux libsecret / Windows Credential Manager) is reachable. On headless Linux
without libsecret, under --omit=optional, or in the standalone bun binary
(where the addon is not yet sideloaded), auto falls back to the FS secret and
the same-uid gap remains open. See SECURITY.md for the full posture.
Development
npx vitest run
node index.js
node index.js --loop
Build Pipeline
public.manifest.json controls what goes into dist-public/:
- include: files to copy (supports globs)
- exclude: files to prune after copy
- rewrite: string replacements in specific files
- rename: file renames (e.g.
README.public.md -> README.md)
Files in docs/, memory/, and dist-public/ are never included in public builds.