Skip to content

Scaffold Configs

GalapagosConfig is a typed dataclass whose sections are named after the six core componentspopulation, selection_policy, prompt_builder, proposer, evaluator, memory — plus top-level seed, run-level general, and EvoX's meta co-evolution loop. The Evaluator implementation is supplied by the task; the evaluator section is run-owned input for an evaluator that opts into receiving it. Section names match the component role keys used in build_components and _ROLE_BASES exactly.

One shared GalapagosConfig spans all twelve scaffolds: each section dataclass holds the union of every scaffold's fields, so a scaffold reads only the subset it needs. Per-scaffold defaults live in the bundled src/galapagos/scaffolds/<name>/config.yaml (loaded by from_config(name)); the dataclass carries the schema, types, and a generic fallback. Unknown sections/keys raise instead of silently falling back.

import galapagos as gx
cfg = gx.GalapagosConfig.from_config("openevolve")          # bundled defaults → typed config
cfg.population.num_islands                                   # 5  (typed, IDE-checked)
cfg = gx.GalapagosConfig.from_config("openevolve", population__num_islands=8)   # __ → .
cfg = gx.GalapagosConfig.from_config(path="my.yaml")        # local YAML, validated on load
cfg.to_yaml("effective.yaml")                               # dump the effective config

The list below is grouped by component; under each, the keys each scaffold uses. Format is config name: description (default value). A key whose value is routed to more than one component is listed under its YAML section with [shared → ...]. Bundled YAMLs need only list the keys a scaffold overrides — omitted keys take the dataclass default.

Run-level (orchestrator — not a component slot)

All scaffolds. Top-level seed feeds every SelectionPolicy's RNG; general is read by the base scaffold.

  • seed: RNG seed, threaded into every SelectionPolicy (0; the openevolve preset sets 42 — OpenEvolve's random_seed)
  • general.max_iterations: iteration budget (100; meta_harness defaults to 20 proposer rounds, with every candidate in a round evaluated before the counter advances; ale_agent uses 1000 to mirror the paper's reported approximate generation scale; algotune_agent uses 9999 as a safety cap and normally stops first at its upstream $1 model-spend limit)
  • general.checkpoint_interval: write a checkpoint every N iterations when run_dir is set (10)
  • general.eval_mode: where the task's evaluator.py runs — docker (the task's own image) or local (a host subprocess) (docker). The only thing that decides it: the task card has no say, and no environment variable is read, so a run is reproducible from its config alone. There is no --eval-mode flag; set it like any other config value (--general.eval_mode local)
  • general.language: candidate language override; otherwise inferred from the seed program (null)
  • general.solution_file_suffix: suffix for candidate files handed to the Evaluator (.py)
  • general.max_solution_length: reject candidates longer than this many characters (60000; the openevolve preset sets 10000 — OpenEvolve's max_code_length; algotune_agent sets 1000000 because its multi-file workspace is packed into one Genome)
  • general.mutation_approach: how the LLM mutates — diff_based_edit (SEARCH/REPLACE edits) or full_rewrite (a whole new program), or any name registered with @register_mutation_approach (a custom MutationApproach). Resolved to an object that supplies the prompt instruction (add_prompt) and the response→code parser; applies to every LLMProposer-based scaffold. An unknown name is rejected at run start (diff_based_edit)

Inner retry (per-iteration resampling)

These general.* keys control how many times an iteration resamples the proposer (parent held fixed) on a no-diff / too-long / invalid result before moving on.

  • general.inner_retry_times: max propose+evaluate attempts per iteration; 1 = no retry, the original behaviour (1; the adaevolve, beam_search, best_of_n, best_of_n_attempts, evox, openevolve and topk presets set 3, SkyDiscover's retry_times)
  • general.inner_retry_feedback: inject the prior failed attempts (error + failed code/response + traceback, SkyDiscover-style) into each retry's prompt so the model avoids repeating them (true)
  • general.inner_retry_solution_chars: cap on the failed solution/response shown in that feedback; set above max_solution_length so normal failures show in full, ceiling only guards pathological output (80000; the beam_search/evox presets set 1500, the SkyDiscover default)
  • general.inner_retry_traceback_chars: cap on the (tail of the) traceback shown in that feedback (1000; the beam_search/evox presets set 800, the SkyDiscover default)

Recoverable proposal failures

IterationGuard is always active for model/proposer execution failures. A None proposal immediately fails the current iteration; an empty/no-diff proposal follows general.inner_retry_times; and an LLM exception becomes a failed iteration after the model client's own transient-request retries. Failed iterations consume their budget slot and there is no consecutive-failure circuit breaker.

The guard intentionally does not catch selection, evaluator, population, setup, checkpoint, or finalization exceptions, nor KeyboardInterrupt/SystemExit. Those failures mean the search state or scoring contract may be unreliable, so the run remains fail-fast.

1. Population — the candidate store

adaevolve (AdaEvolveArchipelago)

  • population.num_islands: initial island count (2) [shared → SelectionPolicy]
  • population.population_size: programs per island archive (20)
  • population.k_neighbors: k for k-NN code-distance novelty (5)
  • population.archive_elite_ratio: fraction protected from eviction (0.2)
  • population.fitness_weight: elite-score fitness-percentile weight (1.0)
  • population.novelty_weight: elite-score novelty-percentile weight (0.0)
  • population.pareto_weight: folded into the elite score's fitness term — w_fit = fitness_weight + pareto_weight — so it is live, and raising it tilts the elite score toward fitness and away from novelty (0.4)
  • population.migration_count: top programs sent to (k+1) mod K (5)

openevolve (MapElitesIslandsPopulation)

  • population.num_islands: island count (5) [shared → SelectionPolicy]
  • population.archive_size: global elite-archive size (100)
  • population.population_size: total population cap (1000)
  • population.feature_dimensions: MAP-Elites axes ([complexity, diversity]) [shared → SelectionPolicy, PromptBuilder]
  • population.feature_bins: bins per feature axis (10)
  • population.migration_interval: migrate every N island generations (50)
  • population.migration_rate: fraction of each island migrated to ring neighbours (0.1)
  • population.diversity_reference_size: sample size for diversity computation (20)

evox (EvoXPopulation)

  • population.improvement_threshold: stagnation-reset gain τ (0.01)
  • population.statistics_k: top-k scores in the φ descriptor (20)

topk (TopKPopulation) / best_of_n + best_of_n_attempts (BestOfNPopulation, keep-all, shared)

  • population.capacity: keep-all archive cap; null = uncapped (the default, matching SkyDiscover), an int bounds it (null)

beam_search (BeamPopulation)

  • population.beam_width: candidates kept in the beam (5)
  • population.beam_diversity_weight: diversity-term weight, 0 = pure fitness (0.3) [shared → SelectionPolicy]
  • population.beam_depth_penalty: exponential fitness penalty per search-tree depth, 0 = off (0.0)

meta_harness (MetaHarnessPopulation)

  • population.cost_metric: optional Pareto cost axis to minimize. null keeps scalar combined_score search; set a metric emitted by every valid evaluation to enable Pareto mode, or set genome_chars explicitly when source length is the intended cost (null)

2. SelectionPolicy — the active, stateful policy

adaevolve (AdaEvolvePolicy)

  • selection_policy.decay: EMA factor ρ for G, UCB rewards, decayed visits (0.9)
  • selection_policy.intensity_min: exploration-probability floor (0.15)
  • selection_policy.intensity_max: exploration-probability ceiling (0.5)
  • selection_policy.fixed_intensity: intensity used when use_adaptive_search is false (0.4)
  • selection_policy.use_adaptive_search: G-based intensity vs fixed (true)
  • selection_policy.use_ucb_selection: UCB island routing vs round-robin (true)
  • selection_policy.use_migration: ring migration on/off (true)
  • selection_policy.use_dynamic_islands: spawn islands on global stagnation (true)
  • selection_policy.migration_interval: migrate every N iterations (15)
  • selection_policy.max_islands: island cap for dynamic spawning (5)
  • selection_policy.spawn_productivity_threshold: spawn when improvements/evaluations < this (0.015)
  • selection_policy.spawn_cooldown_iterations: min iterations between spawns (30)
  • selection_policy.local_context_program_ratio: local share of inspirations (0.6)
  • selection_policy.num_inspirations: inspirations per prompt (4)

openevolve (OpenEvolveSelectionPolicy)

  • selection_policy.exploration_ratio: P(uniform-random parent from current island) (0.2)
  • selection_policy.exploitation_ratio: P(fitness-weighted parent from the archive) (0.7)
  • selection_policy.elite_selection_ratio: top fraction of island used as inspirations (0.1)
  • selection_policy.num_inspirations: top programs as inspirations (3) [shared → PromptBuilder as num_top_programs]
  • selection_policy.num_diverse: diverse programs as inspirations (2) [shared → PromptBuilder]

evox (EvoXPolicy)

  • selection_policy.num_context_programs: inspirations from the active strategy's sample() each iteration (4)

topk (TopKPolicy)

  • selection_policy.num_inspirations: programs at ranks 2..K+1 used as context, K (4)

ale_agent (ALEAgentSelectionPolicy)

  • selection_policy.ale_children_per_parent: sibling branches generated from each best-first parent (30)
  • selection_policy.ale_refinement_turns: evaluated implementation turns per branch before its best version returns to the frontier (3)

best_of_n (BestOfNPolicy)

  • selection_policy.best_of_n: reuse the same parent until N valid children have been produced from it, then commit to the global best and repeat; failed (parse/invalid) attempts are free retries that do not spend the budget (5)
  • selection_policy.num_inspirations: context programs sampled from the top pool (4)

best_of_n_attempts (BestOfNAttemptsPolicy)

  • reuses the same selection_policy.best_of_n / selection_policy.num_inspirations keys as best_of_n, but counts every attempt (valid or not), rotating the parent every N iterations on a fixed cadence

beam_search (BeamSelectionPolicy)

  • selection_policy.beam_selection_strategy: best | stochastic | round_robin | diversity_weighted (diversity_weighted)
  • selection_policy.beam_temperature: softmax temperature for stochastic / diversity_weighted (1.0)
  • selection_policy.num_inspirations: global top programs used as context (4)

3. PromptBuilder — the renderer

Most scaffolds' PromptBuilders take no config (fixed templates). openevolve (OpenEvolvePromptBuilder) has no own keys — it reuses selection_policy.num_inspirations (as num_top_programs), selection_policy.num_diverse, and population.feature_dimensions.

ale_agent (ALEAgentPromptBuilder)

  • prompt_builder.ale_domain_guidance: sample one of the four published algorithm-engineering strategy prompts for each sibling branch (true)
  • prompt_builder.ale_include_history: add the rolling search-trajectory summary; false in the full Method 1&2 configuration to preserve sibling diversity (false)

meta_harness (MetaHarnessPromptBuilder)

  • prompt_builder.skill: serialized-view steering used by proposer.mode=llm, and the backward-compatible fallback when coding_agent_skill is null; accepts a galapagos.skills id (e.g. meta_harness/text_classification), a path to a SKILL.md directory, or none to disable steering. The bundled default is meta_harness/text_classification; the alternate is meta_harness/terminal_bench_2.
  • prompt_builder.coding_agent_skill: primary filesystem-native skill used by mode=coding_agent. The bundled default is meta_harness/text_classification_filesystem; use meta_harness/terminal_bench_2_filesystem for the depth regime. null falls back to prompt_builder.skill for custom/backward-compatible configurations.
  • prompt_builder.top_k_sources: full sources of this many frontier members in the prompt (3)
  • prompt_builder.reports_in_prompt: most recent ≤30-line candidate reports replayed (6)
  • prompt_builder.trace_errors: execution-trace excerpts sampled errors-first (2)
  • prompt_builder.trace_successes: then success excerpts sampled (1)
  • prompt_builder.trace_max_chars: clip per trace excerpt (1500)
  • prompt_builder.summary_max_rows: evolution-summary rows rendered into the prompt (200)
  • (also reuses proposer.candidates_per_proposal)

4. Proposer — the variation operator

Every scaffold's proposer section can carry the shared model keys, consumed by build_model when that scaffold or mode builds an API LLM (see Models): model selection (model_name, model_path, api_key, api_base, optional models weighted-ensemble list), generation (temperature 0.7, top_p 1.0, max_tokens 30000, reasoning_effort null), and request handling (timeout 600, retries 3, retry_delay 5). API proposers can additionally set Tavily tool controls (tool_call_on false, max_tool_rounds 3, max_tool_output_chars null, and nested tavily_tool transport/search/filter/response options); see Models — Tavily web search. Preset overrides: topk / best_of_n / best_of_n_attempts set max_tokens 32000; openevolve sets top_p 0.95, max_tokens 4096, timeout 60; algotune_agent sets temperature 0 and reasoning_effort high. claude_code, codex, and Meta-Harness's default coding_agent mode use a CLI agent instead of build_model; Meta-Harness uses these model fields only in proposer.mode=llm. Only meta_harness adds a loop-shaping key.

meta_harness (MetaHarnessProposer)

  • proposer.mode: what the proposer is — coding_agent (a headless coding agent browses the on-disk archive D, reference-faithful) or llm (one API model call over a serialized view of D) (coding_agent)
  • proposer.coding_agent: which headless agent when mode=coding_agentclaude_code / codex / cursor_agent (claude_code)
  • proposer.candidates_per_proposal: candidate programs emitted per proposal, k (3) [shared → SelectionPolicy, PromptBuilder]

claude_code (the scaffold shells out to the Claude Code CLI — no GalapagosModel is built; general.max_iterations is the prompt-level turn budget)

  • proposer.claude_model: the CLI's --model (claude-*/sonnet/opus/haiku); null = CLI default (null)
  • proposer.claude_cli_max_turns: the CLI's --max-turns safety cap; null = 2× general.max_iterations (null)
  • proposer.claude_wall_timeout_seconds: whole-session wall timeout; null = derived from the CLI cap/evaluator (null)
  • proposer.reasoning_effort: the CLI's --effort (high)

The rest apply to a docker-mode task — the default — where the Claude Code session runs inside the task's own container image. The Meta-Harness CLI also reuses these keys when its default coding_agent=claude_code controller/proposer/evaluator loop is orchestrated in that container (a local-mode run uses host processes instead):

  • proposer.claude_docker_image: null = the task's own image, resolved from its card (the Claude Code CLI is layered onto it on first use); set it to override the task image wholesale (null)
  • proposer.claude_docker_cli_version: pin the installed CLI version (npm i -g @anthropic-ai/claude-code@X); null = latest (null)
  • proposer.claude_docker_memory / claude_docker_cpus / claude_docker_network: docker run resource/network caps (null = unbounded / Docker's default)

codex (the scaffold shells out to one codex exec --json session; no GalapagosModel is built, and general.max_iterations is the improvement budget written into TASK.md)

  • proposer.codex_model: the CLI's --model; provider prefixes are stripped (gpt-5.6-sol)
  • proposer.codex_cli_max_steps: completed actionable JSONL-item safety cap; null = 2× general.max_iterations (null)
  • proposer.codex_wall_timeout_seconds: whole-session wall timeout; null = derived from the action and evaluator caps (null)
  • proposer.reasoning_effort: Codex reasoning effort (max; accepted values are model/CLI-version dependent)
  • proposer.reasoning_summary: auto, concise, detailed, none, or null for the CLI default (auto)
  • proposer.codex_web_search: disabled, cached, indexed, or live (disabled)
  • proposer.codex_docker_image: null = the task's image; set it to override the task image wholesale (null)
  • proposer.codex_docker_cli_version: pin the installed @openai/codex version; null = latest (null)
  • proposer.codex_docker_memory / codex_docker_cpus / codex_docker_network: docker run resource/network caps (null = unbounded / the task or Docker default)

There is no verifier-topology knob for either single-agent scaffold: the agent and the framework's trusted scorer share a single container — the scorer execs in, the agent is non-root, /eval is root-owned and unwritable. See Task environments for how that image and its /workspace + /eval layout are built.

Meta-Harness additionally requires a run directory (galapagos run ... --output-dir DIR, or run_dir=... in Python), persists archive D under <run_dir>/meta_harness_D, and deliberately does not support --resume / resume_from.

OpenEvolve's upstream diff_based_evolution and max_code_length map to run-level keys — general.mutation_approach (diff_based_edit | full_rewrite) and general.max_solution_length (the openevolve preset sets 10000). allow_full_rewrite is not exposed: in diff mode the OpenEvolveProposer applies whole-line SEARCH/REPLACE with no full-rewrite fallback — a response with no valid diff block is a no-op, as the reference discards it.

5. Evaluator — the task-owned scorer

The Evaluator source is supplied by the task, not the scaffold: task.evaluator runs the task's evaluator.py inside the task's own container image via a ContainerEvaluator (the default), or in a host subprocess via a SubprocessEvaluator. Both select the same evaluator source; dependencies, hardware, isolation, and timing can differ.

The run-owned evaluator section carries optional LLM-judge request settings. Existing evaluate(program_path) functions ignore it automatically. A task explicitly opts in with evaluate(program_path, *, evaluator_config), which receives the effective section as a plain dict; the same contract applies to evaluate_stageN and evaluate_final.

  • evaluator.model_name: user-facing judge model name (null)
  • evaluator.model_path: provider model id; task code may fall back to model_name (null)
  • evaluator.api_base: provider name or explicit API base URL (null)
  • evaluator.api_key_env: name of the API-key environment variable to forward; secret values never enter the config (null)
  • evaluator.temperature: judge sampling temperature (0.0)
  • evaluator.top_p: nucleus-sampling cutoff (1.0)
  • evaluator.max_tokens: maximum judge response tokens (4096)
  • evaluator.reasoning_effort: provider-specific reasoning effort (null)
  • evaluator.responses_api: optional Responses-vs-Chat API selection (null)
  • evaluator.seed: provider-side sampling seed when supported (null)
  • evaluator.timeout: per-LLM-request timeout, distinct from the task evaluator process timeout (120)
  • evaluator.retries / evaluator.retry_delay: LLM request attempt count and delay (3 / 5.0)
  • evaluator.request_params: provider-specific JSON parameters ({})
evaluator:
  model_name: openai/gpt-5-mini
  api_base: openrouter
  api_key_env: OPENROUTER_API_KEY
  temperature: 0.0
  max_tokens: 2048

Where is a run-level choice and it lives in general.eval_mode (docker — the default — or local; aliases container/sandbox and subprocess): set it like any other config value — galapagos run --general.eval_mode local — or from code with GalapagosTask.set_eval_mode(). It is the only input — the card gets no say, and neither does the environment — so a run is reproducible from its config alone.

6. Memory — the cross-cutting knowledge store

AdaEvolve and ALE-Agent tune Memory via config; the other scaffolds' Memory takes no keys.

adaevolve (AdaEvolveParadigmMemory)

  • memory.use_paradigm_breakthrough: paradigm-breakthrough on/off (true)
  • memory.paradigm_window_size: binary global-improvement window (10)
  • memory.paradigm_improvement_threshold: rate < this (full window, no active paradigm) → generate (0.12)
  • memory.paradigm_max_uses: uses per paradigm before rotation (2)
  • memory.paradigm_num_to_generate: ideas per generator call (3)
  • memory.paradigm_max_tried: bounded history of tried paradigms (10)

ale_agent (ALEAgentMemory)

  • memory.ale_history_size: rolling branch/turn outcome summaries retained for Base and Method 1 prompts (12)

Meta loop — EvoX co-evolution (not one of the 6 component slots)

EvoX evolves its SelectionPolicy/Proposer as code. These meta.* keys are consumed by the EvoXScaffold orchestrator (__init__/setup), not a single component.

  • meta.switch_interval: strategy-switch period W; null → auto = max(1, max_iterations × 0.10) (null)
  • meta.meta_num_context_programs: strategy inspirations sampled from H per generation event (2)
  • meta.meta_max_retries: meta-generation attempts per event, with failure feedback (3)
  • meta.auto_generate_variation_operators: false → static DIVERGE/REFINE templates, no LLM (true)
  • meta.use_llm_stats_insight: false → raw population-state text in the meta prompt (true)
  • meta.use_problem_summary: problem-context summary guide call, cached per problem (true)
  • meta.use_batch_summaries: batched [PROGRAM N] summaries of prior strategies (true)
  • meta.max_strategy_chars: generated-strategy length cap (60000)