config.yaml schema
The fixed schema every block's config.yaml follows
Every block in the tree — root or subblock — has a config.yaml with the same top-level shape. Live state is not stored here; that lives in artifacts/index.yaml. The schema is machine-enforced by scripts/validate_config.py (run by every block's dryrun.sh, the CI schema tests, and the :check skills).
Top-level structure
meta_info:
name: # short identifier; must equal the block's directory name
label: # human-friendly title
description: # one-sentence purpose
parent: # parent block's `name`, or null for the root
subblocks: # parent blocks only: children with a role one-liner — NO wiring
<child_name>: {role: "<one phrase>"}
dependencies: # this block's OWN upstream hand-offs — see "Wiring rule"
<input.dot.path>: <source_block>.output.<key>
repos: {} # name → {commit_id, role}; pinned vendored deps under repos/
resources:
ip: # 'local' (default) or null = current host; remote IP = SSH+tmux
directory: # working directory on the remote node (when ip is remote)
runtime_info:
input: {} # ONLY values originating outside the block tree
output: {} # values produced for downstream blocksThese are the only two top-level sections. Legacy status: and evolving: sections and a top-level environment: are validation failures (schema:legacy-status, schema:legacy-evolving, schema:unknown-toplevel); per-run env vars live in runtime_info.input.env_extra.
Wiring rule
This is the rule the whole pipeline depends on:
Each consumer block declares its upstream hand-offs in its own flat
meta_info.dependencies. The key is a dot-path into that block'sruntime_info.inputnaming the input that receives the value; the value references the producer's output. A block with no upstream declares an explicitdependencies: {}. The root'ssubblocksentries carry roles only — never wiring.
Two value forms:
# string form — required dependency
task_source.dataset_name: curator.output.swe_tasks_dir
# mapping form — conditional and/or optional
source.job_dir:
from: tracer.output.raw_trajectories_dir
when: {source.type: harbor_job} # enforced only while these inputs hold these values
required: false # null producer output → warning, not failureResolution reads the producer's runtime_info.output.<key>: a non-null value first, else path. A dangling reference (missing producer block or output key) always fails validation, even when the dependency is inactive or optional. The validator also warns (dep:path-mismatch) when a consumer's configured path does not lie under the producer's declared output path — catching stale paths after renames.
Fill markers in runtime_info.input
| Marker | Meaning | Validator |
|---|---|---|
human | User must replace before a run | input:unfilled (fail) |
"" | Auto-derived or env/file-supplied; never edit to run | — |
null | Semantic unset / default / all | — |
| anything else | Real working default | — |
<...>, REPLACE_ME, YOUR_API_KEY, changeme | Retired legacy placeholders | input:placeholder (fail) |
runtime_info.output shape
Each output key is a mapping with path: (a static location fixed at authoring time, block-relative) and/or value: (run-produced — null until the block's run script writes it back, as trainer's train.sh does after training). Consumers resolve value first, then path.
resources.ip
localornull→ run on the current host (default; no SSH).- Real remote IP → the agent must SSH into that node and run inside a tmux session, with
meta_info.resources.directoryas the working directory.
Do not "restore" an old remote IP from git history. The local default is intentional.
Validation
python3 scripts/validate_config.py --root . # whole tree + cross-block deps
python3 scripts/validate_config.py --block subblock/tracer # one block
python3 scripts/validate_config.py --block subblock/tracer --config tests/smoke/config.yamlFindings are printed as [OK]/[WARN]/[FAIL] lines with stable labels (schema:*, dep:*, input:*, output:shape, tree:*); the exit code is non-zero iff any [FAIL] was reported.
Where to read more
- The canonical contract:
.claude/plugins/root-plugin/resources/BLOCK_DEFINITION.md. - The schema template:
.claude/plugins/root-plugin/resources/config.template.yaml. - A worked example scaffold:
.claude/plugins/root-plugin/resources/example_block/.