Skip to content

Introducing The Hutch — Observability, steering, and provenance for autonomous-research agents

v0.1.0, May 5, 2026

Today we're releasing The Hutch, an observability and steering dashboard for autonomous-research agents. Install:

pip install thehutch
hutch serve

…and any LLM-driven loop you have running becomes legible.

The problem

Autoresearch systems (AlphaEvolve, OpenEvolve, ShinkaEvolve, DGM, SICA, AIDE, ASI-ARCH, FunSearch, POET, MAP-Elites) are starting to matter. They are increasingly the way meaningful AI/ML research and software-engineering work gets done. They've already produced novel algorithms, architectures, and proofs.

The user-facing surface for them, though, is primitive. People stare at terminal logs. They open Notion docs. They cat metadata.json. There is no TensorBoard for the agent itself. There's no place to see "here are the experiments my agent ran, here is the lineage, here are the costs, and here are the points where I should intervene."

That's what Hutch is.

What it is

Hutch normalizes whatever your autoresearch system writes to disk into a canonical event stream, and renders that as a multi-tab dashboard. The schema collapses every loop in the literature, from a five-line hypothesis chain to a thousand-experiment ASI-ARCH run, into five concepts:

  • Individual. A candidate object: a program, a hypothesis, a proof state, an architecture, an agent codebase.
  • Operator. What produced this Individual from zero or more parents: mutate, crossover, refine, propose, self_modify, tree_expand, etc.
  • Fitness. A multi-metric scalar evaluation.
  • Lineage. The DAG of parent_ids.
  • Archive (optional). A quality-diversity grid, CVT, or AURORA latent space.

The dashboard renders ten views over those concepts: phylogeny (force, hierarchical, or radial), population trajectories, MAP-Elites heatmap, an Objectives view with four sub-modes (trade-off, best-so-far staircase, distribution, parallel coordinates), multi-stream operator-trace swimlanes, a self-modification audit log with diffs, MCTS-style tree search, an evidence graph (claim ↔ source with stance and confidence), an operator-cadence breakdown, and a steering panel for issuing write-back commands.

Each view degenerates gracefully on partial data. A linear research loop with no operators still gets a sensible Phylogeny (a vertical chain) and a sensible Population view (a single trajectory). A run with no descriptors hides the Archive tab rather than showing an empty grid. The only required event is run_start; everything else is opt-in.

Three ways in

You don't have to pick one:

  1. hutch import <path>. Ten built-in adapters cover OpenEvolve, AIDE, DGM, QDax, ASI-ARCH, FunSearch, CORAL, POET, ptychi-evolve, and ShinkaEvolve. For anything else, the LLM-assisted importer reads a file or directory of unknown records, samples them, prompts an LLM to write a to_canonical(record) adapter, validates the output in a constrained subprocess on a held-out sample, caches the working adapter, and emits canonical events. We've seen 100% schema-valid coverage on novel formats.

  2. SKILL.md. Drop the skill into your LLM agent's instruction surface (Claude Code, Cursor, custom GPT, and similar). The agent learns the canonical event vocabulary plus the steering protocol. It emits events as it works, and polls a queue for write-back commands between iterations.

  3. import hutch as h. The native Python SDK. h.log_individual, h.log_fitness, h.log_operator, with daemon and embedded transports.

The layers are a graduation path, not a fork. A user who only ever runs hutch import already gets the full dashboard.

Steering: the dashboard is a control surface

The dashboard isn't read-only. The Steering tab issues write-back commands; the agent obeys them between iterations.

from hutch import steering

@steering.handler("pause_run")
def on_pause(cmd):
    paused = True

@steering.handler("inject_hint")
def on_hint(cmd):
    state.next_hint = cmd.params["text"]

while running:
    steering.poll()      # drains, dispatches, and acks
    if paused: time.sleep(0.5); continue
    do_one_iteration()

approve_hitl is the synchronous gate: pause your loop until a human clicks Approve in the UI. Every issue and ack is mirrored as a steering_command event in DuckDB, so the audit trail survives a daemon restart.

What v0.1.0 is not

  • Not a multi-tenant cloud product. Localhost-first; remote dashboards are a thin extension via --host 0.0.0.0 plus HUTCH_TOKEN.
  • Not a new agent framework, LLM proxy, or trace viewer. Hutch rides on top of whatever you're already running. The optional [otel] extra emits canonical events as research.* OpenTelemetry spans alongside the primary transport; the canonical schema stays independent of OTel.

What's next

The post-v0.1.0 roadmap:

  • AlphaEvolve adapter if and when a public checkpoint format materializes. The LLM-assisted importer covers the long tail today; hand-tuning is for stability and per-system quirks.
  • OTel-subscribe path. Listen to gen_ai.* spans your existing instrumentation already emits (LangChain, LlamaIndex, OpenAI Agents SDK) and translate them into canonical events.
  • Datashader-style rendering for million-individual phylogenies.

The schema is additive-only between minor versions, so v0.1.x → v0.2.x will not break adapters or examples. Schema invariants are documented in the schema reference.

Try it

pip install thehutch
hutch serve &
hutch import ./your-checkpoint            # try a built-in adapter
hutch import ./your-novel-format --llm    # try the LLM-assisted importer

Or run any of the seven worked examples:

git clone https://github.com/xyin-anl/hutch
cd hutch
python examples/01-linear-research/run.py
python examples/02-openevolve-circle-packing/run_synthetic.py
python examples/03-aide-tree-search/run_synthetic.py
python examples/04-dgm-self-improvement/run_synthetic.py
python examples/05-map-elites-toy/run.py
python examples/06-evolutionary-operators/run.py
python examples/07-steering-demo/run.py

Issues and PRs welcome. Schema discussions especially welcome: we deliberately froze the v0.1.0 surface narrow so we can add what is genuinely missing rather than carry what isn't.