Workflow YAML reference
The complete top-level workflow schema, action shorthand, and the 6-pass validator.
A Revka workflow is a declarative YAML document: a set of typed steps with dependencies, optional triggers, and execution defaults. The operator-mcp backend parses the YAML against a Pydantic schema, runs a six-pass validator, and only then stores the definition as a revision in Kumiho graph memory and executes it deterministically.
This page is the schema reference for everything above the per-step config block: the top-level fields, the inputs/outputs/triggers shapes, the action shorthand that lets the editor write terse steps, and the validator that gates every save and run. For the body of each step type, see Step types reference; for ${...} interpolation and ${{ ... }} expressions, see Variables, expressions & triggers. If you just want to ship something, start with Your first workflow.
Minimal example
Section titled “Minimal example”The smallest valid workflow has a name and at least one step:
name: hello-worldversion: "1.0"description: Greet a topic and return the text.steps: - id: greet type: agent agent: agent_type: claude role: researcher prompt: "Say hello and introduce ${inputs.topic}."A more complete shape, with typed inputs, named outputs, and a trigger:
name: daily-reportversion: "1.0"description: Summarise a topic and publish the result.tags: [reporting]
inputs: - name: topic type: string required: true default: ""
triggers: - cron: "0 9 * * 1" # every Monday 09:00 # timezone is set via the cron job, not the trigger block
steps: - id: summarize action: summarize # shorthand → type: agent, role: summarizer, claude agent: prompt: "Summarise ${inputs.topic} in five bullet points." output_fields: [summary]
- id: report type: output depends_on: [summarize] output: format: markdown template: | # ${inputs.topic} ${summarize.output}
outputs: - name: result source: "${report.output}"Top-level schema
Section titled “Top-level schema”These fields live at the root of the document (WorkflowDef). Only name and steps are required.
| Field | Type | Default | Meaning |
|---|---|---|---|
name | string | — (required) | Workflow identifier. The gateway slugifies the display name into the Kumiho item id. |
version | string | "1.0" | Semantic version label, free-form. |
description | string | "" | Human-readable purpose; shown in the dashboard list and search. |
tags | list<string> | [] | Classification labels for search and filtering. |
triggers | list<Trigger> | [] | Cron or entity-event conditions that auto-launch the workflow. |
inputs | list<Input> | [] | Typed parameters supplied at run time. |
outputs | list<Output> | [] | Named results mapped from step output via source. |
steps | list<Step> | — (required) | Ordered step definitions; at least one is required. |
default_cwd | string | "" | Default working directory for shell/agent steps when a run does not pass cwd. |
default_timeout | number | 300.0 | Default per-step timeout in seconds. |
max_total_time | number | 3600.0 | Safety cap on total run wall-clock time, in seconds (1 hour). |
checkpoint | bool | true | Persist run state after each step so a failed run can be retried. See Runs, approvals & checkpoints. |
Inputs
Section titled “Inputs”Each entry in inputs is a typed parameter. A run supplies values through the inputs object on the trigger call; anything not supplied falls back to default.
inputs: - name: topic type: string # string | number | boolean | list required: true default: "" description: "What to summarise."| Field | Type | Default | Meaning |
|---|---|---|---|
name | string | — | Parameter name; referenced as ${inputs.<name>}. |
type | enum | string | One of string, number, boolean, list. |
required | bool | true | Whether a value must be present at run time. |
default | any | null | Fallback value when none is supplied. |
description | string | "" | Documentation shown in the editor. |
A required input with no default must be provided at run time. If the workflow also has triggers that don’t map it, the validator emits an advisory warning — it can still be auto-filled from upstream entity metadata.
Outputs
Section titled “Outputs”outputs map a name to a step result via a ${...} source expression, so callers and downstream workflows get a stable contract:
outputs: - name: result source: "${report.output}" - name: next_episode source: "${{ int(resolve_cursor.output_data.episode_number) + 1 }}" description: "Computed cursor for the next run."| Field | Type | Default | Meaning |
|---|---|---|---|
name | string | — | Output name. |
source | string | — | ${...} or ${{ ... }} expression resolved at the end of the run. |
description | string | "" | Documentation. |
Triggers
Section titled “Triggers”A trigger auto-launches the workflow. There are two shapes in one struct (TriggerDef): set cron for a time-based trigger, or set on_kind for an entity-event trigger. Saving a definition with cron triggers registers cron jobs automatically; deprecating or deleting it removes them.
triggers: # Time-based - cron: "0 9 * * 1"
# Entity-event: fire when an upstream output step publishes a matching entity - on_kind: "qs-arc-plan" # entity kind to watch (exact match) on_tag: "ready" # revision tag that fires the trigger on_name_pattern: "qs-*" # optional glob on entity name on_space: "Revka/WorkflowOutputs/QuantumSoul" # optional space prefix input_map: # map trigger data → workflow inputs arc_kref: "${trigger.entity_kref}" arc_name: "${trigger.metadata.arc_name}"| Field | Type | Default | Meaning |
|---|---|---|---|
cron | string | "" | Cron expression for time-based triggers. When set, the entity fields are optional. |
on_kind | string | "" | Entity kind to watch (exact match). Required for event triggers. |
on_tag | string | "ready" | Revision tag that fires the trigger (exact match). |
on_name_pattern | string | "" | Optional glob on entity name ("" = any). |
on_space | string | "" | Optional space path prefix filter ("" = any). |
input_map | map<string,string> | {} | Maps a workflow input name to a ${trigger.*} template. |
Event-trigger filters are cumulative (AND). If input_map is omitted, metadata keys on the triggering entity are auto-mapped to matching workflow input names. Full mechanics — including the chaining pattern — are in Variables, expressions & triggers.
Each step shares a common envelope (StepDef) and exactly one type-specific config block named after its type. The full body of every step type is documented in Step types reference; the envelope fields below apply to all of them.
steps: - id: research # unique within the workflow (required) name: "Research phase" # display label; defaults to id type: agent # the step type (or omit and use `action`) depends_on: [resolve_topic] skills: - "kref://CognitiveMemory/Skills/some-skill.skilldef" retry: 1 # retry up to N times after the first attempt retry_delay: 10 # seconds between retries timeout: 600 # step-level override, pushed into the type config agent: prompt: "..."| Field | Type | Default | Meaning |
|---|---|---|---|
id | string | — (required) | Unique step identifier, referenced as ${id.output}. |
name | string | id | Display label for the dashboard graph. |
type | enum | agent | One of the step types. May be omitted when action is set. |
depends_on | list<string> | [] | Step ids that must finish first. Sibling steps with no depends_on run in parallel naturally. |
action | string | "" | Shorthand that infers type and agent defaults. |
agent_hints | list<string> | [] | Override the agent type/role chosen by action (for example [codex]). |
skills | list<string> | [] | Skill krefs injected into an agent step. |
assign | string | "" | Pre-assigned agent pool template; wired to agent.template when that is unset. |
description | string | "" | Used as the prompt when an action step has no explicit agent.prompt. |
compression | bool | false | Compress large output before handing it to downstream steps. |
retry | int (0–5) | 0 | Retries after the first failed attempt. |
retry_delay | number | 5.0 | Seconds to wait between retries. |
timeout | number | inherited | Step-level timeout; pushed into the agent/shell/python/email/image/a2a/group_chat config. |
Step types
Section titled “Step types”The type field accepts these values (StepType). Each maps to a config block of the same name:
| Category | Types |
|---|---|
| Agent & code | agent, shell, python, compute, image |
| Communication | email, notify, human_approval, human_input |
| Control flow | conditional, parallel, goto, for_each |
| Output & data | output, resolve, tag, deprecate |
| Kumiho graph | kumiho_context, kumiho_bundle_update, kumiho_patch_apply |
| Orchestration | map_reduce, supervisor, group_chat, handoff |
| External | a2a, manus |
See Step types reference for the fields of each.
Action shorthand
Section titled “Action shorthand”The editor and hand-written workflows can skip type and the agent block entirely by setting action. The schema maps each action name to a step type and, for agent actions, a default role and agent type. You can still add an agent: block to override the prompt and other fields, and agent_hints overrides the agent type.
# Terse form- id: research action: research # → type: agent, role: researcher, agent_type: claude agent_hints: [codex] # override: run on codex instead of claude description: "Research the competitive landscape."
# Equivalent explicit form- id: research type: agent agent: agent_type: codex role: researcher prompt: "Research the competitive landscape."The complete ACTION_DEFAULTS mapping:
| Action | Step type | Role | Agent type |
|---|---|---|---|
research | agent | researcher | claude |
code | agent | coder | codex |
review | agent | reviewer | claude |
deploy | agent | deployer | codex |
test | agent | tester | codex |
build | agent | builder | codex |
summarize | agent | summarizer | claude |
task | agent | coder | claude |
notify | notify | — | — |
approve | human_approval | — | — |
gate | conditional | — | — |
human_input | human_input | — | — |
resolve | resolve | — | — |
compute | compute | — | — |
kumiho_context | kumiho_context | — | — |
kumiho_bundle_update | kumiho_bundle_update | — | — |
kumiho_patch_apply | kumiho_patch_apply | — | — |
How resolution works:
typeomitted,actionset →typeis inferred from the table.typeset to an action alias (for exampletype: notify) → it is expanded to the real step type (notify→notify; an agent alias →agent) and the original is recorded as theaction.- No
agentblock on an agent action → a defaultAgentStepConfigis synthesized from the action’s role and agent type, usingdescription(orExecute <action> task: <name>) as the prompt. agent_hintsoverride the synthesized agent type:codex/coder→codex;claude/researcher/reviewer→claude. A hint ofcoder,researcher, orrevieweralso sets the role.taskis the fallback action when an unknown action name is used.
Workflow validation (6-pass)
Section titled “Workflow validation (6-pass)”Before a definition is stored or run, the operator’s validate_workflow runs a series of structural passes and returns { valid, errors, warnings, execution_order, all_step_ids }. Any error makes the definition invalid; warnings are advisory and never block a save.
-
Duplicate step IDs — every
step.idmust be unique. (Hard duplicates are already rejected at parse time; this pass also reports them in the structured result.) -
Dependency references — every
depends_onentry must name an existing step. Unknown references are errors and build the adjacency map for the next pass. -
Cycle detection — a depth-first topological sort over
depends_on. A back-edge is aDependency cycle detectederror. The resulting topological order becomesexecution_order(children owned byparallel/for_eachwrappers are excluded so they don’t run twice). -
Per-step config — type-specific checks. For example:
shellneeds acommand;imageandmap_reduce/supervisor/group_chatneed their required fields;conditionalbranches andgoto/handofftargets must point to real steps (orend);parallelneeds ≥2 sub-steps that exist and don’t cross-depend;outputrequires bothentity_nameandentity_kindif either is set;agent.output_fieldsmust be valid, non-reserved identifiers. -
Variable references — scans every interpolatable string for
${...}and${{ ... }}references. Built-in namespaces (inputs,loop,env,trigger,for_each,previous,outputs,run_id,rejection) are allowed; any other leading namespace that isn’t a known step id produces a warning (not an error), so first-run patterns that reference not-yet-produced data still save. -
Agent dependency & contract checks — two finer agent passes: an agent step whose
depends_onentry is never referenced in its prompt is an error (see the caution above); and an${X.output_data.<field>}reference to an agent step that doesn’t declare<field>inagent.output_fieldsis a warning. -
Triggers — each trigger must be valid: a non-cron trigger needs
on_kindandon_tag; a workflow with required inputs that a trigger doesn’t map produces a warning (they may be auto-filled from entity metadata).
Where validation runs
Section titled “Where validation runs”- Dashboard — saving validates automatically; errors render inline in the editor. See Workflows, editor & runs.
- Gateway API —
POST /api/workflows,PUT /api/workflows/{*kref}, andPOST /api/workflows/run/{name}validate before persisting or dispatching and reject with400on failure. - Operator MCP — the
validate_workflowanddry_run_workflowtools (below) let an agent or the Architect panel check a definition without saving it.
The gateway calls the operator’s validator with a fixed timeout. If validation cannot run because of an infrastructure error (the operator is briefly unreachable), it is skipped rather than blocking the save (fail-open). Full HTTP behavior is in Workflows & Architect API.
Failure response shape
Section titled “Failure response shape”POST/PUT on definitions and POST /api/workflows/run/{name} return 400 with:
{ "error": "Workflow validation failed: ...", "valid": false, "errors": [ { "message": "depends_on references unknown step 'reserch'", "severity": "error", "step_id": "report", "field": "depends_on" } ], "warnings": [ { "message": "Variable reference '${draft.output}' — step 'draft' not found", "severity": "warning", "step_id": "report" } ]}Each entry carries message and severity (error or warning), plus optional step_id and field to locate the issue.
Operator tools: the declarative workflow engine
Section titled “Operator tools: the declarative workflow engine”Workflows are executed by the operator-mcp engine, which exposes the full lifecycle as MCP tools the agent and dashboard call. The validation tools are the ones you reach for while authoring; the rest run and manage workflows. See Operator MCP for how the backend is wired.
validate_workflow
Section titled “validate_workflow”Runs the six-pass validator without executing or persisting anything. Accepts a workflow by name, an inline definition, or raw YAML, and returns the ValidationResult (valid, errors, warnings).
validate_workflow( workflow?, # name of a stored/builtin workflow workflow_def?, # inline definition object workflow_yaml?, # raw YAML string cwd?, # working directory for discovery)→ { "valid": true, "errors": [], "warnings": [ ... ] }Use this to lint a draft before saving. The gateway’s POST /api/architect/validate_yaml route is a thin wrapper over the related propose_workflow_yaml tool for the visual editor’s chat-fallback path.
dry_run_workflow
Section titled “dry_run_workflow”Validates and previews execution without running any step: it reports the planned execution order, step count, and a cost estimate. Use it to confirm a workflow will do roughly what you expect — and what it might cost — before a real run.
dry_run_workflow( workflow?, # name of a stored/builtin workflow workflow_def?, # inline definition object inputs?, # input values to plan against cwd?,)→ preview of execution order, step count, and estimated costOther lifecycle tools
Section titled “Other lifecycle tools”| Tool | Purpose |
|---|---|
run_workflow(workflow, inputs, cwd, run_id?, max_cost_usd?) | Execute by name or inline definition. max_cost_usd aborts the run if the cost cap is exceeded. |
list_workflows(cwd?, tag?) | List builtin + user + project-local workflows, optionally filtered by tag. |
get_workflow_status(run_id, include_outputs?) | Per-step results for a running or completed run. |
cancel_workflow(run_id) | Cancel a running or paused run at the next step boundary. |
resume_workflow(run_id, approved?, cwd?) | Resume after a human_approval step. |
retry_workflow(run_id, cwd?) | Retry from the first failed step; successful steps are preserved. |
create_workflow(workflow_def, directory?) | Create and save the YAML to ~/.revka/workflows/. |
revise_workflow(workflow_kref, operations, rationale?) | Apply structured add/edit/delete/reorder/wire operations, producing a new revision. |
propose_workflow_yaml(proposed_yaml, intent_summary?, base_yaml?) | Architect-only: validate + diff without persisting; powers the visual editor. |
get_workflow_metadata(include?) | Available step types, pool agents, auth profiles, skills, and channels. |
recall_workflow_runs(workflow?, limit?) / get_workflow_run_detail(run_id) | Recent runs and per-step detail from Kumiho memory. |
File discovery & storage
Section titled “File discovery & storage”Workflows can live on disk or in Kumiho. The operator scans these locations, with later sources overriding earlier ones by name:
| Priority | Location | Purpose |
|---|---|---|
| Highest | .revka/workflows/ (project-local) | Per-project overrides. |
~/.revka/workflows/ (user) | User-global workflows. | |
| Lowest | operator_mcp/workflow/builtins/ | Shipped defaults (see Built-in workflows & patterns). |
| Fallback | Kumiho space Revka/Workflows | Cloud-managed definitions. |
When you save from the dashboard or via the API, the definition is stored as a Kumiho item of kind workflow in the Revka/Workflows space. The YAML itself is written as a workflow.yaml revision artifact (not inline metadata, to stay under Kumiho’s size limit). The dashboard also writes the YAML to disk at ~/.revka/workflows/{slug}.r{N}.yaml; the directory scanner picks up the base {slug}.yaml, while the .r{N}.yaml revision files are reached only through kref resolution. Every save writes a new revision and re-tags it published, so each run can be pinned to the exact YAML it executed.