You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Ring 3 rework: the evolution loop now closes in code, measures honestly, and
uses the LLM for the one step that needs intelligence.
Added
LLM skill synthesis (src/evolve/synthesis.rs): seeded skill bodies are
synthesized by a headless claude -p call from the session's real failure
evidence (per-category error snippets, counts, detected patterns) instead of
static templates. Falls back to the template body on any failure; synthesized
content passes the same validate → Critic → gate path. Config: [evolution] llm_synthesis / llm_synthesis_cmd / llm_synthesis_model / llm_synthesis_timeout_secs / llm_synthesis_max_per_session. Recursion
guard via EPIC_SYNTH_CHILD=1 + EPIC_HOOK_PROFILE=minimal; disabled in
debug builds unless EPIC_SYNTH_FORCE=1.
Error snippet evidence: SessionAnalysis.error_snippets — one masked,
truncated representative snippet per failure category.
Holdout A/B attribution: deterministic date-keyed rotation
(hash(skill, date) % attribution_holdout_modulus) withholds under-evaluation
skills for ~1/3 of days; avg_score_without now averages genuine holdout
sessions (SkillAttribution.sessions_holdout, new SQLite column with
idempotent migration). Config: attribution_eval_sessions, attribution_holdout_modulus.
Deterministic evolved-skill injection: epic resume prints active
evolved skills' bodies to stdout so SessionStart injects them into context —
no more reliance on _dispatch prompt obedience to scan evolved/.
Changed
Skill eviction now requires evidence from both arms (≥3 active AND ≥2
holdout sessions) instead of acting on the confounded legacy delta.
Attribution scores only skills the session actually saw: the pre-seed skill
listing is used, so skills seeded at session end no longer get credited with
that session's score.
_dispatch no longer instructs the model to scan $HARNESS_DIR/evolved/
(holdout-arm skills must stay out of context).
Fixed
Cargo.toml description and AGENTS.md structure line now match the real skill
count (26 + _dispatch).
Holdout partition now uses the session-start date on both resume and reflect, so a session spanning UTC midnight no longer credits an
active-injected skill to the holdout baseline (the confound this rework
removed).
mask_secrets now masks absolute file paths (Unix/Windows/tilde-home) so
error snippets can't leak repo paths into the synthesis prompt or generated
skills.
LLM synthesis default timeout/per-session tightened (30s×2 → 10s×1) to keep
the reflect SessionEnd hook well under host hook budgets.
Install epic-harness 0.8.1
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/epicsagas/epic-harness/releases/download/v0.8.1/epic-harness-installer.sh | sh
The plugin-native release. epic-harness now distributes as a single plugin layout that Claude Code, agy (Antigravity CLI), and codex read directly from disk — the install subcommand and the embed+copy pipeline are gone.
Changed — Plugin-native distribution (breaking)
Removed epic-harness install/uninstall + install.rs/install_wizard.rs (~2,330 LOC). Skills, hooks, and the harness-mem MCP server now load from a root plugin layout (plugin.json, skills/, hooks.json, .mcp.json) read directly by each tool.
Skills moved to repo root (registry/skills/ → skills/). registry/commands/ dropped (commands were already consolidated into skills).
Config seeding relocated: ~/.harness/config.toml + HARNESS.md are now self-seeded by the resume hook (config::ensure_global_config) on first session — idempotent (config.toml write-once, HARNESS.md synced only when stale).
Tool support narrowed to Claude Code + agy + codex. The cursor/opencode/cline/aider integrations were removed.
The HarnessX evolution-engine release. Adapts the AEGIS pipeline (arXiv:2606.14249v1) to epic-harness's single-agent, per-project evolution loop. The evolution engine went from "reactive single-agent + SKILL.md-only" to strategic, typed, regression-protected, and self-verifying. ~5,000 LOC across 5 PRs (#75–#80), +69 tests, all CI green. Driven by the gap-analysis at docs/analysis/harnessx-vs-epic-harness-gap-analysis.md (vault mirror ref-010).
Added — Evolution engine
Digester (src/evolve/digester.rs): compresses a session's observations into per-task TaskDigests — binary outcome, ranked failure categories, implicated components, evidence excerpts, tool trajectory, cross-iteration persistence. Paper §4.3.
Planner (src/evolve/planner.rs): builds an AdaptationLandscape (persistent failures, attempted edits, edit-type coverage, untried edit types, component heatmap) and flags under-exploration. Paper §4.3 — the primary defense against local-minimum bias.
Typed edits (src/evolve/edits.rs): HarnessEdit enum (AddSkill/ModifySkill/AddGuardRule concrete; ModifyConfig/AddInstinct reserved) with a falsifiable EditManifest per edit (edit_type/target/intended_effect/predicted_impact). Paper §4.3 / Table 9. edit_type now persists in SQLite and round-trips (was hardcoded AddSkill).
Seesaw (src/evolve/seesaw.rs): per-task regression gate that blocks seeding when a previously-solved task regresses beyond tolerance. Paper §4.1. (Deliberately per-task, not per-dimension — the paper §6.6 proves per-dimension gating misses sub-threshold coupling.)
Variant isolation (src/evolve/variants.rs): VariantPool with fork-on-regression (spawns a sibling variant rather than overwriting) and warm/cold stack-based routing. MAX_VARIANTS separate from MAX_EVOLVED_SKILLS. Atomic persistence. Paper §4.5 — the real catastrophic-forgetting defense.
Reward-hacking detection (src/evolve/metrics.rs::detect_reward_hacking): least-squares slope of output_quality vs execution_cost (efficiency proxy, higher=better) over a configurable window. Configurable thresholds in EvolutionConfig. Now computed + persisted (was a dead flag).
Critic layer (src/evolve/critic.rs + registry/skills/_critic/SKILL.md): deterministic in-loop Critic (no external LLM, per project rule) that suppresses seeding under reward hacking and rejects manifests claiming score lifts that contradict evidence. The _critic skill is the out-of-band LLM counterpart for non-local effects.
Falsifiability ledger: each shipped edit's EditManifest is persisted to EvolutionRecord.manifests + a manifests.jsonl sidecar. (The cross-round Critic read that verifies predictions held is honestly documented as a deferred follow-up — the write loop is wired.)
AddGuardRule concrete editor (src/hooks/guard.rs::append_guard_rule): appends a blocked/warned rule to the project's guard-rules.yaml via atomic read-modify-write, round-trip safe through the incumbent parser. Makes the Planner's add_guard_rule untried-edit-type attemptable.
Regression harness (tests/evolve_regression_test.rs): 6 hermetic scenarios (no live benchmark, no SQLite, no network, no HOME redirect) locking the seesaw/variant/planner/outcome-score contracts — the validation substrate the gap-analysis demanded before the engine's claims could be trusted.
Processor abstraction (src/hooks/processor.rs): HookPoint enum (6 lifecycle points ↔ subcommands) + Processor trait + static dispatch table wrapping the existing run() hooks unchanged. Representational seam (paper §3.2) — a full in-process pipeline redesign was explicitly rejected as the most invasive change.
Added — Harness as a first-class object
HarnessSnapshot + CLI (src/evolve/snapshot.rs, src/harness_cli.rs): epic harness snapshot (JSON + deterministic content hash), epic harness diff <a> <b>. restore deferred (destructive). Was dead code; now constructed.
5 new dashboard handlers (src/serve.rs): get_seesaw_registry, get_variant_pool, get_harness_snapshot, get_adaptation_landscape, get_manifests (tail-reads the falsifiability ledger, capped 50).
3 previously-broken dashboard panels fixed: get_session_snapshots, get_global_patterns, get_effect_pending were returning "null" via the dispatch fallthrough; now implemented.
Evolution.svelte: reward-hacking warning banner (when reward_hacking_suspected), Seesaw/Variants/Adaptation-landscape panels, edit_type column in evolution history. Promise.allSettled so a cold project degrades gracefully.
docs/references/operational-mirror.md: maps the evolution engine onto RL vocabulary (state/action/reward + the three pathologies → concrete defenses) with a tuning guide. Paper §4.1–4.2, §7.3.
Seesaw reg.update() latent bug: the solved-task registry update now only runs when the gate passed. Previously it ran unconditionally, which could raise a task's best-of on a regressing round's coincidental high scores and mask future genuine regressions.
Flaky rebuild_produces_stable_hash test: switched from live build_snapshot() (which diverged when a parallel test wrote to evolved_dir()) to a hermetic fixture.
SQLite DDL migration: evolution_records.edit_type added via idempotent ensure_column (pragma_table_info guard + AssertSqlSafe), so existing databases upgrade without manual surgery.
Reward-hacking + epoch_class SQLite round-trip: were hardcoded false/None on load; now read from the metrics_state key/value table.
Changed
seed_smart_skills() split into plan_skill_edits() (pure planner, emits Vec<HarnessEdit>) + apply_skill_edits() (Critic-verifies then applies) — signature preserved, behavior unchanged for the common path.
EditManifest, Metrics now derive Serialize/Deserialize/Default.
cargo clippy --all-targets -- -D warnings remains clean across the stack; 643 lib + 6 regression + 7 CLI tests.
Known limitations (documented in code)
Falsifiability loop is write-only: manifests persist, but the cross-round Critic read is a deferred follow-up.
Seesaw is deliberately coarse (per-task); sub-threshold coupling out of scope — variant isolation is the practical mitigation.
AddGuardRule editor is concrete but Planner auto-emission is not wired (conservative).
HarnessSnapshot restore deferred (destructive).
Processor trait is a representational wrapper (main.rs dispatch unchanged).
File-based evolution readers (seesaw/variants/snapshot/manifests) thread project via *_for(project) — every dashboard panel now reflects the selected project.
metrics_state / evolution_records / score_history / skill_attribution writers bind the project slug; metrics_state and skill_attribution gained composite PKs (key, project) / (skill_name, project) via idempotent table-rebuild migrations.
score_history DELETE is project-scoped (was whole-table — a latent cross-project data-loss bug).
EditType::from_db_str no longer distorts unknown DB values into AddSkill — added EditType::Unknown (excluded from coverage) and made "add_skill" explicit.
edit_type_roundtrips test timestamp is index-based; token_estimate / estimate_tokens documented as intentional scaffold.
Install epic-harness 0.7.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/epicsagas/epic-harness/releases/download/v0.7.0/epic-harness-installer.sh | sh
Dashboard always shows the installed version: the sidebar had a hardcoded v0.4.1 and __APP_VERSION__ was declared but never defined, so the dashboard version display was frozen regardless of the installed release. The running binary now stamps its own CARGO_PKG_VERSION into the served HTML via <meta name="harness-version"> (serve.rs), and the sidebar reads it at runtime (build-time __APP_VERSION__ from app/package.json is the vite dev fallback). The version is now correct for every install/update without depending on a frontend rebuild. app/package.json was added to the version-bump checklist.
Release build reproducibility: Cargo.lock is now tracked (it was gitignored). The v0.6.4 release failed in CI because, without a lockfile, CI resolved brotli-decompressor 5.0.2 (published 2026-06-13), which broke brotli 8.0.3's implement_allocator macro. The committed lock pins brotli-decompressor to 5.0.1, matching the successful v0.6.3 build. Otherwise identical to 0.6.4.
Install epic-harness 0.6.5
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/epicsagas/epic-harness/releases/download/v0.6.5/epic-harness-installer.sh | sh
SQLite operational store: all project operational data (observations, sessions, metrics, evolution, orbit pipelines, evolved skills) now stored in harness.db alongside the existing memory.db knowledge graph
epic-harness migrate subcommand: import legacy JSONL/JSON data into SQLite (--dry-run to preview, --reset to retry interrupted migration)
store::observations::query_latest_observations_conn(): query N most recent observation records
Changed
Dashboard commands (get_harness_metrics, get_orbit_pipelines, get_evolved_skills, get_obs_summary) now read from SQLite instead of file I/O
observe hook writes to SQLite first, falls back to JSONL on write failure
reflect hook reads/writes metrics and evolution data from SQLite
snapshot hook syncs sessions and orbit pipelines to SQLite
Web dashboard HTML response now includes Cache-Control: no-cache header to prevent stale UI
Migration Guide
Existing users with JSONL/JSON data should run once after upgrading:
epic-harness migrate --dry-run # preview what would be imported
epic-harness migrate # perform the import
Original files are not deleted after import. New users are automatically on SQLite — no action needed.
Install epic-harness 0.5.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/epicsagas/epic-harness/releases/download/v0.5.0/epic-harness-installer.sh | sh