Adapters¶
An adapter converts one autoresearch system's on-disk checkpoint into Hutch's canonical event stream. Eleven ship in this release.
| Adapter | What it reads | Key event kinds emitted |
|---|---|---|
openevolve |
OpenEvolve checkpoint dirs (metadata.json + programs/<id>.json) |
individual, operator, fitness, descriptor |
aide |
AIDE search-tree journals (tree.json or journal.json) |
individual, operator, fitness, tree_expansion |
dgm |
DGM dgm_metadata.jsonl plus output_dgm/<agent_id>/ dirs |
individual, self_mod, fitness |
qdax |
QDax repertoire.json JSON exports |
individual, fitness, descriptor, archive_snapshot |
asi_arch |
ASI-ARCH MongoDB dumps (experiments.jsonl) |
individual, operator, fitness, review |
funsearch |
FunSearch programs.jsonl |
individual, operator, fitness |
coral |
CORAL multi-agent run dirs (iterations.jsonl, heartbeats, memory) |
individual, operator, fitness, steering_command, archive_snapshot |
poet |
POET generations.jsonl (coevolved env-agent pairs) |
individual (env + agent), operator, fitness, migration |
cvevolve |
CVEvolve session roots or history/search_history.sqlite databases |
individual, operator, fitness, stream_event |
ptychi_evolve |
ptychi-evolve rounds.jsonl (X-ray ptychography reconstruction search) |
individual, operator, fitness |
shinka_evolve |
ShinkaEvolve candidates.jsonl plus meta_mutations.jsonl |
individual (incl. skill for meta-mutations), operator (incl. meta_mutate), fitness |
For anything not in the table, use hutch import --llm. It reads a
file or directory of unknown records, asks an LLM to write a
to_canonical(record) function, validates the output in a constrained
subprocess, caches the working adapter, and emits canonical events. The
trust boundary is documented in security.md.
CLI¶
hutch import ./checkpoint # auto-detect format from the registry
hutch watch ./checkpoint # keep polling and update the dashboard live
hutch import --watch ./checkpoint # same live mode through the import command
hutch import ./checkpoint --format aide # force a specific adapter
hutch import ./cvevolve-run/history/search_history.sqlite --format cvevolve
hutch watch ./cvevolve-run --format cvevolve --include-audit
hutch import ./novel-format --llm # fall back to the LLM-assisted importer
Auto-detection runs each registered adapter's detect(path) in order
and picks the first match.
Writing a new adapter¶
Each adapter at hutch-py/src/hutch/adapters/<system>.py exposes:
def detect(path: Path) -> bool:
"""Cheap probe. Return True for paths this adapter can handle."""
def import_<system>(
path: str | Path,
*,
run_id: str | None = None,
project: str | None = None,
finalize: bool = True,
) -> Iterator[AnyEvent]:
"""Yield canonical events. Skip what you can't recover rather than
fabricating fields. When finalize=False, suppress run_end for watch mode."""
def is_complete(path: Path) -> bool | None:
"""Return True for explicit completion, False for still active, or None
when the format has no explicit terminal marker."""
Then add an entry to REGISTRY in
hutch-py/src/hutch/adapters/__init__.py:
Adapter(
name="myformat",
detect=myformat.detect,
importer=myformat.import_myformat,
is_complete=myformat.is_complete,
completion_policy="explicit", # or "idle"
),
A test under hutch-py/tests/test_adapter_<system>.py should:
- Generate a small synthetic fixture in a temp dir.
- Assert that event-kind counts match the fixture.
- Round-trip every emitted event through
EVENT_ADAPTER.validate_python()to catch schema drift. - Verify
detect()accepts the fixture and rejects an unrelated dir. - Verify
finalize=Falsesuppressesrun_endand registry-derived event IDs are stable across repeated imports.
Permissive by default¶
All adapters render gracefully on partial data. If the source format does not carry generation indices or descriptor dimensions, the adapter omits the optional fields rather than guessing. The dashboard's views tolerate holes in the data: the Phylogeny falls back to a chain when there are no crossovers, the Archive tab is hidden when there are no descriptors, and so on.
Per-adapter notes¶
OpenEvolve¶
Reads the published checkpoint format: a metadata.json listing islands
and feature maps, and one programs/<program_id>.json per individual.
OpenEvolve does not preserve the original mutation or crossover label,
so operators are emitted as kind="refine" (the safest canonical fit).
Cell-key strings like "(34, 71)" are parsed into descriptor
coordinates with a regex; if parsing fails, the cell-key string is
preserved as cell_id.
AIDE¶
AIDE's search-tree dumps are nested JSON. The adapter reads the journal
file directly and emits one IndividualEvent (kind="experiment_plan")
per node, plus a TreeExpansionEvent carrying visit counts and value
estimates. Buggy or non-runnable nodes get a FitnessEvent with
invalid_reason populated, so the dashboard counts the failure
honestly.
DGM¶
DGM keeps a JSONL log of agent generations and on-disk diffs of each
self-modification. The adapter pairs the parent and child agents into a
SelfModEvent carrying the overseer verdict and the
benchmark-score-before / benchmark-score-after pair. The Self-Mod Audit
view is the primary surface for these.
QDax¶
The adapter accepts a JSON export of a QDax Repertoire rather than a
live JAX object, so it can stay free of a JAX or NumPy dependency.
Two-line conversion from a live repertoire:
import json
json.dump({
"centroids": r.centroids.tolist(),
"fitnesses": r.fitnesses.tolist(),
"descriptors": r.descriptors.tolist(),
"metadata": {"descriptor_dims": [...], "objective_name": "fitness"},
}, open("repertoire.json", "w"))
The adapter emits one IndividualEvent plus FitnessEvent plus
DescriptorEvent per filled cell, plus one ArchiveSnapshotEvent per
run summarizing coverage, qd_score, and max_fitness.
ASI-ARCH¶
ASI-ARCH stores experiment records in MongoDB. The adapter reads the
natural mongoexport output: a JSONL file with one record per line, or
a single JSON file containing an array. Records carry an index (a
stable integer id) and a parent index (0 or null means root). The
agent role (researcher, engineer, or analyst) lands as the
envelope's stream_id, so the Operator-trace swimlane lays the events
out per role. The analyst's free-form analysis text becomes a
ReviewEvent.
FunSearch¶
A JSONL dump of one program record per line:
{id, code, score, parents, island_id, generation, evaluator}.
Mutation versus crossover is inferred from the length of the parents
array (1 means mutate, 2 or more means crossover). Island assignment
becomes the envelope's stream_id, so the Operator-trace swimlane lays
events out per island. The evaluator field becomes the canonical
evaluator_id, so the dashboard can filter per benchmark (cap-set,
online bin packing, etc.).
CORAL¶
Multi-agent runs map naturally onto Hutch's structural pieces:
- Agents become streams. Every CORAL agent (Researcher, Engineer,
Analyst, etc.) gets its own
stream_idswimlane. - Heartbeats become
steering_commandevents. CORAL's intervention mechanism mirrors directly onto Hutch's command vocabulary (pause_run,cancel_individual,inject_hint, etc.), so the Steering panel and audit trail surface them. - Shared memory becomes
archive_snapshotevents. Periodic snapshots of the cross-agent memory show up in the Archive view's coverage curve.
Format: iterations.jsonl, optionally accompanied by
heartbeats.jsonl and memory_snapshots.jsonl.
POET¶
Coevolution of environments and agents. Each generation records
environments, pairs (env-agent evaluations), and transfers
(agents moving between envs). The adapter emits each environment as an
IndividualEvent(kind="environment"), each agent as
IndividualEvent(kind="agent") (disjoint id spaces), the pair score as
a FitnessEvent with evaluator_id = env_id so the dashboard can
filter agent fitness per environment, and transfers as
MigrationEvent(trigger="poet_transfer"). Agents inherit
island_id = env_id, so the Phylogeny groups by environment.
CVEvolve¶
CVEvolve supports both one-shot import and live polling. The adapter
accepts either a session root containing history/search_history.sqlite
or a direct path to that SQLite file. Detection requires the expected
CVEvolve history tables (metric_definitions, rounds, candidates,
metrics, evaluation_metrics, and session_state), so unrelated
SQLite files are ignored. In watch mode, completion is explicit:
hutch watch <session> exits when session_state.phase = "completed".
Candidates become IndividualEvent(kind="program") records with code
referenced by file:// URI when the candidate artifact exists. Baseline
candidates are seeds; non-baseline CVEvolve actions become operators:
generate maps to propose, tune maps to refine, one-parent
evolve maps to mutate, and crossover strategy or multi-parent
evolve maps to crossover. Metrics and holdout-test metrics become
FitnessEvent records. CVEvolve minimize metric definitions are
declared as Hutch lower score directions and their composites are
negated, keeping the dashboard's higher-is-better aggregate convention.
Candidate failures are retained as stream_event audit rows. Message
and tool-call audit databases are intentionally left out of the default
adapter to avoid flooding the event store. Use --include-audit with
hutch import, hutch import --watch, or hutch watch to import
history/messages.sqlite and legacy history/tool_calls.sqlite as
cvevolve_message / cvevolve_tool_call stream events. The dashboard
shows those rows in the CVEvolve Audit tab when present. Audit event text
is capped by --audit-max-text-chars (default 8000; 0 disables
truncation).
When audit import is enabled the adapter declares the audit run
capability so the dashboard can show the CVEvolve Audit tab. Watch mode
declares live_updates; offline adapter imports do not declare
steering.
ptychi-evolve¶
A JSONL-per-round dump of an X-ray ptychography reconstruction search.
Each round contains a population of candidate reconstruction algorithms
with {nrmse, time_s} metrics. Both metrics are lower-better, so the
adapter sets the canonical composite to -nrmse to keep the
dashboard's higher-is-better axis pointing the right way.
ShinkaEvolve¶
Two JSONL files: candidates.jsonl (the program or prompt search) and
meta_mutations.jsonl (the search procedure itself, evolved via
meta_mutate). Meta-mutations land as IndividualEvent(kind="skill")
plus OperatorEvent(kind="meta_mutate"). That is the schema's intended
shape for "the procedure searching for the procedure."
Beyond this release¶
One additional system would be a natural fit, AlphaEvolve, but it
is closed-source with no public checkpoint format to target. Until that
changes, hutch import --llm covers the long tail.