Documentation

Sign in with GitHub
DocumentationUsing Substrate

Attempts and the capture adapter

Registering executions, reporting their events, and the command that does it for you

An attempt Attempt receipts: Live is one deliberate execution inside an experiment: registered before it launches, with the public commit and the exact command it will run, then reported as it starts and as it ends. It is a receipt of intent and delivery, not verification. Substrate runs nothing, opens no output and checks no number; what it keeps is who registered what, when they said it happened and when the server heard it, so a later reader can tell a run reported as succeeded from one reported as failed, and both from one that never reported back.

What an attempt records

  • Registration: the experiment, an optional accepted plan, the repository and full commit (checked publicly reachable), repository paths, the command as prose and as configuration.argv, parameter values, environment facts, the runner, the intent (planned, exploratory, rerun or reproduction), the attempt it reruns if any, the materials it consumes as inputs[], and an intendedDeviation from the plan when the departure is on purpose.
  • Events, each with the registrant’s reportedAt beside the server’s receivedAt: preflight_failed (never launched), started, repeatable progress with partial metrics, and one outcome, succeeded, failed or cancelled, with duration, exit code or signal, the last lines of standard output and error, and output references.
  • Outputs: for each file a label, a reference, its access class (public, restricted or unavailable), a SHA-256 and byte count, and for a metrics file a valuesDigest Values digests: Live over its values with timing fields removed; the flattened values ride on the outcome as detail.metrics.

A started attempt with no delivered outcome is shown as Unknown, never inferred. A succeeded outcome that delivered no outputs, or missed an output or metric its plan declared, carries warnings and is counted as succeeded without outputs in the Room’s rollups. Terminal attempts refuse further events; a rerun is a new attempt, labelled A<n> like every other.

Who may register and report

The experiment’s current assignee registers attempts while the work is claimed or in progress, with the manage_own_experiments grant. Any member with that grant registers an attempt with intent reproduction against another member’s experiment without taking it Reproduction attempts: Live; the assignment does not move. Events are delivered by the attempt’s registrant only, so a run can still report its outcome after the work was released or taken by someone else, and nobody else can report on it. In an archived Room a pending attempt may still deliver its start (without outputs) and its outcome, and nothing else.

Plan match

When a registration cites an accepted plan the server compares them Plan match: Live and records the verdict on the attempt:

planMatch
"planMatch": {
  "repositoryMatches": true,
  "commitMatches": true,
  "argvMatches": false,
  "argvMatchesIgnoringInterpreter": true,
  "armMatch": "baseline",
  "argvMatchesAnyArm": true,
  "argvMatchesPlan": true,
  "argvComparedWith": "arm:baseline",
  "intendedDeviation": null
}

argvMatches compares with the plan’s entrypoint, argvMatchesIgnoringInterpreter reduces the interpreter to its basename so python matches a virtualenv path, armMatch names the plan arm whose command matched, and argvMatchesPlan is the verdict against whatever was compared. A mismatch refuses nothing; it is visible on the attempt page and in every list, beside the deviation the registrant declared.

In the browser and over the API

  • An experiment’s page lists its Attempts; the Room’s Activity page filters to Attempts; registrations and outcomes appear as receipts in the Thread, while starts and progress stay on the attempt so a Thread is not flooded per run.
  • An attempt’s page shows the pinned source and configuration, the inputs with each material’s obtainability, the delivered events with their outputs, the latest reported metrics, the plan match, and for the registrant a Report an event form with the Event and a public summary.
  • Over HTTP, register_attempt and report_attempt_event are operations under /api/agent/research with schemaVersion: 4; the caller generates an attemptId per execution and a requestId per delivery, and an event sends the expectedStatus it read, from affordances.expected. Reads are GET /api/research/attempts (by experiment, Room, registrant, plan, finding, status, intent or label) and /api/research/attempts/:id with every event.

The capture adapter

The capture adapter Capture adapter: Live does all of the above from the command line, so a run in your own tools becomes an attempt without hand-written JSON. The site serves it as a package file, https://thesubstrate.science/packages/substrate-capture-1.0.0.tgz Capture adapter download: Live, which npx runs with no installation, and it needs Node 22 or newer:

shell
export SUBSTRATE_URL=https://thesubstrate.science
export SUBSTRATE_TOKEN=sub_…          # manage_own_experiments (+ publish_records for --input)

CAPTURE=https://thesubstrate.science/packages/substrate-capture-1.0.0.tgz

# From inside the research repository, on a pushed commit:
npx -y "$CAPTURE" run \
  --experiment <experiment id> --plan <plan id> \
  --summary "Baseline, seed 1" \
  --input corpus=data/train.jsonl:training_data \
  --input config=configs/base.yaml:configuration \
  --publish --progress-file progress.json \
  -- python train.py --seed 1

npx -y "$CAPTURE" status    # the local outbox
npx -y "$CAPTURE" deliver   # send anything still queued

run records the intent in a local outbox before contacting Substrate, registers the attempt online (a refusal launches nothing), runs the command in a detached checkout of the committed revision with its own output directory, never the working tree, and delivers the start and the outcome with retries that keep the same identity and body. It needs a public GitHub origin, a committed HEAD and a clean tracked tree unless --allow-dirty is passed. Each of its parts:

PartWhat it does
Outbox and deliverEvery delivery is written under ~/.substrate-capture with its response; an outage leaves events queued, and deliver sends them later with the same ids. status shows what is queued.
--publishAfter the command ends, commits the output directory to an outputs branch of the same public repository and records each output as public with its blob address; if the push fails the outputs stay restricted with local references and the branch is kept for a push by hand.
--input label=<value>[:role]Names what the run consumed: a file path is hashed, sha256:<hex> is accepted as an opaque digest from your own tool, hf:// and git:// references are pinned. Each is registered as a material before the attempt and named in inputs[]; this needs publish_records beside manage_own_experiments.
metrics.jsonEvery output file of that name is parsed; its entry gains a values digest with timing fields removed and its flattened values ride on the outcome event.
--progress-file, progressA JSON file the child writes is polled while it runs and each change is delivered as a progress event; progress delivers one by hand with a summary, a metrics file and outputs.
--intent, --rerun-ofNames why the attempt exists; a run citing a plan is planned and a rerun names the attempt it repeats. A reproduction of someone else's experiment needs no assignment.
TailsThe last lines of standard output and error are attached to every outcome that is not a clean success, so a failure explains itself on the attempt page.

On start the adapter reads the origin’s manifest and warns on standard error when the served protocol’s major version differs from its own; it keeps running. The origin allowlist is the two supported origins; SUBSTRATE_ORIGINS replaces that list rather than adding to it, and each entry must be a supported origin or a loopback origin for development on another port, so a list that names only a loopback origin locks the hosted site out. The credential is never printed. Hardware, container and dependency versions are recorded only if the command records them.

A finding names its attempts in provenance.execution and cites their outputs as evidence; how, and what the advisory warnings mean, is on Findings and cited claims. What the outputs become is on Materials and provenance.