Workflow file: top-level fields
This page lists every field that can appear at the top level of workflow.yaml. There are 15, taken from the list the loader checks files against. For each one it gives the type, whether it is required, what it does, and an example that was run.
For the fields of a step, see Step fields.
Summary
Section titled “Summary”| Field | Type | Required | What it holds |
|---|---|---|---|
id |
string | Yes | The name runs are started by. |
name |
string | Yes | The name shown to people. |
description |
string | No | What the workflow is for. |
version |
number | Yes | A number you choose. |
params_schema |
JSON Schema | No | The shape of a run’s parameters. |
protocol |
map | No | Instructions given to an assistant. |
services |
map | No | The services that auto steps call. |
mcp_servers |
list | No | Tool servers for agent steps. |
templates |
map | No | Groups of steps to reuse. |
steps |
map | Yes | The steps. |
profiles_dir |
string | No | The folder that holds agent profiles. |
extensions |
string or list | No | Your own code to load. |
workflow_context |
map | No | Files whose text any prompt can include. |
context_wrapper |
string | No | How that text is marked off in a prompt. |
trigger |
map | No | The webhook that starts runs. |
The examples below are parts of one file, shown whole in A file that uses every field.
- Type: string. Required.
- The name the workflow is registered under.
start_runtakes it asworkflow_id, and CLI commands take it wherever they ask for a workflow ID. The registered copy is stored as~/.realm/workflows/<id>.json. - The loader does not check which characters the ID contains. An ID that contains
/passesrealm workflow validateand then fails atrealm workflow register, because the ID is used as a file name.
id: review-noteWithout it, the file is refused: Invalid workflow: Missing required field: 'id'.
- Type: string. Required.
- The name shown in
realm workflow listand returned to assistants bylist_workflows.
name: Review a noteWithout it: Invalid workflow: Missing required field: 'name'.
description
Section titled “description”- Type: string. Optional.
- What the workflow is for.
realm workflow validateandrealm workflow registerprint it under their first line, andget_workflow_protocolreturns it to an assistant asdescription.
description: Reads a note, has it reviewed, and files the result.version
Section titled “version”- Type: number. Required.
- A number you choose and change yourself. It is shown after the ID, as in
review-note v1, and stored with each run. Realm does not increase it, and registering a changed file under the same version replaces the stored copy.
version: 1A value in quotes is refused: Invalid workflow: 'version' must be a number.
params_schema
Section titled “params_schema”- Type: a JSON Schema. Optional.
- The shape that a run’s parameters must have. Starting a run with parameters that do not fit is refused, and no run is created. Without
params_schema, any parameters are accepted. - The schema itself is checked when the file is loaded. See JSON Schema blocks.
params_schema: type: object additionalProperties: false required: [path] properties: path: type: stringStarting a run with no path returns:
VALIDATION_INPUT_SCHEMA: Invalid params for workflow 'review-note': (root) must have required property 'path'protocol
Section titled “protocol”- Type: map with two optional keys,
quick_startandrules. Optional. - Changes what
get_workflow_protocoltells an assistant.
| Key | Type | Effect |
|---|---|---|
quick_start |
string | Replaces the opening instruction. An empty string is ignored. |
rules |
list of strings | Replaces the five standard rules. Two rules about concurrent attempts are always added after yours. |
protocol: quick_start: Start a run with the full path of the note, then follow each step's prompt. rules: - Never state a fact that is not in the note.Without protocol, the opening instruction is:
Call start_run with workflow_id 'review-note'. The engine runs the steps it owns and returns control at the first step requiring agent action; when next_actions names advance_run, call it. Follow the next_action in each response until the workflow completes.The advance_run clause was added after version 0.46.0.
and the five standard rules are:
Follow the next_action instruction in each response exactly.When you receive status 'confirm_required', read gate.agent_hint for instructions, present gate.display to the user verbatim, wait for their response, then call submit_human_response by copying the call in next_actions[0].instruction.call_with and filling in their choice.Do NOT auto-confirm any human gate. The user must decide.Do NOT ask the user for permission between steps unless the system tells you to.When next_actions names advance_run, call it: the engine owes steps it runs when you call advance_run.The fifth rule was added after version 0.46.0. Setting rules removes all five, including the two about human gates.
services
Section titled “services”- Type: map from a name you choose to a service definition. Optional.
- Each entry names an adapter. A step calls the service with
uses_service. See Services, profiles and context.
services: files: adapter: filesystem trust: engine_deliveredmcp_servers
Section titled “mcp_servers”- Type: list of tool-server definitions. Optional.
- The tool servers that agent steps can take tools from when
realm agentdrives them. Each entry hasid,transport(onlystdio),command, and optionallyargsandenv. A step that liststoolsrequires this block. See Give an agent step tools.
mcp_servers: - id: notes transport: stdio command: npx args: ['-y', '@modelcontextprotocol/server-filesystem', './notes']templates
Section titled “templates”- Type: map from a template name to a group of steps with parameters. Optional.
- A step entry that has
use_templateis replaced, when the file is loaded, by the template’s steps. See Services, profiles and context.
templates: check: params: topic: required: true steps: look: description: 'Check the note for {{ topic }}.' execution: agent depends_on: [read_note]Used with prefix: spelling, this template adds a step named spelling_look.
- Type: map from a step name to a step definition. Required.
- The steps of the workflow. The order of the entries does not decide the order in which steps run;
depends_ondoes. See Step fields.
steps: read_note: description: Read the note from disk. execution: auto uses_service: files operation: read input_map: path: run.params.pathWithout it: Invalid workflow: Missing required field: 'steps'. A list in place of the map is refused: Invalid workflow: 'steps' must be a non-null object.
profiles_dir
Section titled “profiles_dir”- Type: string, a path relative to the workflow file. Optional. Default:
profiles. - The folder in which a step’s
agent_profileis looked up, as<profiles_dir>/<name>.md. The folder is read only when a step names a profile.
profiles_dir: personasextensions
Section titled “extensions”- Type: string, or list of strings. Each is a path relative to the workflow file. Optional.
- Files of your own code to load: adapters, handlers and processors. Each file must be inside the workflow’s project. See Project extensions.
extensions: ./registry.mjsrealm workflow validate then reports what it loaded:
Extensions: ./registry.mjs (adapters: 0, handlers: 1, processors: 0)A path that starts at the root of the disk is refused:
Invalid workflow: 'extensions' entry '/abs/registry.mjs' is an absolute path — extension modules must be declared RELATIVE to the workflow directory (e.g. ../dist/registry.js)workflow_context
Section titled “workflow_context”- Type: map from a name to an entry with
source.pathand an optionaldescription. Optional. - Files whose text a prompt can include with
{{ workflow.context.<name> }}. See Services, profiles and context.
workflow_context: glossary: source: path: ./glossary.md description: Terms used in the notes.context_wrapper
Section titled “context_wrapper”- Type: one of
xml,brackets,none. Optional. Default:xml. - How the text of a
workflow_contextentry is marked off where a prompt includes it.
context_wrapper: bracketsWith brackets, a prompt that includes {{ workflow.context.glossary }} was delivered as:
[glossary]SKU: the code that identifies one product.
[/glossary]Any other value is refused: Invalid workflow: 'context_wrapper' must be 'xml', 'brackets', or 'none' (found: 'html') (line 4).
trigger
Section titled “trigger”- Type: map. Optional.
- The webhook that starts runs of this workflow under
realm listen. See Webhook trigger.
trigger: type: webhook path: /review-note auth: mode: none params_map: path: body.pathYour own fields
Section titled “Your own fields”A top-level field whose name starts with x- is yours. Realm keeps it in the registered copy and never reads it. realm workflow validate and realm workflow register name the ones they found:
x-owner: docs-teamValid: review-note v1 (4 steps) — 1 extension key carried, never read by realm: x-ownerNames that start with x-realm- are reserved, and are refused.
Any other field
Section titled “Any other field”A top-level field that is neither in the table nor starts with x- makes realm workflow validate and realm workflow register fail:
⚠ workflow 'w': unknown key 'owner' (line 4) — ignored (not a recognized workflow field).Invalid: 1 warning, 1 escalated to an error by policy: UNKNOWN_WORKFLOW_KEY 'owner'Fields that Realm writes
Section titled “Fields that Realm writes”Realm adds seven fields to the registered copy: source_dir, trust_root, resolved_profiles, schema_version, origin, model and agent. They are not allowed in the file. Writing one, such as schema_version, is refused like any unknown field.
A file that uses every field
Section titled “A file that uses every field”This file, with the files it names beside it, was validated, registered and run to completion.
id: review-notename: Review a notedescription: Reads a note, has it reviewed, and files the result.version: 1
x-owner: docs-team
params_schema: type: object additionalProperties: false required: [path] properties: path: type: string
protocol: quick_start: Start a run with the full path of the note, then follow each step's prompt. rules: - Never state a fact that is not in the note.
services: files: adapter: filesystem trust: engine_delivered
mcp_servers: - id: notes transport: stdio command: npx args: ['-y', '@modelcontextprotocol/server-filesystem', './notes']
templates: check: params: topic: required: true steps: look: description: 'Check the note for {{ topic }}.' execution: agent depends_on: [read_note] input_schema: type: object additionalProperties: false required: [problems] properties: problems: type: array items: type: string
profiles_dir: personasextensions: ./registry.mjs
workflow_context: glossary: source: path: ./glossary.md description: Terms used in the notes.context_wrapper: brackets
trigger: type: webhook path: /review-note auth: mode: none params_map: path: body.path
steps: read_note: description: Read the note from disk. execution: auto uses_service: files operation: read input_map: path: run.params.path
spelling: use_template: check prefix: spelling params: topic: spelling mistakes
review: description: Give a verdict on the note. execution: agent agent_profile: reviewer depends_on: [spelling_look] prompt: | {{ workflow.context.glossary }}
Give a verdict on this note:
{{ context.resources.read_note.content }} input_schema: type: object additionalProperties: false required: [verdict] properties: verdict: type: string enum: [fine, needs_work]
file: description: File the verdict. execution: auto depends_on: [review] handler: file_result input_map: verdict: context.resources.review.verdictrealm workflow validate ./ prints:
Valid: review-note v1 (4 steps) — 1 extension key carried, never read by realm: x-owner Reads a note, has it reviewed, and files the result.Extensions: ./registry.mjs (adapters: 0, handlers: 1, processors: 0)ℹ 2 steps ready for structured_output: strict — run 'realm workflow validate --explain' for detail (REALM_NO_NUDGE=1 to silence).