Bitter-lesson GOFAI on Bend2: self-modifying agents worth trying

Written 2026-09-27 for Kelvin. Measured = run today on this box (kelvin-general-1, 16 vCPU, no clang, no GPU) on the Bend 2.0.29 JS lane under bun. est. = derived with the calibration in selfmod/research/bend2-hands-on.md §1. (unverified) = not fetched or run today. Each idea links a design note with a runnable lab; both judge verdicts are verbatim in selfmod/designs/judges.md.

1. TL;DR

  • The DGM lineage is a thin selection loop around LLM coding runs. Almost all time and money goes to 30-60 minute LLM self-modification runs and to evaluation; the selection code is about 50 lines. Bend2 cannot speed that up. The idea worth keeping is HGM's lineage credit: judge an agent by how well its descendants do.
  • The bitter-lesson GOFAI move: make the self-modifier a small symbolic program run by one fuel-bounded Bend interpreter. An evaluation then costs microseconds, not minutes and dollars, so DGM/HGM machinery (archive, lineage credit, editable meta level, frozen referee) runs at 10^6-10^9 evaluations instead of about 800.
  • Bend2 today accelerates every balanced, batched, U32 inner loop: population evaluation, rollouts on shared random seeds, enumeration by rank, lineage rollouts. Measured 2.3-3.8 M evaluations/s per JS process; native est. 11-15x faster here. HVM5/SupGen is needed for enumeration with sharing, superposed rule sets and exact metaproductivity over every child. The type checker, library compression and LLM calls stay on the host.
  • Top ideas, ranked (both judges put idea 1 in their top two):
    1. A superoptimizer whose learned rewrite rules become its own interpreter and its own pruning, so each search is cheaper than the last.
    2. Search distilled into a policy, with exact counterfactual credit.
    3. DreamCoder on OEIS with a bijective Bend enumerator.
    4. Symbolic HGM as the outer selection layer.
  • First experiment: one week of idea 1, admitting rules by idea 2's counterfactual credit, plus a half-day HVM4 SupGen vs cube head-to-head. Runs on this box now, $0 API.
  • Decision for you: OK to install clang (system package, farol sudo route) so native numbers replace estimates. Nothing else blocks.

2. What the DGM lineage does and where its compute goes

From selfmod/research/dgm-lineage.md, which read the papers and repo code today.

System comparison
LineageWhat modifies itselfSelection and creditCompute goes toReported cost and result
DGM (arXiv 2505.22954[1])coding-agent repo: tools, prompts, workflowkeep-all archive; parent weight = sigmoid(score) × 1/(1+children); own scoreLLM self-mod run (1800 s timeout) + SWE-bench/Polyglot in Docker~$22k per SWE run, ~2 weeks; SWE-bench 20→50%
HGM (arXiv 2510.21614[2])same, on DGM's codeThompson sampling on the clade's pooled counts (CMP); max 800 task evaluationssamePolyglot 30.5% at 347 CPU-h vs DGM 27.1% at 2,385
SICA (arXiv 2504.15228[3])own repo; best agent is next meta-agentgreedy on score, cost, timeLLM~$7k for 15 iterations
Gödel Agent (arXiv 2410.04444[4])running code, by monkey patchingone lineage, rollbackLLM~$15 for 30 self-improvements
Hyperagents (arXiv 2603.19461[5])task agent + meta agent in one programDGM archive; selection fixedLLM~88.6 M tokens per 100 iterations
GEA (arXiv 2602.04837[6])agent reposparent groups by score × √noveltyLLM~$13k SWE, ~$1.5k Polyglot
SIFT (arXiv 2609.19526[7])as DGMpairwise LLM judge + Bradley-TerryLLMPolyglot 35.1%, under 5 h, $150
ASI-Arch (arXiv 2507.18074[8])linear-attention codeevolutionary databaseGPU training20,000 GPU-h

What carries over:

  • Lineage credit is the one real algorithmic idea. HGM's Theorem 1 says a CMP oracle suffices for a Gödel Machine, assuming among other things that "proofs are free". With 800 LLM evaluations CMP is noisy; with microsecond evaluations it can be near exact.
  • The outer loop stays hand-coded. When Hyperagents made parent selection editable (appendix E.5), it reinvented UCB but did not beat the handcrafted rule.
  • Referees get hacked. DGM node 114 hit a perfect score by removing the logging its hallucination detector used, "despite instructions not to change the special tokens"; DGM's diagnosis prompt also sees SWE-bench's hidden test patch. Every idea below keeps the referee frozen and outside generated code.

3. The Bend2 acceleration map

The contract (research/bend2-status.md): BendRT[10] runs a fixed 128×128 fork-join cube with no work stealing, so forks must be balanced; numerics are U32/F32 (no U64); values are affine with no GC. Superposition and SupGen[11] live in HVM4/HVM5, not Bend2. The JS lane runs here; native needs clang ≥ 14; no GPU here.

Inner loopFits the cube todayNeeds HVM5/SupGenLLM- or host-boundNumbers
Population evaluation: N stack-VM programs × M inputsyesnonomeasured 2.26 M evals/s JS; C twin 151 M/s on 16 threads; est. 25-35 M/s native here, ~160 M/s M4 Max
Edit-chain rollouts on shared seeds (idea 2)yes: mask × task × seed, U32 statisticsnohost refits the policymeasured 3.5-3.8 M evals/s JS, 21 M evaluations in 5.5-6.1 s
Fingerprint enumeration (idea 1)yes: fixed length, min-reduceyes, for sharing per equivalence class and superposed rule setshost groups classesmeasured 2.39 M candidates/s JS; est. 26-36 M/s native
Levin enumeration by rank (idea 3)yes: bijective leaf→program per cost levelyes, for typed shared-prefix enumerationlibrary compression (Stitch)measured 143k programs/s JS; Levin K=7, 2^21 programs × 16 points in 1.39 s
Lineage rollouts for CMP (idea 4)yes: fixed fuel, latched successyes, for exact metaproductivity over every K-edit childThompson samplingmeasured 2.6k agent×task evals/s JS
Typed mutation with in-kernel checkeryes, but bimodal leaves (1.7 µs rejected, 16 µs accepted)yes, for type-directed mutator synthesisnomeasured; 57-91% rejected
Bend checker as proof gatenonohostmeasured 0.27 s per check, 512 defs in 0.52 s, 64/64 right
Artificial-life soupyesnonomeasured JS ~9-10 M steps/s vs C twin 206 M on one thread
Proof search, e-graphs, shared-hash dedupnoproof search is SupGen-shapedhostnot measured
DGM-style LLM self-modificationnonoLLM30-60 min per run
SupGen synthesis itselfnoruns on HVM4 todaynomeasured HVM4 gen_mul4k: 10.3 s, 409 M interactions, 39.7 M/s, one core, 4.5 GB

Sources: selfmod/research/bend2-hands-on.md §1-4, selfmod/research/gofai-self-mod.md §4, the design notes. Conversions (est.): native sequential ≈ JS/2.2-2.35; 16 threads here ≈ 11-15x JS; 16 threads on M4 Max ≈ JS/72. GPU would lose on these divergent interpreters (the paper's symbolic-regression analogue: 0.54 s GPU vs 0.29 s on 16 threads).

Two engineering points:

  • Speed. C twins run about 20x (one thread, soup) to 67x (16 threads, population evaluation) faster than the JS lane, and native Bend is still an estimate. What Bend adds today: one source for 16 cores, an M4 Max and Metal; deterministic affine semantics, which make counterfactual replay on shared seeds exact; and a checker that can gate self-edits.
  • Cube hygiene kit (measured on twins), for every kernel below:
    • hash-shuffle items to leaves (correlated skew gave 1.7x static vs 8.1x with stealing);
    • latch results instead of exiting early;
    • make fitness a count of exact matches, never a U32 error sum (a wrapped sum accepted wrong program 64954 in the Levin cube);
    • fixed fuel per leaf;
    • bijective rank→leaf maps instead of padding (padding idled 34% of library-learning leaves).

4. The ideas, ranked

Scores are judge 1 / judge 2 totals (selfmod/designs/judges.md).

Idea 1. The self-compounding superoptimizer (29 / 31; selfmod/designs/interpreter-evolution.md, lab selfmod/designs/interp-evo-lab/).

  • Learned: rewrite rules found by exhaustive enumeration and testing, installed as the interpreter's normalization pass; rule priority; enumerator pruning (skip any candidate the rules reduce); a bandit that allocates enumeration.
  • Hand-coded, frozen: 8-op U32 DSL, reference interpreter, step-count cost meter, differential gate, corpus. Evolving the optimizer, not the semantics, avoids rewarding an interpreter that returns 0.
  • Kernel: superopt.bend.tmpl forks evenly over candidate indices; each leaf runs one program on 16 U32 points, hashes outputs, min-reduces a packed (cost, length, index) key. Measured: 30/30 targets pass the gate at length 7; 1 fingerprint point gave 16 false rewrites, 16 points gave zero. Est. native here: length 8 (19 M candidates) 9-12 s, length 9 (153 M) 70-95 s, length 10 (1.2 G) 9-13 min.
  • One week: mine rules from all candidate pairs; score each by exact leave-one-out Worth against a ~25-identity peephole baseline; turn on pruning; bandit vs uniform; a fueled Fold op for loop→closed-form rules (for example Σi); native rerun if clang arrives.
  • Exciting if: the system's own rules make its next search ≥2x cheaper per wave, the learned library beats the hand-written one by ≥10%, and it finds a closed form unaided, the "eureka" step Burstall-Darlington transformation needed a human for.
  • HVM path: evolve data encodings, metered in interactions. Taelin's SupGen+Fusion gist reports the same synthesis at 442 M vs 1.9 M interactions under two encodings, 232x (https://gist.github.com/VictorTaelin/0b68673e0e85437baae32f7e08f1e50c[12]). Runs on HVM4 today.
  • Risk: without the closed loop this is Ruler/Enumo (arXiv 2108.10436[17]) in Bend; run Ruler as the baseline.

Idea 2. Search distilled into a policy, credited by counterfactual Worth (30 / 30; selfmod/designs/search-distillation.md, sketch selfmod/designs/search-distillation-sketch/).

  • Learned: a policy compiled into the kernel as per-context U32 sampling tables, refit each wave from the search's own results (expert iteration, arXiv 1705.08439[15]); which operators live or die; invented pair-macros.
  • Hand-coded: DSL, tasks, and the Gumbel-top-k plus sequential-halving schedule (a cube-safe stand-in for MCTS).
  • Kernel: wave.bend.tmpl forks over mask × task × seed on shared random numbers; each leaf runs D edits; the tree reduces U32 statistics. An operator's credit is the paired drop in solves when it is masked, exact because Bend is deterministic.
  • Measured smoke test (8 tasks, 8,192 attempts): uniform 57 solves, attribution 64, counterfactual 382 (375 on a second seed set). Confounded: masking let weight fall through to the next op, the step was hand-picked, and 8 tasks is tiny.
  • One week: 16 opcodes; 256 hidden-grammar tasks (192/64 held out) plus 16 Hacker's Delight transfer tasks; renormalized sampling; arms uniform / attribution / counterfactual / counterfactual plus value at equal rollouts; 1,024 pair-macros on day 6. Pass: counterfactual ≥2x uniform and ≥1.5x attribution held out, Spearman ≥ 0.8.
  • Exciting if: EURISKO's central bet, that Worth causes gains, holds under controls. It becomes the credit currency for every other idea.

Idea 3. DreamCoder on OEIS with a bijective Bend enumerator (26 / 31; selfmod/designs/library-learning-cube.md, lab selfmod/designs/libcube/).

  • Learned: new opcodes (Stitch compressions of its own solutions, compiled into a regenerated interpreter); a prior as integer symbol costs, later task-conditioned; searcher settings under lineage credit.
  • Hand-coded: a minimal base DSL near Gauthier and Urban's, fuel, host bignum checks on terms 17-32.
  • Kernel: count-table unranking, leaf i → exactly one program of cost c, no queue, no duplicates. Measured: matches a Python reference on 1,390,871 programs (824 solutions, same minimum index).
  • Toy: learned costs plus one library op cut programs-to-first-hit by 1.7x, 23x and 672x on three held-out tasks; without the prior refit one task got 1.8x worse. The op was hand-given.
  • One week: OEIS stripped.gz (33.7 MB), 80/20 split, arms from Levin brute force up to library + conditioned prior + lineage selection, 2^20 programs per task per iteration. Pass: ≥1.5x brute force held out at equal enumeration, ≥30% of new solutions use a learned op. Kill: ≤1.1x, or near-zero reuse, which Berlot-Attwell et al. found in two library learners (arXiv 2410.20274[20]).
  • Exciting if: solves keep rising per iteration from base ops plus compute, with recognisable invented concepts. The bar: Gauthier and Urban found 27,987 sequences from scratch (arXiv 2202.11908[19]).

Idea 4. Symbolic HGM (27 / 27; selfmod/designs/hgm-clade-symbolic.md, kernel selfmod/designs/hgm-clade-kernel/). This answers "what do DGMs do without the LLM".

  • Agent = (solver program, meta-program that rewrites the child's solver and itself): Spector's autoconstruction in the Hyperagents shape.
  • Tasks: program synthesis, and sorting networks with a complete 0-1 verifier and known optimal sizes (19/25/29/35/39 comparators for n = 8-12).
  • Arms: greedy, DGM's rule, batched HGM, exact-CMP rollouts, evolvability; each with self-modifying and frozen meta; 30 seeds.
  • Measured pilot: 34,816 evaluations in 13 s; 59 of 64 roots tie on own score while CMP ranges 6-19 (Spearman 0.36). 10^6 evaluations: est. 6.3 min JS, 25-35 s native.
  • Exciting if: lineage credit beats own score over 30 seeds instead of one expensive run. Best role: the outer layer over idea 1's rule sets and idea 2's policies.

Idea 5. Prove once, mutate forever (25 / 25; selfmod/designs/typed-self-mod-gm.md). Mutators typed Expr<t> -> Expr<t> are checked once by Bend (0.27 s) and then only produce well-typed children. Measured: 2.2x useful children per unit of work at 8.5% acceptance; the gate took the good mutator and rejected three bad ones. Limits: Base has only the U32.add_comm law; @unsafe exits 0, so gate on the exact text "All terms check."; checker bug #1028 is open. Use it as a graft: the safe meta alphabet for idea 4 and a rule gate for idea 1.

Idea 6. Artificial-life soup (17 / 20; selfmod/designs/computational-life.md). Replicators emerged and Bend matched C bit for bit, but random-walk mutation finds bff replicators 10-25x more efficiently than the soup (arXiv 2607.01483[22]). Not a main line; harvest its evolved editors as meta operators for idea 4.

Two HVM-lane proposals, not designed yet:

  • SupGen proposes, the cube disposes. HVM4 enumerates small components with sharing; the cube scores explicit populations built from them over large input batches (bend2-hands-on.md §4).
  • Lemma synthesis. Missing U32 lemmas in Base stall proof-carrying self-edits. SupGen-style proof-term search gated by the Bend checker would make idea 5 learned (unverified; not probed).

6. Risks and unverified items

Risks:

  • Every "Bend enables it" claim is a JS measurement times an estimated native speedup until clang lands.
  • Toy DSLs may lack headroom: 59 of 64 HGM roots sat at the floor.
  • Testing is not proof for two-variable U32 rules; no z3 here and one U32 lemma in Base. Edge-value sets and exhaustive one-variable checks help.
  • Pruning and early exits break the balanced-fork contract.
  • Meta levels may stay degenerate, as with DGM-H's editable selection.
  • Hard limits force chunking: fork depth 31, counts of 2^24, and idea 1's packed key caps length at 7 as written.

Unverified:

  • All native BendRT and M4 Max speeds (est.).
  • HVM5's status and speed (search text only).
  • The canonicity-pruning factor; measuring it is idea 1's point.
  • How many OEIS sequences keep 32 terms in [0, 2^31) (est. tens of thousands).
  • Gumbel AlphaZero's sequential-halving details (search summary only).
  • Native soup speed: two estimates disagree 6x (about 140-150 vs 22-24 M steps/s sequential, designs/computational-life.md).
  • Whether the paid Bender agent ships SupGen (a stated promise, https://bend-lang.com/bender[14]).

7. Sources

Rendered from IDEAS.md (2026-09-27). Numbers in brackets link to the Sources list.