Skip to content

workflow.json

The experiment DAG. One per experiment, at research/<experiment id>/workflow.json.

{
  "name": "Kepler's Third Law from exoplanet data",
  "description": "Query the archive, fit the power law, test the exponent.",
  "created_at": "2026-08-20T00:00:00+00:00",
  "nodes": [ ... ],
  "edges": [ ... ]
}

Top level

Field Type Default Meaning
name string "" Descriptive name of the workflow.
description string "" Summary of the pipeline.
nodes array [] The nodes. At least one is required.
edges array [] The typed connections.
created_at string now ISO-8601 timestamp.

Node

Field Type Default Meaning
id string required Unique within the DAG.
name string the id Human-readable label.
kind string "algorithm" One of the agent kinds below. Unknown values raise.
purpose string "" Why this node exists.
ports object {} {"inputs": [...], "outputs": [...]}.
module string agents/<id>.py The implementing Python file, relative to the experiment directory.
tools array [] Tools this node will call. Checked by tool_use_verified.
params object {} Static parameters, read with self.param(name).
workflow string "" For kind: "composite": the nested workflow file.

Agent kinds

data · algorithm · training · evaluation · visualization · config · composite

Each maps to a primitive base class, and the class the agent file defines must match.

{
  "id": "analyze",
  "name": "Fit the power law",
  "kind": "algorithm",
  "purpose": "Fit T = C × a^α in log-log space to recover the Kepler exponent.",
  "ports": {
    "inputs":  [{ "name": "planets", "type": "json" }],
    "outputs": [{ "name": "fit_result", "type": "json", "description": "Exponent, r², diagnostics" }]
  },
  "tools": ["power_law_fit"],
  "params": { "min_points": 100 }
}

Port

Field Type Default Meaning
name string required Unique on this node.
type string "any" One of the port types below. Unknown values raise.
description string "" What the value carries.
required bool true If false, self.input() may return its default.

A bare string is shorthand for a port of type any:

"outputs": ["result"]

Port types

Type Carries
int, float, bool, str Scalars.
json Any JSON-able structure.
list A sequence.
dataframe A pandas.DataFrame. Spills to .parquet.
array A numpy.ndarray. Spills to .npy.
file A path to a file in the run's data/.
figure A rendered figure.
model A fitted model.
any Anything; compatible with everything.

Type compatibility

An edge is legal when the source type equals the target type, when either side is any, or when it is int → float. Nothing else, including float → int.

Edge

Field Type Meaning
source string Source node id.
source_port string Output port name on the source.
target string Target node id.
target_port string Input port name on the target.
{ "source": "analyze", "source_port": "fit_result",
  "target": "evaluate", "target_port": "fit_result" }

An input port accepts exactly one edge. An output port may feed many.

Rules validate enforces

  • At least one node; node ids unique.
  • Every edge endpoint and every named port exists.
  • Edge types compatible.
  • One edge per input port.
  • No cycles.
  • Every required input connected.
  • (warning) No orphan nodes; at least one evaluation node.

See validate a workflow.

A complete example

{
  "name": "Kepler's Third Law from exoplanet data",
  "description": "Query the NASA Exoplanet Archive for confirmed planets, fit the period–semi-major-axis power law in log-log space, and test whether the recovered exponent confirms T² ∝ a³.",
  "nodes": [
    {
      "id": "config",
      "name": "Experiment parameters",
      "kind": "config",
      "purpose": "Query filters and the theoretical Kepler exponent.",
      "ports": {
        "inputs": [],
        "outputs": [
          { "name": "settings", "type": "json", "description": "Query parameters and physical constants" }
        ]
      }
    },
    {
      "id": "fetch",
      "name": "Fetch exoplanet data",
      "kind": "data",
      "purpose": "Query NASA's Exoplanet Archive for confirmed planets.",
      "ports": {
        "inputs":  [{ "name": "settings", "type": "json" }],
        "outputs": [{ "name": "planets", "type": "json" }]
      },
      "tools": ["query_exoplanets"]
    },
    {
      "id": "analyze",
      "name": "Fit the power law",
      "kind": "algorithm",
      "ports": {
        "inputs":  [{ "name": "planets", "type": "json" }],
        "outputs": [{ "name": "fit_result", "type": "json" }]
      },
      "tools": ["power_law_fit"]
    },
    {
      "id": "evaluate",
      "name": "Test Kepler's Law",
      "kind": "evaluation",
      "ports": {
        "inputs": [
          { "name": "fit_result", "type": "json" },
          { "name": "settings", "type": "json" }
        ],
        "outputs": [
          { "name": "metric", "type": "str" },
          { "name": "value", "type": "float" },
          { "name": "detail", "type": "json", "required": false }
        ]
      }
    }
  ],
  "edges": [
    { "source": "config",  "source_port": "settings",   "target": "fetch",    "target_port": "settings" },
    { "source": "config",  "source_port": "settings",   "target": "evaluate", "target_port": "settings" },
    { "source": "fetch",   "source_port": "planets",    "target": "analyze",  "target_port": "planets" },
    { "source": "analyze", "source_port": "fit_result", "target": "evaluate", "target_port": "fit_result" }
  ]
}

See also