TOML configuration reference¶
ape/run.py runs a full evaluation from a TOML file:
python -m ape config.toml # resolve relative paths against the config's directory
python -m ape config.toml -r /project # resolve against /project instead
python -m ape config.toml -o /out # redirect output files into /out
(python -m ape.run also works, but emits a harmless RuntimeWarning.)
Everything is validated up front — unknown keys, missing required keys, bad
imports, out-of-range solver knobs — so a misconfigured run fails with a readable
ConfigError before the CLI dashboard starts.
You can print the fully-populated example below at any time with
python -m ape config-schema, or copy it to a file with
python -m ape config-schema -o config.toml.
Editing the config interactively¶
Rather than hand-editing the TOML, you can open a small local web UI with per-key documentation, live validation, and a save button:
python -m ape config-edit # edits ./config.toml (created on first save if missing)
python -m ape config-edit my/config.toml # edit a specific file
python -m ape config-edit -p 8765 # serve on a different port (default 8000)
python -m ape config-edit --no-browser # don't open a browser automatically
By default the editor opens http://localhost:8000 in your browser. Relative
paths are resolved and validated against the config file's directory; override
this with -r/--root.
The editor's save feature needs the optional config-editor extra (it
writes TOML, which the standard library cannot do):
Without it, browsing and validating still work, but saving reports an error asking you to install the extra.
Full config_reference.toml
# ============================================================================
# Maximal APE configuration — every section and key the loader understands.
# (Draft reference; to be revisited.)
#
# Run with: python -m ape config.toml (resolves paths against the
# directory containing this file)
# python -m ape config.toml -r /proj (resolve against /proj instead)
# python -m ape config.toml -o /out (redirect output files to /out)
# ============================================================================
# --- Input data --------------------------------------------------------------
[data]
path = "data.jsonl" # required; .csv or .jsonl, resolved vs project root
schema = "myproj.components.MyProblem" # required; dotted path to a DataModel subclass
start_id = "problem-0042" # optional; resume the input slice from this id
end_id = "problem-0100" # optional; stop after this id (inclusive)
# --- Instruction prompt ------------------------------------------------------
[prompt]
template = "prompts/instruction.md" # required; mustache template, {{ field }} from the data item
# --- Main LLM ----------------------------------------------------------------
[model]
provider = "langchain_google_genai.ChatGoogleGenerativeAI" # required; dotted path to a BaseChatModel class
name = "gemini-2.5-pro" # required; passed as model=<name> to the class
# Optional cheaper helper LLM, used to summarize long tool errors.
# Both keys must be set together, or both omitted (=> no helper, fall back to main LLM).
helper_provider = "langchain_google_genai.ChatGoogleGenerativeAI"
helper_name = "gemini-2.5-flash"
# --- Solution adapter --------------------------------------------------------
[adapter]
callable = "myproj.components.parse_solution" # required; the parsing FUNCTION itself, Callable[[str], SolutionT]
# --- Solver knobs ------------------------------------------------------------
[solver]
reformat_prompt = "That answer didn't parse. Reply with ONLY the final answer." # required, no default
tools = ["calculator", "lmfdb"] # optional; names of [tools.X] tables to bind to the LLM
# All optional; names match the SolverConfig fields:
user_system_prompt = "You are an expert algebraist. Be terse."
context_window_size = 256000 # int; None/omit => best-effort detection from the model
context_compaction_threshold = 0.8 # (0, 1]; occupancy ratio that triggers compaction
max_steps = 8 # >= 1; inferences allowed before force-finish
error_summarization_threshold = 500 # >= 0; tool-output errors at least this long get summarized
solution_adaption_attempts = 3 # >= 1; reformat retries before declaring PARSING_FAILED
rate_limit_backoff_seconds = [2, 4, 8, 16, 32] # all > 0; seconds to wait between provider rate-limit retries
# --- Checker -----------------------------------------------------------------
[checker]
callable = "myproj.components.MyChecker" # required; a Checker class or a zero-arg factory
expose_as_tool = true # optional; also expose the checker to the LLM as a tool
checker_tool = "myproj.components.make_checker_tool" # required iff expose_as_tool; tool factory
# Any extra keys here are forwarded as **kwargs to `callable` (and to `checker_tool`).
# --- Tool definitions --------------------------------------------------------
# Each [tools.X] is instantiated as callable(**remaining_keys). If the result is a
# ToolProvider, its get_tool() output is used (a single BaseTool, or a list — both
# are handled). Only tables listed in [solver] tools are actually loaded.
[tools.lmfdb]
callable = "ape.tools.LMFDB" # required; this is a ToolProvider -> yields a list of tools
pool_workers = 2 # extra keys => LMFDB(pool_workers=2, query_timeout=10)
query_timeout = 10
# --- Run parameters (fields of RunParams) ------------------------------------
[run]
save_file = "output/results.jsonl" # JSONL of OutputBatches; also used for resume
metadata_file = "output/metadata.json" # run metadata (incl. the pickled SolverConfig)
solver_workers = 4
checker_workers = 2
runs_per_data = 3 # solver sessions attempted per data item
load_save = true # on start, skip ids already completed in save_file
# --- CLI dashboard -----------------------------------------------------------
[cli]
enabled = true # default true; set false to run headless (no dashboard)
log_file = "output/run.log"
session_log_file = "output/sessions.log"
log_level = "INFO" # name or int
# --- Logging suppression -----------------------------------------------------
[logging]
suppress = ["httpx", "langchain_core", "urllib3"] # raise these loggers to WARNING
# --- User hooks --------------------------------------------------------------
# Optional callbacks invoked at well-defined points in the run. Each value is a
# dotted path to a Callable. Exceptions raised by hooks are logged and
# swallowed so a faulty hook cannot lose results or stop the run.
[hooks]
on_batch_saved = "myproj.components.on_batch_saved" # Callable[[OutputBatch], None];
# fires right after the built-in save handler
# persists each batch - use to mirror results
# to an external store, push a metric, etc.
Sections¶
[data]¶
| key | required | meaning |
|---|---|---|
path |
yes | input file (.csv or .jsonl), resolved against the project root |
schema |
yes | dotted path to a DataModel subclass |
start_id |
no | resume the input slice from this id |
end_id |
no | stop after this id (inclusive) |
[prompt]¶
| key | required | meaning |
|---|---|---|
template |
yes | path to the instruction-prompt template (mustache: {{ field }} from the data item) |
[model]¶
| key | required | meaning |
|---|---|---|
provider |
yes | dotted path to a BaseChatModel class |
name |
yes | model name; passed as model=<name> to the class |
helper_provider |
iff helper_name |
dotted path to a BaseChatModel class for the helper LLM |
helper_name |
iff helper_provider |
model name for the helper LLM; both helper_provider and helper_name must be set together or both omitted |
The optional helper LLM is used for secondary tasks such as context compaction and tool-error summarization. When omitted, the main LLM is used as a fallback.
[adapter]¶
| key | required | meaning |
|---|---|---|
callable |
yes | dotted path to the solution-adapter function itself (Callable[[str], SolutionT]) |
[solver]¶
| key | required | meaning |
|---|---|---|
reformat_prompt |
yes | prompt shown to the LLM when the adapter fails to parse its answer |
tools |
no | list of [tools.X] names to bind to the LLM |
user_system_prompt |
no | text appended to the framework's base system prompt, or a path to a file containing it (resolved against the project root) |
context_window_size |
no | int; omit ⇒ best-effort detection from the model |
context_compaction_threshold |
no | float in (0, 1]; occupancy ratio that triggers compaction |
max_steps |
no | ≥ 1; inferences allowed before force-finish |
error_summarization_threshold |
no | ≥ 0; tool-output errors at least this long get summarized |
solution_adaption_attempts |
no | ≥ 1; total parse attempts (1 on the original answer + up to N−1 after reformat prompts) before declaring PARSING_FAILED |
rate_limit_backoff_seconds |
no | list of positive ints; waits between provider rate-limit retries |
The optional knobs are the SolverConfig field names verbatim.
[checker]¶
| key | required | meaning |
|---|---|---|
callable |
yes | a Checker class or a zero-arg factory |
expose_as_tool |
no | also expose the checker to the LLM as a tool |
checker_tool |
iff expose_as_tool |
dotted path to a tool factory |
Any other keys are forwarded as **kwargs to callable (and to checker_tool)
and recorded in the run metadata. checker_tool is instantiated and resolved exactly
like a [tools.X] factory (may return a BaseTool, a list, or a ToolProvider).
[tools.X]¶
| key | required | meaning |
|---|---|---|
callable |
yes | dotted path; instantiated as callable(**remaining_keys) |
If the result is a ToolProvider, its get_tool() output is used (a single
BaseTool or a list — both are handled). Only tables named in [solver] tools
are actually loaded. Any other keys become constructor kwargs.
[run]¶
Accepts any field of RunParams:
| key | default | meaning |
|---|---|---|
save_file |
output/results.jsonl |
JSONL of OutputBatches; also used for resume |
metadata_file |
output/metadata.json |
run metadata (incl. the pickled SolverConfig) |
solver_workers |
1 |
number of solver workers |
checker_workers |
1 |
number of checker workers |
runs_per_data |
1 |
solver sessions attempted per data item |
load_save |
true |
on start, skip ids recorded as completed in metadata_file |
[cli]¶
| key | default | meaning |
|---|---|---|
enabled |
true |
set false to run headless (no dashboard) |
log_file |
output/run.log |
dashboard log file |
session_log_file |
output/sessions.log |
per-session transcript file |
log_level |
INFO |
logger level name or int |
[logging]¶
| key | required | meaning |
|---|---|---|
suppress |
no | list of logger names to raise to WARNING |
[hooks]¶
Optional callbacks invoked at well-defined points in the run. Each value is a dotted path to a callable. Exceptions raised by hooks are logged and swallowed so a faulty hook cannot lose results or stop the run.
| key | required | meaning |
|---|---|---|
on_batch_saved |
no | Callable[[OutputBatch], None]; fires right after each batch is persisted by the built-in save handler — use to mirror results to an external store, push a metric, etc. |