minnesotanlp/meta-n

Code for Zae Myung Kim's paper titled "Meta^n: Recursive Self-Improvement through Emergent Depth"

28

stars

2

commits

Python

primary language

Aug 26, 2026

updated

README

Meta^n: Recursive Self-Improvement through Emergent Depth

arXiv tests Python 3.11 | 3.12 License: MIT

Code for the paper Meta^n: Recursive Self-Improvement through Emergent Depth (Zae Myung Kim, Young-Jun Lee, Seungyeon Jwa, Dongyeop Kang, 2026).

Most "self-improving" agent loops refine answers, not the process that produces them. Meta^n instead keeps a single universal meta-operation Ω fixed and recurses on its input: Ω reads execution traces from the layers below and writes executable code (a pre_process hook plus a code_library of utilities) that is injected into the layer beneath it, changing its behavior. Applied repeatedly, this produces a stack of self-improving agent layers whose roles emerge from context rather than being prescribed — meta-layers are constructive (they write code) rather than merely evaluative (accept/reject).

Meta^n at a glance: roles emerge at depth, and the recursive stack converges faster and generalizes better than baselines

How it works

Prior systems either hand-craft a single meta-improvement layer or make one layer edit itself; Meta^n instead stacks the same fixed meta-operation recursively, so depth is bounded by usefulness rather than by design:

Hand-crafted and self-referential one-layer meta-improvement vs recursive n-layer meta-improvement (ours)

The stack itself is:

  • Layer 0 — BaseExecutor: runs candidate scripts (locally or in a Docker sandbox) and captures a Trace (commands, errors, reasoning, success).
  • Layer 1 — default solver: an LLM agent that reads a task description and produces a solution (Layer1Solver, or the iterative AgenticSolver).
  • Layer 2+ — emergent: generated by Ω from execution traces of the layers below.

Search alternates two steps. In the build step (left), Ω reads the execution traces of the current stack and writes the code for a new meta-layer — helper functions, prompt directives, or rollbacks of a regressing change. In the run step (right), the nested stack Mₙ(…M₂(S₁)) executes on each task, with every layer's injected code applied around the base solver:

Build step: Ω constructs each successive meta-layer from traces (LawBench example, 0.767 to 0.833) Run step: the nested meta-layer stack executes on a task

(The chain shown is a real LawBench charge-prediction lineage from the paper: Ω injects a fuzzy label matcher, a later over-aggressive prompt change causes a regression, and the next layer rolls it back and standardizes on the verified helper — lifting the score from 0.767 to 0.833.)

ComponentRole
MetaLayerWraps an inner layer and applies injected code (pre_process, code_library)
TraceExecution record: commands, errors, reasoning, success/score
InjectedCodeOutput of Ω — a pre_process hook and a code_library dict
OmegaEngineCalls the LLM with the universal Ω prompt and parses the response into InjectedCode
ArchiveMonotonically growing collection of evaluated Candidate chains; tracks per-task best and supports weighted parent selection
EvolutionaryOrchestratorArchive-based evolutionary search loop — the only orchestrator
AgenticSolverTerminus-2-style iterative solver with two-stage completion confirmation

Run model: search is driven by the archive-based EvolutionaryOrchestrator (--max-iterations / --patience), so --use-archive is required. The bundled config meta_n/configs/benchmark_features.yaml is loaded by default and turns on the metacognition stack per benchmark; precedence is explicit CLI flag > per-benchmark block > defaults block > code default. --benchmark-config none reproduces bare behavior, and the single-draw best-of-N control is --use-archive --benchmark-config none --max-iterations 0.

Benchmarks

Nine benchmarks are supported via --benchmark:

--benchmarkWhatSizeScoring
co_benchCO-Bench combinatorial optimization (operations research)36 tasksper-instance objective → norm_score ~[0,1], averaged
symptom2diseaseSymptom2Disease medical diagnosis (English)22 classesexact-match accuracy
lawbench_chargeLawBench task 3-3 charge prediction (multi-label, Chinese)per-example F1, averaged
terminal_benchTerminalBench 2.0 terminal-agent tasks, via harbor~113 tasksbinary reward
swe_bench_verifiedSWE-bench Verified, real GitHub issues500 issues% resolved
alphaevolve_mathAlphaEvolve Math (OpenEvolve family)combined_score
symbolic_regressionSymbolic Regression (OpenEvolve)combined_score = -log10(mse + 1e-9)
algotuneAlgoTune (OpenEvolve)combined_score
arc_agi_2ARC-AGI-2 abstract reasoning120 eval taskspass@2

Benchmark datasets are not bundled in this repo — see data/README.md for how each is obtained (setup scripts for ARC-AGI-2 and the OpenEvolve trio, auto-download for the classification tasks and TerminalBench/SWE-bench, upstream release for CO-Bench). Default data dir is ./data/<benchmark>, overridable with --bench-data-dir.

Install

Python ≥ 3.11 (CI runs 3.11 and 3.12).

python -m venv .venv && source .venv/bin/activate
pip install -e .                                     # core
pip install -e ".[dev,bench,classify,openevolve]"    # + extras you need

Extras: dev (pytest), bench (co_bench solvers), classify (HF datasets), analysis (plots/embeddings), harbor (TerminalBench/SWE-bench), openevolve/openevolve-jax (OpenEvolve trio), terminus2/openhands (external agent SDKs — install against the committed locks under constraints/). The Docker CLI must be on PATH for the TerminalBench/SWE-bench paths.

API keys live in a .env at the repo root (OPENROUTER_API_KEY, or AZURE_OPENAI_API_KEY + AZURE_OPENAI_ENDPOINT for azure/ models); source .env before running.

External-agent base solvers (optional)

--base-solver {builtin,openhands,terminus2} selects the program that solves each task. The OpenHands / Terminus 2 SDKs live in a separate .venv_external_agents built by bash scripts/install_external_agents.sh (expects a terminal-bench checkout: git clone https://github.com/harbor-framework/terminal-bench baselines/terminal-bench); meta-n never imports them in-process — the backends spawn child-process runners (scripts/{oh,t2,oh_tb,builtin_tb}_runner.py) under that venv. External backends require --use-archive and --daily-budget-usd > 0, and add a cost guard, a bounded Docker-lease guard, and a JSONL telemetry ledger.

Quickstart

source .env

# CO-Bench on 10 tasks via OpenRouter (archive/evolutionary, default config)
meta-n --benchmark co_bench --bench-limit 10 --use-archive \
  --model anthropic/claude-sonnet-4-20250514 \
  --max-iterations 20 --output-dir ./experiments/run_x

# Any OpenAI-compatible endpoint (LM Studio / vLLM / Azure)
meta-n --benchmark co_bench --bench-limit 5 --use-archive \
  --base-url http://127.0.0.1:1234/v1 --model gemma-4-31b-it-mlx --api-key lm-studio

# External base solver (OpenHands on TerminalBench)
meta-n --benchmark terminal_bench --base-solver openhands \
  --use-archive --daily-budget-usd 200 --agent-max-budget 0.5 --max-docker 4

# Custom tasks (local executor, bare defaults)
meta-n --tasks examples/toy_tasks.json --use-archive --model <model> --base-url <url>

meta-n and python -m meta_n.main are equivalent entry points; see meta-n --help for the full argument list and scripts/run_agentic_stage*.sh / scripts/run_tb2_*.sh for full-scale invocation patterns.

Each run writes to experiments/<exp-name>/: config.json, summary.json (aggregate scores), convergence.json / oracle_convergence.json, checkpoint.json (resumable), archive/index.json, per-candidate traces/ + injected_code_d*.json, and llm_io/*.jsonl logs of every LLM call.

Status

Meta^n is a research prototype. Its demonstrable properties are a monotone archive that behaves as a ≥ best-of-N order statistic and a working code-injection channel (the code_library improves the solver when fed a correct helper). Empirical results are exploratory and should not be read as headline wins — see the paper for the full analysis.

Testing

pytest tests/ -m "not slow"      # what CI runs
pytest tests/external_agents/ -q # LLM-free external-agents gate (no SDK / Docker)

On-disk artifact shapes (summary.json, checkpoint.json, archive/index.json, telemetry rows) are byte-for-byte contracts pinned by tests/test_persistence_compat.py and tests/golden/ — do not change them casually. To add a benchmark, implement a BenchmarkAdapter under meta_n/integrations/ and wire it into meta_n/main.py.

Citation

@article{kim2026metan,
  title   = {Meta$^n$: Recursive Self-Improvement through Emergent Depth},
  author  = {Kim, Zae Myung and Lee, Young-Jun and Jwa, Seungyeon and Kang, Dongyeop},
  journal = {arXiv preprint arXiv:2608.24735},
  year    = {2026},
  url     = {https://arxiv.org/abs/2608.24735}
}

License

Released under the MIT License.

Contributors

zaemyung

2 commits

minnesotanlp/meta-n

Code for Zae Myung Kim's paper titled "Meta^n: Recursive Self-Improvement through Emergent Depth"

28

stars

2

commits

Python

primary language

Aug 26, 2026

updated

README

Meta^n: Recursive Self-Improvement through Emergent Depth

arXiv tests Python 3.11 | 3.12 License: MIT

Code for the paper Meta^n: Recursive Self-Improvement through Emergent Depth (Zae Myung Kim, Young-Jun Lee, Seungyeon Jwa, Dongyeop Kang, 2026).

Most "self-improving" agent loops refine answers, not the process that produces them. Meta^n instead keeps a single universal meta-operation Ω fixed and recurses on its input: Ω reads execution traces from the layers below and writes executable code (a pre_process hook plus a code_library of utilities) that is injected into the layer beneath it, changing its behavior. Applied repeatedly, this produces a stack of self-improving agent layers whose roles emerge from context rather than being prescribed — meta-layers are constructive (they write code) rather than merely evaluative (accept/reject).

Meta^n at a glance: roles emerge at depth, and the recursive stack converges faster and generalizes better than baselines

How it works

Prior systems either hand-craft a single meta-improvement layer or make one layer edit itself; Meta^n instead stacks the same fixed meta-operation recursively, so depth is bounded by usefulness rather than by design:

Hand-crafted and self-referential one-layer meta-improvement vs recursive n-layer meta-improvement (ours)

The stack itself is:

  • Layer 0 — BaseExecutor: runs candidate scripts (locally or in a Docker sandbox) and captures a Trace (commands, errors, reasoning, success).
  • Layer 1 — default solver: an LLM agent that reads a task description and produces a solution (Layer1Solver, or the iterative AgenticSolver).
  • Layer 2+ — emergent: generated by Ω from execution traces of the layers below.

Search alternates two steps. In the build step (left), Ω reads the execution traces of the current stack and writes the code for a new meta-layer — helper functions, prompt directives, or rollbacks of a regressing change. In the run step (right), the nested stack Mₙ(…M₂(S₁)) executes on each task, with every layer's injected code applied around the base solver:

Build step: Ω constructs each successive meta-layer from traces (LawBench example, 0.767 to 0.833) Run step: the nested meta-layer stack executes on a task

(The chain shown is a real LawBench charge-prediction lineage from the paper: Ω injects a fuzzy label matcher, a later over-aggressive prompt change causes a regression, and the next layer rolls it back and standardizes on the verified helper — lifting the score from 0.767 to 0.833.)

ComponentRole
MetaLayerWraps an inner layer and applies injected code (pre_process, code_library)
TraceExecution record: commands, errors, reasoning, success/score
InjectedCodeOutput of Ω — a pre_process hook and a code_library dict
OmegaEngineCalls the LLM with the universal Ω prompt and parses the response into InjectedCode
ArchiveMonotonically growing collection of evaluated Candidate chains; tracks per-task best and supports weighted parent selection
EvolutionaryOrchestratorArchive-based evolutionary search loop — the only orchestrator
AgenticSolverTerminus-2-style iterative solver with two-stage completion confirmation

Run model: search is driven by the archive-based EvolutionaryOrchestrator (--max-iterations / --patience), so --use-archive is required. The bundled config meta_n/configs/benchmark_features.yaml is loaded by default and turns on the metacognition stack per benchmark; precedence is explicit CLI flag > per-benchmark block > defaults block > code default. --benchmark-config none reproduces bare behavior, and the single-draw best-of-N control is --use-archive --benchmark-config none --max-iterations 0.

Benchmarks

Nine benchmarks are supported via --benchmark:

--benchmarkWhatSizeScoring
co_benchCO-Bench combinatorial optimization (operations research)36 tasksper-instance objective → norm_score ~[0,1], averaged
symptom2diseaseSymptom2Disease medical diagnosis (English)22 classesexact-match accuracy
lawbench_chargeLawBench task 3-3 charge prediction (multi-label, Chinese)per-example F1, averaged
terminal_benchTerminalBench 2.0 terminal-agent tasks, via harbor~113 tasksbinary reward
swe_bench_verifiedSWE-bench Verified, real GitHub issues500 issues% resolved
alphaevolve_mathAlphaEvolve Math (OpenEvolve family)combined_score
symbolic_regressionSymbolic Regression (OpenEvolve)combined_score = -log10(mse + 1e-9)
algotuneAlgoTune (OpenEvolve)combined_score
arc_agi_2ARC-AGI-2 abstract reasoning120 eval taskspass@2

Benchmark datasets are not bundled in this repo — see data/README.md for how each is obtained (setup scripts for ARC-AGI-2 and the OpenEvolve trio, auto-download for the classification tasks and TerminalBench/SWE-bench, upstream release for CO-Bench). Default data dir is ./data/<benchmark>, overridable with --bench-data-dir.

Install

Python ≥ 3.11 (CI runs 3.11 and 3.12).

python -m venv .venv && source .venv/bin/activate
pip install -e .                                     # core
pip install -e ".[dev,bench,classify,openevolve]"    # + extras you need

Extras: dev (pytest), bench (co_bench solvers), classify (HF datasets), analysis (plots/embeddings), harbor (TerminalBench/SWE-bench), openevolve/openevolve-jax (OpenEvolve trio), terminus2/openhands (external agent SDKs — install against the committed locks under constraints/). The Docker CLI must be on PATH for the TerminalBench/SWE-bench paths.

API keys live in a .env at the repo root (OPENROUTER_API_KEY, or AZURE_OPENAI_API_KEY + AZURE_OPENAI_ENDPOINT for azure/ models); source .env before running.

External-agent base solvers (optional)

--base-solver {builtin,openhands,terminus2} selects the program that solves each task. The OpenHands / Terminus 2 SDKs live in a separate .venv_external_agents built by bash scripts/install_external_agents.sh (expects a terminal-bench checkout: git clone https://github.com/harbor-framework/terminal-bench baselines/terminal-bench); meta-n never imports them in-process — the backends spawn child-process runners (scripts/{oh,t2,oh_tb,builtin_tb}_runner.py) under that venv. External backends require --use-archive and --daily-budget-usd > 0, and add a cost guard, a bounded Docker-lease guard, and a JSONL telemetry ledger.

Quickstart

source .env

# CO-Bench on 10 tasks via OpenRouter (archive/evolutionary, default config)
meta-n --benchmark co_bench --bench-limit 10 --use-archive \
  --model anthropic/claude-sonnet-4-20250514 \
  --max-iterations 20 --output-dir ./experiments/run_x

# Any OpenAI-compatible endpoint (LM Studio / vLLM / Azure)
meta-n --benchmark co_bench --bench-limit 5 --use-archive \
  --base-url http://127.0.0.1:1234/v1 --model gemma-4-31b-it-mlx --api-key lm-studio

# External base solver (OpenHands on TerminalBench)
meta-n --benchmark terminal_bench --base-solver openhands \
  --use-archive --daily-budget-usd 200 --agent-max-budget 0.5 --max-docker 4

# Custom tasks (local executor, bare defaults)
meta-n --tasks examples/toy_tasks.json --use-archive --model <model> --base-url <url>

meta-n and python -m meta_n.main are equivalent entry points; see meta-n --help for the full argument list and scripts/run_agentic_stage*.sh / scripts/run_tb2_*.sh for full-scale invocation patterns.

Each run writes to experiments/<exp-name>/: config.json, summary.json (aggregate scores), convergence.json / oracle_convergence.json, checkpoint.json (resumable), archive/index.json, per-candidate traces/ + injected_code_d*.json, and llm_io/*.jsonl logs of every LLM call.

Status

Meta^n is a research prototype. Its demonstrable properties are a monotone archive that behaves as a ≥ best-of-N order statistic and a working code-injection channel (the code_library improves the solver when fed a correct helper). Empirical results are exploratory and should not be read as headline wins — see the paper for the full analysis.

Testing

pytest tests/ -m "not slow"      # what CI runs
pytest tests/external_agents/ -q # LLM-free external-agents gate (no SDK / Docker)

On-disk artifact shapes (summary.json, checkpoint.json, archive/index.json, telemetry rows) are byte-for-byte contracts pinned by tests/test_persistence_compat.py and tests/golden/ — do not change them casually. To add a benchmark, implement a BenchmarkAdapter under meta_n/integrations/ and wire it into meta_n/main.py.

Citation

@article{kim2026metan,
  title   = {Meta$^n$: Recursive Self-Improvement through Emergent Depth},
  author  = {Kim, Zae Myung and Lee, Young-Jun and Jwa, Seungyeon and Kang, Dongyeop},
  journal = {arXiv preprint arXiv:2608.24735},
  year    = {2026},
  url     = {https://arxiv.org/abs/2608.24735}
}

License

Released under the MIT License.

Contributors

zaemyung

2 commits

Languages

Python

98.3%

Shell

1.6%