YAML reference
The generated workflow JSON Schema is authoritative. This page explains the field groups, defaults, and validation behavior that matter when writing YAML.
Document envelope
Section titled “Document envelope”| Field | Required | Meaning |
|---|---|---|
apiVersion |
yes | Must be agentctl.dev/v1. |
kind |
yes | Must be Workflow. |
metadata.name |
yes | Stable human-readable workflow name. |
metadata.description |
no | Short purpose. |
metadata.labels |
no | String metadata map. |
spec |
yes | Workflow declarations and ordered tasks. |
Unknown fields fail. Documents, ordinary input files, packs, direct reads, existing write targets, and instruction files are limited to 1 MiB.
Workflow declarations
Section titled “Workflow declarations”spec field |
Default | Purpose |
|---|---|---|
inputs |
{} |
Default JSON values supplied to templates. |
outputs |
{} |
Final values selected from inputs, memory, variables, or task outputs. |
providers |
{} |
Named fake, OpenAI, Azure OpenAI, Anthropic, or Google adapters. |
agents |
{} |
Named bounded model executors. |
actions |
{} |
Named deterministic or protocol actions. |
tools |
{} |
Strict model-callable tool contracts. |
subworkflows |
{} |
Semantically versioned reusable task graphs with typed input and output boundaries. |
compensation |
manual, policy approval | Best-effort compensation trigger and approval behavior. |
tasks |
required list | Ordered graph nodes. |
policy |
safe defaults | Filesystem, process, network, provider, tool, and approval rules. |
memory |
empty | Initial working memory and optional typed long-term store, namespace, retention, and embedding configuration. |
mcpServers |
{} |
Pinned MCP Streamable HTTP peers. |
a2aPeers |
{} |
Pinned A2A Agent Card peers. |
packs |
[] |
Semver-constrained local, pinned Git, or immutable archive pack roots. |
packTrust |
unsigned warning, process denied | Unsigned policy, Sigstore identity/issuer allowlist, and explicit unsigned-process acknowledgement. |
runtime |
bounded defaults | Runtime controls. maxConcurrency defaults to 1 and accepts 1 through 64. |
output |
defaults | Output presentation contract. |
Network policy
Section titled “Network policy”policy.networkAllowlist contains exact hosts or *.suffix subdomain rules.
The wildcard never matches the suffix apex. Every network action also uses the
following policy.network fields:
| Field | Default | Validation and behavior |
|---|---|---|
allowedSchemes |
[https, http] |
Nonempty subset of https and http. |
allowedPorts |
[] |
Empty permits the scheme’s known or explicit port; otherwise the effective port must appear here. Port 0 is invalid. |
allowPrivate |
false |
When false, private, loopback, link-local, shared, documentation, benchmark, unspecified, multicast, and reserved IPv4/IPv6 answers fail. |
allowProxy |
false |
When false, environment proxy discovery is disabled. Enabling it explicitly trusts that proxy’s routing and resolution. |
customCa |
none | Environment, mounted-file, or policy-gated process secret reference containing only PEM certificates. Environment references must appear in environmentAllowlist. |
connectTimeoutSeconds |
10 |
Bounds DNS resolution and TCP connection setup; valid range is 1 through 120. |
maxResponseBytes |
8388608 |
Upper network response bound; valid range is 1 through 67108864 and composes with lower adapter limits. |
Required provider, MCP, and A2A URLs are checked before a run record is created. Agentctl resolves the destination, rejects the complete answer if any address is forbidden, and pins all accepted addresses into the direct client. Redirects and Unix-socket transports are disabled. See Network policy.
Each task requires id and uses. uses is action:name, agent:name,
workflow:name, or router.
| Field | Default | Validation |
|---|---|---|
needs |
[] |
Every ID must exist; cycles fail. |
foreach |
none | Static typed items, binding as, and maxItems. Mutually exclusive with matrix; maximum 256 children. |
matrix |
none | Static axes Cartesian product and maxItems. Axis names are template-safe identifiers; maximum 256 children. |
route |
required for uses: router |
Exact typed select, unique typed cases, enumerated destinations, and optional default destinations. Every destination must depend on the router. |
loop |
none | Required maxIterations from 1 through 64, exact typed while, and optional typed initial value. Mutually exclusive with when, foreach, matrix, and route. |
memoryWrites |
inferred or [] |
Working-memory keys. Literal memory-write keys are inferred; templated keys require an explicit set. Unordered overlaps fail when concurrency is greater than one. |
when |
true | Constrained boolean/equality expression. |
vars |
{} |
Task-local JSON values. |
with |
{} |
Typed action or agent input. |
outputSchema |
action-owned object or agent structured contract | Valid JSON Schema checked at task completion and selective-repair reuse. |
retry |
bounded default | Only definitive retry-safe failures may repeat. |
timeoutSeconds |
action or agent default | Must be within the implementation bound. |
compensate |
none | Named effectful action, typed with, bounded retry, and timeout. Valid only on a potentially mutating task. |
| failure behavior | fail | Unsupported dynamic control flow is rejected. |
extension.process actions require
protocolVersion: agentctl.dev/process-extension/v1, explicit idempotency,
input and output JSON Schemas, a declared capability list, direct command/args,
and bounded process limits. See Extensions.
Ready tasks are selected in YAML declaration order up to maxConcurrency.
They read isolated durable snapshots and commit in compiled order. There is no
runtime or model-controlled expansion. Static foreach and matrix tasks
compile to inspectable child tasks and a parent aggregate. Bounded loops
compile to a sequential child chain and parent aggregate. Sub-workflows compile
to namespaced ordinary tasks with typed input and output boundaries. There is
no handler or separate parallel group in this version. Compensation is planned
after a terminal run and executes declared inverse actions in reverse graph
order through an ordinary source-linked durable run.
Agents
Section titled “Agents”An agent requires provider and model. Defaults are maxTurns: 8, maxToolCalls: 16, maxOutputTokens: 2048, and timeoutSeconds: 120. Set tighter values for known work. Optional fields include instructions or instructionsFile, variables, tools, retry, reasoning, structured output, usage limits, and provider-specific options.
structuredOutput asks the provider for typed JSON and becomes the default task output contract. A task-level outputSchema can define the complete task contract explicitly. An agent result that feeds downstream tasks must have one of these contracts before it can be reused by selective repair. Schema documents are compiled when the workflow is checked; values are validated both when completed and when reused.
Capability negotiation happens during compilation. A provider must explicitly support every requested feature.
Runtime budgets
Section titled “Runtime budgets”runtime.maxConcurrency defaults to 1, and
runtime.defaultTimeoutSeconds defaults to 120. Optional
runtime.budgets fields are maxProviderRequests, maxTurns,
maxToolCalls, maxInputTokens, maxOutputTokens, maxTotalTokens,
maxWallTimeSeconds, maxProcessOutputBytes, maxArtifactBytes,
maxTasks, maxExpansionItems, maxLoopIterations, and
maxCostMicrousd. Values must be greater than zero.
maxCostMicrousd requires runtime.pricing.version and a
runtime.pricing.models entry for every cost-limited provider/model.
Input and output rates are integer micro-US-dollars per million tokens.
Optional reasoning and cache rates fall back to output and input rates. See
Resource and cost budgets.
Actions
Section titled “Actions”Supported action kinds:
builtin.assignbuiltin.assertbuiltin.readbuiltin.writebuiltin.shell.execbuiltin.memory.readbuiltin.memory.writebuiltin.long_term_memory.readbuiltin.long_term_memory.searchbuiltin.long_term_memory.writebuiltin.long_term_memory.promotemcp.calla2a.delegate
builtin.shell.exec uses a direct executable and argument list. Output defaults are 1 MiB per stream and 2 MiB combined, with a maximum configured value of 16 MiB. Its maximum timeout is 86,400 seconds.
Both process action kinds accept isolation. process is the default and
means bounded host execution, not sandboxing. container requires a
container block:
| Field | Default | Validation and behavior |
|---|---|---|
image |
required | Local content address in NAME@sha256:DIGEST or sha256:IMAGE_ID form. Pulls are disabled. |
runtime |
auto |
auto, docker, or podman. Explicit selection never falls back. |
memoryLimitBytes |
268435456 |
16 MiB through 16 GiB. |
cpuLimitMillis |
1000 |
1 through 64,000; 1,000 is one CPU. |
pidsLimit |
64 |
1 through 4,096. |
Container mode fixes a read-only root and workspace mount, non-root user,
network none, dropped capabilities, no-new-privileges, bounded /tmp, and
direct entrypoint/arguments. The compiled plan exposes process requirements.
See Process isolation.
mcp.call accepts an optional idempotency declaration. Only pure,
idempotent, or keyed permits the bounded reconnect path, and a refreshed
tool schema must match exactly. Omitted idempotency is unknown.
An A2A peer accepts timeoutSeconds, maxPolls from 1 through 1,000, and
pollIntervalMs from 1 through 60,000. Defaults are 120 seconds, 100 polls,
and 100 milliseconds. These bounds apply to observation of a known task;
SendMessage remains at most once.
Long-term memory
Section titled “Long-term memory”memory.longTerm defaults to the built-in sqlite provider and default
namespace. retentionDays, when set, is 1 through 36,500. Its embedding
block defaults to local_hash with 64 dimensions and accepts 8 through 4096
dimensions. Any non-local embedding provider must name a compatible entry in
spec.providers. OpenAI embeddings also require embedding.model.
Memory writes accept a versioned entry, a typed content block, or a legacy
value plus optional searchable text and metadata. Search accepts exact
metadata filters and text, vector, or hybrid mode, with a result limit
from 1 through 100. Promotion is a separate internal-state action and requires
its working-memory key in memoryWrites when the key is templated. See
State and memory.
A tool requires kind, description, strict input and output JSON Schema, capability, risk, effect class, idempotency, retry safety, timeout, and approval behavior. Built-in tool executors are workspace read, workspace write, and echo. Declared semantics must match the built-in kind.
Templates and conditions
Section titled “Templates and conditions”Allowed template roots are:
${{ inputs.path }}${{ vars.path }}${{ memory.path }}${{ tasks.task-id.output.path }}An exact template preserves objects, arrays, booleans, numbers, strings, and null. Text interpolation accepts scalars. Conditions add not, type-sensitive == and !=, and numeric <, <=, >, and >=. There is no code execution, arithmetic, arbitrary function, indexing, or implicit dependency.
Secret references
Section titled “Secret references”Provider credentials, action environment values, and protocol headers use
{ env: NAME }, { file: PATH }, or a bounded { process: ... } reference.
The source description is stored in the workflow, but the value is resolved
only at the execution boundary. File and process sources require explicit
secretFileRoots or secretProcessAllowlist policy. See
Secret references.
Example and validation
Section titled “Example and validation”See examples/v1/dataflow.yaml for typed inputs and task outputs. From the repository root:
agentctl check examples/v1/dataflow.yamlagentctl plan examples/v1/dataflow.yamlagentctl run examples/v1/dataflow.yaml --db /tmp/dataflow.db --output json --color neverRelated guides: Workflow authoring, Matrix and foreach, Conditions and routers, Bounded loops, Reusable sub-workflows, Compensation, Secret references, Policies, Tools, and Workflow DSL.
Canonical source:
docs/reference/YAML.md. Verified against agentctl commit2aeaa88fba71162206b5f08f5bda4f0150247e4f.