Graph Templates¶
TopoExec provides a small schema-v1 template surface for reusable YAML graph
snippets. Templates are expanded while loading the graph; the runtime,
scheduler, channel router, and validators only see the expanded flat
GraphSpec.
Contract¶
Templates are deliberately limited:
- no arbitrary code, expressions, file includes, loops, or conditionals;
- parameter substitution is the only dynamic behavior;
- placeholders use
{{name}}and must match a declared parameter exactly; - instance parameter maps must provide every declared parameter and no unknown parameters;
- expansion prefixes local component, edge,
depends_on, and CompositeLoop ids with thetemplate_instances[].idnamespace; - edges cannot be hidden because every template edge expands into a normal
GraphSpec::edgesentry before validation.
Use templates for small repeated shapes such as source-transform-sink, request-worker-response, bounded async task paths, or delay feedback snippets. Do not use them as a dynamic plugin system or runtime graph loader.
YAML shape¶
schema_version: 1
graph: {name: template_source_transform_sink, kind: internal_test}
lanes: {main: {type: event_loop}}
components: []
edges: []
templates:
- id: source_transform_sink
parameters: [source_descriptor, sink_descriptor]
components:
- id: source
type: topoexec.boundary.Input
boundary: {role: input, descriptor: "{{source_descriptor}}"}
event_sources: [{type: manual}]
trigger_policy: {type: manual}
execution: {lane: main}
- id: transform
type: topoexec.transforms.Identity
event_sources: [{type: message, inputs: [in]}]
trigger_policy: {type: any_input, inputs: [in]}
execution: {lane: main}
- id: sink
type: topoexec.boundary.Output
boundary: {role: output, descriptor: "{{sink_descriptor}}"}
event_sources: [{type: message, inputs: [in]}]
trigger_policy: {type: any_input, inputs: [in]}
execution: {lane: main}
edges:
- {id: source_transform, kind: immediate, from: source.out, to: transform.in}
- {id: transform_sink, kind: immediate, from: transform.out, to: sink.in}
template_instances:
- id: demo
template: source_transform_sink
parameters: {source_descriptor: stdin, sink_descriptor: stdout}
The instance expands into components demo.source, demo.transform, and
demo.sink; edges demo.source_transform and demo.transform_sink; and
endpoints such as demo.source.out and demo.sink.in. Plan JSON shows the
expanded namespace under hierarchy[]; runtime metrics and trace use the
expanded ids.
Validation¶
Template expansion happens before normal graph validation, so all existing semantic checks still apply:
- unsupported component types fail registry validation;
- immediate cycles still require exact CompositeLoop ownership;
- missing ports, invalid trigger inputs, and invalid channel policies fail the same way as handwritten expanded YAML;
- invalid placeholders, missing parameters, unknown parameters, and duplicate template ids fail during loading.
The CLI has no separate template command. Use existing graph commands:
./build/topoexec graph validate examples/template_source_transform_sink.yaml
./build/topoexec graph plan examples/template_source_transform_sink.yaml --format json