Domain model
Autoresearch adds no database tables. Every concept in the domain model is a page in the
research/ directory, typed through metadata.research.type the same way any other
page metadata typing works, and the research/ namespace
is version-captured so you can see how a goal or hypothesis read at any point in the past.
The research/ pages
Section titled “The research/ pages”| Type | metadata.research.type |
Carries |
|---|---|---|
| Goal | goal |
{metric: {name, direction, evalSet?}, budget?}, plus the MLOps workspace bindings (metadata.fs.path / metadata.mlops.launcher) live on the same page |
| Hypothesis | hypothesis |
{status: proposed | accepted | testing | supported | refuted | parked, goals: [refs], evidence: [observation page ids]} |
| Observation | observation |
{run, hypothesis, direction: supports | contradicts | neutral, strength, author: agent | human | merged, parents?} |
| Experiment | experiment |
Free-form experiment notes/design, linked from hypotheses and runs |
| Concept | concept |
Literature-triage output: a distilled idea linked source ↔ concept ↔ hypothesis |
| Profile | profile |
The shared system card described below |
A hypothesis is multi-goal by design: its goals field is an array of page refs, so one
hypothesis can be evidence-tracked against several goals at once rather than being forked
per goal. An observation always names both the run it came from and the hypothesis it
speaks to, plus a direction (supports, contradicts, or neutral), a strength, and an
author that is agent, human, or merged, the three-way split the blind-first review
flow in research loops produces.
Runs stay mlops-core’s page type
Section titled “Runs stay mlops-core’s page type”A completed run is never a second, research-flavored page type. It is the exact same
mlops/run page MLOps already materializes from whichever tracker
produced it, decorated with a metadata.research {goal, hypothesis, proposal} lineage
stamp once the scheduler launches it (see lineage records below). This
one-page-two-namespaces design means a run page you’re looking at from the MLOps dashboard
and a run page an observation links to are literally the same row: there is nothing to keep
in sync, because there is only ever one page.
The per-goal backlog
Section titled “The per-goal backlog”Confirming a heartbeat-drafted run proposal (a task-queue Confirm, see
research loops) promotes it into that goal’s backlog page,
auto-created in research/ as <goal> - backlog. The backlog is an ordinary outliner page:
each queued run spec lives as one bullet carrying its structured spec in props, and bullet
order is priority. Drag a bullet up to move it earlier in the drain order, exactly the
outliner gesture you’d use to reorder anything else. The research.scheduler loop reads
this page top to bottom every time it runs; see research loops for
how it drains entries against a launcher’s live capacity and a goal’s budget.
Profile pages (the model card)
Section titled “Profile pages (the model card)”A goal references a shared research/profile page through metadata.research.profile.
The profile exists because ingest triage and the heartbeat can’t judge whether a paper’s
architecture trick or training recipe actually applies to your project without knowing what
you actually run, and a hand-maintained description goes stale the moment a hyperparameter
changes. The profile solves this by being run-config-derived: every ingested run
normalizes its config (ignoring configured ephemeral keys like timestamps or random seeds)
and updates the profile’s machine-derived subtree before the observer even looks at the run.
- Runs off a main or release git ref replace or fold into the profile’s baseline.
- Off-main configs cluster by a stable config signature, branch name is provenance, not identity, retain a bounded set of run/git-ref stamps, and expire once they go runless or end up tied to a refuted or parked hypothesis.
- A config that stabilizes and lands on main disappears as its own cluster once the matching recipe becomes the baseline.
- The profile’s human-authored root nodes (intent, constraints) are never touched by this machinery, only the derived subtree updates automatically.
A baseline signature change emits a research-profile-drift event through trusted
triage into the profile’s inbox, so a meaningful shift in what
“the current recipe” means surfaces to you rather than silently rewriting history. Goals
that opt in automatically pin their profile in triage.context, and both the heartbeat’s
gather step and literature triage read the same live profile body as context.
Lineage records
Section titled “Lineage records”{goal, hypothesis, proposal} is the lineage triple the scheduler stamps onto
metadata.research of every run page it launches: which goal the run serves, which
hypothesis it’s meant to move evidence on, and which backlog proposal produced it. Combined
with the coding lane’s dispatch hints (a launched task carries a hypothesis [[ref]]), the
full chain goal → hypothesis → task/proposal → run → observation is traversable as
ordinary page links, click through from a hypothesis to every run that tested it, or from a
run back to the goal it served, with no separate lineage database to query.
See research loops for the workflows that create, drain, and consume these pages, and MLOps overview for the tracker/launcher layer the run pages themselves come from.