Skip to content

YAML reference

The generated workflow JSON Schema is authoritative. This page explains the field groups, defaults, and validation behavior that matter when writing YAML.

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.

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.

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.

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.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.

Supported action kinds:

  • builtin.assign
  • builtin.assert
  • builtin.read
  • builtin.write
  • builtin.shell.exec
  • builtin.memory.read
  • builtin.memory.write
  • builtin.long_term_memory.read
  • builtin.long_term_memory.search
  • builtin.long_term_memory.write
  • builtin.long_term_memory.promote
  • mcp.call
  • a2a.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.

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.

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.

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.

See examples/v1/dataflow.yaml for typed inputs and task outputs. From the repository root:

agentctl check examples/v1/dataflow.yaml
agentctl plan examples/v1/dataflow.yaml
agentctl run examples/v1/dataflow.yaml --db /tmp/dataflow.db --output json --color never

Related 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 commit 2aeaa88fba71162206b5f08f5bda4f0150247e4f.