Workflow Object
A Workflow is the top-level document. It defines a directed graph of Nodes connected by Edges, with a designated entry point.
Fields
Section titled “Fields”| Field | Type | Required | Default | Description |
|---|---|---|---|---|
id | string | REQUIRED | — | Unique identifier for this workflow. MUST be non-empty. |
name | string | REQUIRED | — | Human-readable name. MUST be non-empty. |
description | string | OPTIONAL | "" | Purpose of the workflow. |
entry | string | REQUIRED | — | Node ID where execution begins. MUST reference a key in nodes. |
nodes | Record<string, Node> | REQUIRED | — | Map of node ID to Node definition. Keys are referenced by entry and edge from/to fields. |
edges | Edge[] | REQUIRED | — | Directed edges defining execution flow and routing conditions. |
skills | Record<string, SkillDefinition> | OPTIONAL | {} | Inline skill definitions scoped to this workflow. |
rules | Source[] | OPTIONAL | [] | Directives prepended to every node’s instruction. Organization-wide policies, coding standards. |
context | Source[] | OPTIONAL | [] | Background knowledge prepended to every node’s instruction. Architecture docs, playbooks. |
workflow_type | string (enum) | OPTIONAL | generic | Workflow type discriminator. Routes runs to a type-specific renderer. See Workflow type. |
model | string | OPTIONAL | impl‑defined | Default execution model for every node. Overridable per-node. Free-text passthrough. See Nodes — Model Selection. |
inputs | Record<string, InputField> | OPTIONAL | — | Declared per-run input contract. The CLI validates --input against this and applies defaults. See Inputs. |
Workflow type
Section titled “Workflow type”The workflow_type field tells consumers which kind of work this workflow does, so the run can be rendered with type-appropriate metrics. The field is optional. When absent, consumers MUST treat the workflow as type generic.
v1 enum values
Section titled “v1 enum values”| Value | What it produces | Typical metrics |
|---|---|---|
pr_review | A PR comment with risks and suggestions | Caught / Calibration / Missed |
e2e_test | Pass-fail per test, screenshots, traces | Flake rate, step failure heatmap, run duration |
content_generation | Text or JSON artifacts (e.g. changelog drafts) | Acceptance rate, regen rate, edit distance |
monitor | A delta report (e.g. weekly regulatory monitor) | Coverage, novel-finding rate, staleness |
data_sync | Records processed counts, errors, latency | Throughput, error rate, drift |
generic | Anything else | Run duration, step status, edge routing health |
A conforming consumer:
- MUST accept any of the values above.
- MUST treat absent
workflow_typeasgeneric. - MUST reject any value not in the enum at parse time.
- MAY ignore the field entirely if it doesn’t have type-specific rendering. Type-specific rendering is an opt-in surface; the runtime executor doesn’t change behavior based on
workflow_type.
Marketplace templates published in v1+ are required to declare workflow_type so they render correctly out of the box.
workflow_type is independent of the Inputs contract. A workflow of any type MAY declare inputs, and the type discriminator does not reserve any field names. The composition rules are spelled out under Inputs and workflow_type.
Example
Section titled “Example”id: regulatory-monitorname: Regulatory Monitorworkflow_type: monitordescription: Weekly state-by-state regulation collectionentry: gathernodes: gather: { ... }edges: [...]Rules & Context
Section titled “Rules & Context”The rules and context fields attach knowledge documents to the workflow. Every Source in these arrays is resolved eagerly before any node executes, and the resolved content is prepended to every node’s instruction (see Nodes — Input Augmentation).
rules— directives the AI model MUST follow. Coding standards, review policies, compliance requirements.context— background information the AI model should consider. Architecture docs, service maps, incident history.
Both support inline text, file paths, and URLs:
rules: - ./coding-standards.md - https://raw.githubusercontent.com/acme/playbook/main/review-policy.md - "Never introduce breaking API changes without a migration path."context: - ./ARCHITECTURE.md - ./docs/service-map.mdNodes can declare their own rules and context that layer on top. See Nodes — Rules & Context for cascade semantics.
Runtime Input
Section titled “Runtime Input”When executing a workflow, you may pass runtime input parameters. Two special fields are recognized:
rules— A Source or array of Sources containing directives prepended to every node’s instruction. These layer on top of workflow-level and node-level rules.context— A Source or array of Sources containing background information prepended to every node’s instruction. These layer on top of workflow-level and node-level context.
Runtime input rules and context resolve eagerly before any node executes. See Nodes — Input Augmentation for the full assembly order.
Inputs
Section titled “Inputs”A workflow MAY declare a top-level inputs block describing the per-run parameters it accepts. When present, the CLI validates the caller-supplied --input <json> against this declaration before the executor runs, applies defaults for omitted optional fields, and rejects malformed input with a grouped error message.
Workflows without an inputs block accept any JSON object (back-compat with every workflow shipped before this feature).
InputField
Section titled “InputField”Each entry in inputs declares one parameter:
| Field | Type | Required | Description |
|---|---|---|---|
type | string (enum) | REQUIRED | One of string, number, boolean, string[]. |
description | string | OPTIONAL | Human-readable purpose. Shown in CLI errors and cloud renderers. |
required | boolean | OPTIONAL | When true, the caller MUST provide a value. Default: false. |
default | matches type | OPTIONAL | Value applied when the caller omits the field. Type-checked at parse time against type. |
enum | array | OPTIONAL | Optional set of allowed values. Each entry MUST match the field’s type. |
An InputField MUST NOT declare both required: true and a default; the combination is incoherent (a default would either silently satisfy the required check, or never fire) and is rejected at workflow load time. Authors who want the required check to fire MUST omit the default. Authors who want a fallback value MUST omit required: true.
Types are intentionally narrow. If you need richer shapes, model them as a flat object and let the receiving node parse the field. The contract MAY widen later without breaking existing YAML.
Validation rules
Section titled “Validation rules”A conforming runtime MUST enforce:
- Required check. Each declared field with
required: trueMUST be present in the caller’s input. A field is “present” when the caller provides a non-nullvalue; an explicitnull(or absence of the key) MUST be treated as missing and surface the same required-field error. (A field withrequired: truecannot also declare adefault; see InputField.) - Type check. Each declared field’s value MUST match its
type.numberrejectsNaNand±Infinity.string[]requires every element to be a string. - Enum check. When
enumis declared, the value MUST equal one of the listed entries. - Default fill. When a field is absent or
nullAND has adefault, the runtime MUST substitute the default before passing the input to the executor. Becauserequiredanddefaultare mutually exclusive, this rule only applies to optional fields. - Caller wins. A caller-provided value MUST take precedence over a declared
default. - Undeclared keys pass through. Keys provided by the caller that aren’t declared in
inputsSHOULD pass through unchanged (so CLI-injected fields likedryRunand the runtimerules/contextcascade keep working). - All errors at once. A validator MUST surface every missing-required and type-mismatch in a single response, not one error per call.
Telemetry shape
Section titled “Telemetry shape”Cloud renderers and run dashboards MAY display the input shape a run was invoked with (key names plus their declared types), but MUST NOT ship the input values themselves. A workflow that accepts a token or other secret as input never leaks the value to telemetry.
A conforming runtime that posts run-start telemetry MUST transmit the shape under the payload key inputs_shape (key name → declared type, e.g. { "since_tag": "string", "draft": "boolean" }) and MUST NOT include the matching inputs (or any equivalent values bag) in the same or any other telemetry payload. Runtimes that do not transmit input data at all trivially satisfy this rule and MAY omit inputs_shape entirely.
Composition with workflow_type
Section titled “Composition with workflow_type”The inputs contract and the workflow_type discriminator are orthogonal. They do not introspect each other. Concretely:
- Any workflow type can declare inputs.
pr_review,e2e_test,content_generation,monitor,data_sync, andgenericworkflows all accept aninputsblock. There is no type for whichinputsis illegal, and no type that requiresinputs. The validator does not gateinputsonworkflow_type. - Inputs are purely additive. Declaring
inputsdoes NOT replace, infer, or override anything the type’s renderer might display. The author’s declared parameters ride alongside the type’s standard fields. Cloud renderers compose the two surfaces; they do not choose between them. - No reserved field names. No type reserves an input name. A
pr_reviewworkflow MAY name a fieldpull_request_url,pr,repo,severity, anything. The renderer does not look inside the input bag to populate its own UI; the type’s standard fields come from cloud-side trigger metadata (PR URL from the GitHub Action context, e.g.), not frominputs. If your workflow needs a value the renderer also displays, it is the author’s job to wire it through. - Renderer scope. When a typed workflow declares
inputs, the cloud run dashboard MAY display BOTH the input shape (key names + declared types, never values; see Telemetry shape) AND the type’s standard fields. The two panes are independent. A renderer MUST NOT fail or warn if a typed workflow declares inputs. - No runtime coupling. The executor passes the resolved
inputbag to every node regardless ofworkflow_type. Type-specific cloud renderers do not introspect theinputbag’s contents at runtime; they only see the declared shape via the telemetry surface.
If a future workflow type needs to require named input fields (e.g. a hypothetical scheduled_report type that requires a cadence field), the spec will name those fields explicitly and the validator will enforce them. As of v1, no type does.
Example
Section titled “Example”id: release-notesname: Release Notesdescription: Draft release notes for the next tagentry: discover
inputs: since_tag: type: string description: Lower bound for the commit range. Default is the previous tag. default: "" until_tag: type: string description: Upper bound for the commit range. default: HEAD draft: type: boolean description: When true, post the notes as a draft instead of publishing. default: true audience: type: string description: Target audience for the notes. enum: [drivers, dispatchers, engineering, all] default: all required_label: type: string required: true description: Issue label to scope the changelog to.
nodes: discover: name: Discover changes instruction: >- Compare commits between input.since_tag and input.until_tag. Scope to PRs labeled input.required_label. Group by area.edges: []Invocation
Section titled “Invocation”CLI:
sweny workflow run release-notes.yml \ --input '{"since_tag":"v1.41.12","until_tag":"v1.41.13","required_label":"release"}'GitHub Action (composite):
- uses: swenyai/sweny@v5 with: workflow: .sweny/release-notes.yml input: | { "since_tag": "${{ inputs.since_tag }}", "until_tag": "${{ github.ref_name }}", "required_label": "release" }Workflow authors reference inputs by name in node instructions and edge when conditions; the resolved bag is exposed to every node as input on the prompt context.
Structural Validation
Section titled “Structural Validation”A conforming validator MUST enforce the following rules:
- Entry exists. The
entryvalue MUST reference an existing key innodes. - Edge references. Every edge
fromandtovalue MUST reference an existing key innodes. - Reachability. All nodes MUST be reachable from
entryvia edges (BFS traversal from entry, following all outgoing edges regardless of conditions). - Self-loops. An edge where
fromequalstoMUST havemax_iterationsset. A self-loop withoutmax_iterationsis invalid. - Unbounded cycles. A cycle in the graph where no edge in the cycle has
max_iterationsis invalid. A conforming validator MUST detect and reject unbounded cycles. The detection algorithm: remove all edges that havemax_iterations(and all self-loops), then check the remaining subgraph for cycles using DFS. - Skill references. All skill IDs referenced in node
skillsarrays SHOULD exist in the executor’s skill registry. Unknown skills are warnings, not errors. - Inline skill constraint. Every entry in
skillsMUST provide at least one ofinstructionormcp. An inline skill with neither is invalid.
Error Codes
Section titled “Error Codes”| Code | Description |
|---|---|
MISSING_ENTRY | entry does not reference an existing node. |
UNKNOWN_EDGE_SOURCE | An edge from references a non-existent node. |
UNKNOWN_EDGE_TARGET | An edge to references a non-existent node. |
UNREACHABLE_NODE | A node is not reachable from entry. |
SELF_LOOP | A self-loop edge lacks max_iterations. |
UNBOUNDED_CYCLE | A cycle exists with no max_iterations guard. |
UNKNOWN_SKILL | A node references a skill not in the registry. |
INVALID_INLINE_SKILL | An inline skill provides neither instruction nor mcp. |
SkillDefinition Object
Section titled “SkillDefinition Object”Inline skill definitions declared in the workflow’s skills block. These are scoped to the workflow and available to any node that references them by key.
| Field | Type | Required | Description |
|---|---|---|---|
name | string | OPTIONAL | Display name. Defaults to the map key. |
description | string | OPTIONAL | What this skill provides. |
instruction | string | OPTIONAL | Natural language expertise injected into the node prompt. |
mcp | McpServerConfig | OPTIONAL | External MCP server definition. |
A valid SkillDefinition MUST provide at least one of instruction or mcp.
Inline skills cannot define tools (those require runtime code). They provide instruction-based expertise and/or external MCP server connections.
Example
Section titled “Example”skills: sre-rubric: name: SRE Postmortem Rubric instruction: | Score each postmortem dimension 1-5: - Completeness: Can you reconstruct the incident? - Root Cause Depth: "Database was slow" = 1, specific PR + mechanism = 5 - Blamelessness: No individual names as responsible parties - Action Items: Specific, assignable, measurableMinimal Example
Section titled “Minimal Example”The smallest valid workflow: one node, no edges, no routing.
id: helloname: Hello Worldentry: greetnodes: greet: name: Greet instruction: Say hello to the user.edges: []Full Example
Section titled “Full Example”A workflow with conditional routing, multiple skills, structured output, and knowledge files.
id: triagename: Alert Triagedescription: Investigate a production alert and take action based on findings.entry: gatherrules: - ./coding-standards.mdcontext: - ./ARCHITECTURE.mdskills: triage-rubric: name: Triage Severity Rubric instruction: | When assessing severity: critical = customer-facing outage, high = degraded service, medium = internal impact, low = cosmetic.
nodes: gather: name: Gather Context instruction: >- Investigate the production alert. Pull error details, stack traces, recent logs, and metrics. Check recent commits and deploys. skills: - github - sentry - datadog
investigate: name: Root Cause Analysis instruction: >- Classify each issue found as novel or duplicate. Assess severity and fix complexity. Output structured findings. skills: - github - linear - triage-rubric output: type: object properties: findings: type: array items: type: object properties: title: { type: string } severity: { type: string, enum: [critical, high, medium, low] } is_duplicate: { type: boolean } required: [title, severity, is_duplicate] novel_count: { type: number } highest_severity: { type: string } required: [findings, novel_count, highest_severity]
create_issue: name: Create Issues instruction: Create issues for novel findings. Comment on duplicates. skills: - linear - github
skip: name: Skip instruction: All findings were duplicates or low priority. Log and move on. skills: - linear
notify: name: Notify Team instruction: Send a notification summarizing the triage result. skills: - slack
edges: - from: gather to: investigate - from: investigate to: create_issue when: novel_count is greater than 0 AND highest_severity is medium or higher - from: investigate to: skip when: novel_count is 0, OR highest_severity is low - from: create_issue to: notify - from: skip to: notifyJSON Schema
Section titled “JSON Schema”The canonical JSON Schema for validating Workflow documents is available at spec.sweny.ai/schemas/workflow.json.
Reference it from a YAML file:
# $schema: https://spec.sweny.ai/schemas/workflow.jsonid: my-workflowname: My Workflow# ...