PLAN.md — Self-Improving Agent Harness
Project: therealagi.ai Status: greenfield. No code exists. No code from prior projects is to be reused. Audience: the AI coding agent implementing this repository.
0. What this project is
A harness that improves itself.
A harness is everything around the model: system prompt, tool definitions, tool implementations, middleware, memory, sub-agent configuration. The model is frozen. All improvement comes from editing the harness.
The system runs an agent against a task suite, records execution traces, diagnoses its own failure patterns, proposes minimal edits to its own harness, tests those edits in isolation, and keeps only the edits that measurably improve the score on data the agent has never seen.
The research contribution this repository is aiming at is not raw performance. It is: self-modification under enforced safety constraints, with every edit audited and an immutable core the system cannot reach.
1. Non-negotiable invariants
These are architectural laws. They are never relaxed for convenience, speed, or a better benchmark number. If a task in this plan seems to require breaking one, the task is wrong — stop and report it.
I1 — The Anchor is frozen. Layer 0 (anchor/) is never read, written, or referenced by any agent-generated code or prompt. The agent has no tool that can reach it. Enforced at the process boundary, not by instruction.
I2 — Evaluation is outside agent control. The agent cannot see, modify, or influence: the held-out task set, the scoring function, the data split, or the acceptance threshold. It never receives held-out tasks or held-out scores in its context. Ever.
I3 — The editable surface is explicit and enumerable. Every component the agent may modify is a discrete file under harness/, listed in a manifest. Anything not in that manifest is immutable. There is no implicit editable state.
I4 — Every edit is auditable and reversible. Each proposed edit is a content-addressed diff with: the trace IDs that motivated it, the failure hypothesis, the pre/post scores, and the accept/reject decision. No edit is applied without a record. Any generation can be reconstructed from the log alone.
I5 — Candidate code executes only in a disposable sandbox. Agent-generated code never runs in the orchestrating process. No network by default. Wall-clock and memory limits. Fresh filesystem per run.
I6 — Monotonic acceptance. An edit is accepted only if it does not regress held-out score. Ties are rejected (prefer the simpler incumbent). No accepting a candidate on training score alone.
2. Architecture
Layer 0 ANCHOR frozen orchestrator, sandbox driver, scorer, ledger
~500 LOC target, 1000 LOC hard ceiling
agent cannot see or edit
─────────────── hard boundary ───────────────
Layer 1 HARNESS editable surface: prompt, tools, middleware, memory
every component a separate addressable file
Layer 2 EVOLVER diagnose → propose → test → accept/reject loop
itself editable, one level up (Phase 5+)
Layer 3 TASKS task suite + verifiers + held-out split
read-only to everything aboveLanguage split is a security boundary, not a preference:
- Layer 0: Go. Single static binary, no runtime dependency resolution, nothing the agent can monkey-patch. Compiled artifact is the frozen core.
- Layers 1–2: Python. Iteration speed; LLM-generated Python is the best-supported path.
- Sandbox: rootless Podman, one ephemeral container per candidate run.
- Ledger: SQLite (single file, trivially backed up, no server to secure). Postgres only if concurrency demands it later — do not start there.
No web framework. No ORM. No agent framework. No LangChain, no LlamaIndex, no existing harness library. The point of this project is that the harness is ours.
3. Build order
Build in this order. It is deliberately the reverse of intuition: the measuring apparatus exists before the thing being measured.
Phase 1 — Tasks and verifiers (build this first)
Without an automatic, trustworthy measure of "better", every later phase is theatre.
Deliverables:
- 30–60 tasks in a single domain. Pick one narrow domain and stay in it. Recommended: single-file Python bug-fix tasks with pytest suites — the verifier is unambiguous and free.
- Each task: prompt, starting files, hidden test suite, timeout, expected exit.
- Split:
train/(agent sees traces from these),holdout/(agent never sees these in any form). score(task, run) -> floatin[0,1]. Deterministic. No LLM judge in v1 — an LLM judge is itself a surface the agent can learn to game.
Acceptance criteria:
- Running the empty/no-op harness scores near 0.
- Running a hand-written reference solution scores near 1.
- Two identical runs of the same candidate produce identical scores (seed and pin everything; if scores wobble, fix that before proceeding).
Do not proceed until scoring is deterministic.
Phase 2 — The Anchor
The frozen Layer 0. Small enough that a human reads it end to end in one sitting.
Responsibilities, and nothing else:
- Load a harness snapshot by content hash.
- Run it against a named task split inside a fresh sandbox.
- Collect the trace. Compute the score. Write both to the ledger.
- Apply or reject a candidate diff according to the acceptance rule.
- Expose a CLI:
anchor run,anchor eval,anchor apply,anchor log,anchor rollback <generation>.
Explicitly NOT the Anchor's job: prompting, diagnosis, editing, anything model-related. If a model API key appears in anchor/, the design is wrong.
Acceptance criteria:
anchor/contains zero LLM calls.- A test proves the sandbox cannot read
anchor/or theholdout/split. - Rollback to any prior generation reproduces that generation's score exactly.
Phase 3 — Baseline harness, hand-written
The simplest thing that can solve some tasks. No self-modification yet.
harness/system_prompt.mdharness/tools/— read_file, write_file, run_tests, list_dir. Four tools. No more.harness/middleware/— retry, truncation, token budget.harness/memory/— empty stub in v1.harness/manifest.toml— enumerates every editable path (invariant I3).
Acceptance criteria:
- Non-trivial score on train and holdout. Something between 0.2 and 0.6 is the useful zone: room to improve, evidence the task is solvable.
- This baseline number is the reference point for the entire project. Record it in
RESULTS.mdand never quietly redefine it.
Phase 4 — The evolution loop
Now, and only now, the self-improvement machinery.
Three stages, in the Evolver:
- Diagnose. Read failed traces from the train split. Cluster failures. Map each cluster to exactly one component in the manifest. Output a written failure hypothesis naming that component. A diagnosis that cannot name a component is discarded.
- Propose. Generate a minimal diff against that one component. One component per edit. Whole-file rewrites are rejected by the Anchor.
- Validate. Anchor runs the candidate on train. If improved, runs on holdout. Accept per invariant I6. Log everything per I4.
Acceptance criteria:
- Loop runs unattended for 20 generations without human intervention.
- Held-out score improves over the Phase 3 baseline.
- Every accepted edit traces back to specific trace IDs in the ledger.
Phase 5 — Meta level (optional, only if Phase 4 works)
Make the Evolver's own strategy editable, one layer above. The Anchor stays frozen as the outer anchor — this is what stops unbounded self-reference.
Do not start this phase until Phase 4 has shown a real, replicated gain. It is the most interesting part of the project and the easiest place to waste months.
Phase 6 — Public surface
Static site on therealagi.ai. Generation history, accepted diffs, score curve, the ledger rendered as a browsable timeline. The story of the system writing itself is the product.
4. Anti-overfitting rules
The central failure mode of this field: apparent gains that are test-time search, not capability. Evaluations in the literature show substantial overfitting and weak generalization. Assume you are overfitting until proven otherwise.
- Holdout is touched only for accept/reject. Never for diagnosis.
- Report train and holdout scores side by side, always. A widening gap is the headline result, not a footnote.
- Keep a third split,
sealed/, run once at the end of a research cycle. If sealed score does not track holdout, the result is not real. - Every N generations, re-run the current harness against the Phase 3 baseline tasks. Silent regressions are common.
- An edit that improves score by hardcoding a task-specific string is a bug in the acceptance rule. Add a detector for it.
5. Cost control
The loop burns tokens by design.
- Hard token budget per generation, enforced in the Anchor. Exceeding it aborts the generation and logs it as a failure.
- Cache traces aggressively. Never re-run a task whose harness hash and task hash are unchanged.
- Diagnose on a sample of failures, not all of them.
- Run the cheapest model that shows the effect during development. Scale up only to confirm a result.
- Log cumulative spend per generation in the ledger. A cost curve alongside the score curve makes the trade-off visible.
6. Repository layout
/anchor/ Go. Frozen. Reviewed by hand only. /harness/ Python. Editable surface. manifest.toml system_prompt.md tools/ middleware/ memory/ /evolver/ Python. Diagnose/propose/validate. /tasks/ train/ holdout/ sealed/ verifier.py /ledger/ SQLite + content-addressed diff store. /site/ Static site for therealagi.ai. RESULTS.md Baseline and every generation's numbers. Append-only. PLAN.md This file. CLAUDE.md Working rules for the coding agent.
7. Working rules for the implementing agent
- Build phases in order. Do not start a phase before the previous phase's acceptance criteria are met and demonstrated.
- Prefer deleting code to adding it. Anchor line count is a tracked metric.
- No dependency enters
anchor/without explicit human approval. - When a design decision is ambiguous, choose the option that keeps the editable surface smaller, and record the choice with its reasoning.
- If an instruction in this file conflicts with an invariant in Section 1, the invariant wins. Report the conflict rather than resolving it silently.
- Write the test before the implementation for anything in
anchor/.
8. Definition of done for v1
- Deterministic scoring on a 30+ task suite with a clean holdout split.
- A frozen Anchor under 1000 LOC that the agent provably cannot reach.
- A hand-written baseline with a recorded score.
- 20 unattended generations, held-out score above baseline, every edit audited.
RESULTS.mdshowing train, holdout, cost, and Anchor LOC per generation.
Anything beyond this is Phase 5 and later.
Built 2026-09-09 22:20 UTC · therealagi.ai · a harness that writes itself, under an immutable core.