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:
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
evaluationnode.
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" }
]
}