Workflow Schema Reference
Builder-grade reference for authoring your own workflow: one table per YAML file — every field with type, default, and meaning — plus the wiring map that shows how the files reference each other and with what cardinality. Matches the engine's Pydantic models field-for-field; the models are the final authority.
Conventions: ... = required (missing file/value fails) · = value = default · list[X] = YAML list · dict[k, X] = YAML
mapping. Kind IDs and assistant IDs are DICT KEYS (no id field
inside). Enums reject anything unstated. Plain-words companion:
Modular Workflows.
The builder's wiring map
How the files interact. Every arrow below is a reference the
loader enforces — a dangling ID fails the load and names the
missing reference. Cardinality on each edge: 1 = exactly one ·
1..* = one or more · 0..* = zero or more · 0..1 = zero or one.
Read it as a builder:
- stages.yaml is the hub. It is the only file that fans out to modes, skills, node types, appendages, kinds, and intents — get stages right and most resolution errors disappear.
- node_types.yaml is the graph. Types reference each other
(parent / child / depends_on) and must stay acyclic; their
transitions pull in gates; their
rules:pull in governance. - gates reach back into skills (
score_skill), and governance reaches out through connections. Those are the only cross-file chains besides stages. - A session binds it all at runtime: one stage, one mode, one or more skills, one intent, one node instance, at most one assistant — checked against checklists and proven by tools.
File index (22 YAML files + governance)
| # | File | Required? | Role |
|---|---|---|---|
| 1 | workflow.yaml | required | meta + defaults |
| 2 | modes.yaml | required (≥1) | rules per station |
| 3 | intents.yaml | default [] | goals of a sitting |
| 4 | node_types.yaml | required (≥1) | graph model + lifecycles |
| 5 | stages.yaml | required (≥1) | stations |
| 6 | skills.yaml | required (≥1) | trades |
| 7 | gates.yaml | default [] | transition checks |
| 8 | guardrails.yaml | defaulted | per-mode limits |
| 9 | structure.yaml | defaulted | file-routing kinds |
| 10 | tools.yaml | default [] | appendage: commands |
| 11 | mcps.yaml | default [] | appendage: MCP servers |
| 12 | apis.yaml | default [] | appendage: HTTP APIs |
| 13 | clis.yaml | default [] | appendage: CLIs |
| 14 | sdks.yaml | default [] | appendage: SDKs |
| 15 | hooks.yaml | defaulted | 7 lifecycle hooks |
| 16 | traceability.yaml | defaulted | TTL, snapshots, metrics |
| 17 | connections.yaml | defaulted | pack transports |
| 18 | assistants.yaml | default {} | declared workers |
| 19 | checklists.yaml | lenient | scoring rubrics |
| 20 | constraints.yaml | default null | size limits |
| 21 | verification.yaml | default [] | proof tools |
| 22 | git.yaml | defaulted | branch policy (.vyasa/git.yaml) |
| + | governance.yaml | scaffolded per project | your standing laws (user-owned) |
Rule of thumb: the five required files make a workflow LOAD; gates, governance, and verification make it GOVERN. Missing defaulted files fall through to safe defaults.
1. workflow.yaml — meta + defaults
| Field | Type | Default | Meaning |
|---|---|---|---|
| id | str | ... | unique workflow identifier |
| label | str | ... | human-readable name |
| description | str | "" | what this workflow does |
| enabled | bool | true | false blocks EVERY session start |
| version | str | "1.0" | semantic version |
| tier | lite|standard|full | standard | determines which features are active |
| structure_pack | str? | null | default kind pack |
| default_flow | simple|scoring | simple | session flow unless --flow overrides |
| work_style | str | "conservative" | suggestion only — sessions still require an explicit style |
| work_styles | dict[str, str] | {} | behavioral prose per style ID |
| context_budget_tokens | int ≥1? | null | agent-context cap; null = unlimited |
| session_mode | content|worktree | content | where output lands (staging mirror vs detached worktree) |
Connects: root — nothing outbound; everything reads its defaults.
2. modes.yaml — rules per station
| Field | Type | Default | Meaning |
|---|---|---|---|
| id | str | ... | unique mode identifier |
| label | str | ... | human-readable name |
| description | str | "" | what this mode does |
| default_ttl_hours | int 1–24 | 2 | session expiry → lock expiry |
| is_advisory | bool | false | prompt-level read-only |
| read_only | bool | false | hook/guard-ENFORCED read-only (strictly stronger) |
| token_budget | int ≥1000 | 100000 | per-session token cap |
Connects: referenced by stages (mode: — exactly 1); selects
guardrail patterns + scope generation.
3. intents.yaml — goals of a sitting
| Field | Type | Default | Meaning |
|---|---|---|---|
| id | str | ... | unique intent identifier |
| label | str | ... | human-readable name |
| description | str | "" | what this intent achieves |
| approach | str | "" | how — method / strategy |
Connects: sessions declare 1 intent (--intent, validated);
stages suggest 0..1 (default_intent).
4. node_types.yaml — the graph model
| Field | Type | Default | Meaning |
|---|---|---|---|
| id | str | ... | unique type identifier |
| label | str | ... | human-readable name |
| description | str | "" | what this type represents |
| enabled | bool | true | false = instances cannot be created |
| id_pattern | regex str | ".*" | instance-ID gate (^US-\d+$ style) |
| headers | str[] | [] | required markdown sections (default level 2) |
| header_levels | dict[str, 1–6] | {} | per-header overrides; keys MUST be in headers |
| versionable | bool | false | archive old versions |
| relations | parent? / child[] / depends_on[] | {} | type IDs; must stay acyclic (DAG) |
| lifecycle | statuses[] ≥1 + transitions[] | ... | statuses + moves |
| sub_nodes | enabled (false) / decomposition_strategy[] / max_sessions_per_node (d.5) / max_tokens_per_session (d.50000) / auto_generate | disabled | decomposition |
| template | str | "" | starting markdown |
| rules | str[] | [] | governance rule IDs for this type ONLY; empty = none; unknown ID fails closed |
| output_schema | OutputFieldConfig[] | [] | id + type (text|number|bool|list|object, d.text) + required (d.false) + description |
| max_iterations | int ≥1 | 3 | validator retry bound |
| on_max_iterations | accept_with_warning|block|escalate | escalate | retry exhaustion behavior |
StatusTransition (inside lifecycle):
| Field | Type | Default | Meaning |
|---|---|---|---|
| from_status | str | ... | move origin |
| to_status | str | ... | move destination |
| gates | str[] | [] | gate IDs — ALL must pass |
| on_fail_status | str? | null | unset = hold position |
Connects: types ↔ types (relations, DAG-enforced); transitions →
gates (0..* each, ALL evaluated); rules: → governance IDs;
stages produce/consume types; sessions target instances.
5. stages.yaml — stations
| Field | Type | Default | Meaning |
|---|---|---|---|
| id | str | ... | unique stage identifier |
| label | str | ... | human-readable name |
| description | str | "" | purpose |
| enabled | bool | true | false hides from session start |
| order | int ≥1 | ... | feed order (guides, never exclusive) |
| mode | str | ... | mode ID — exactly 1, must resolve |
| skills | str[] | ... (≥1) | skill IDs — ALL must resolve |
| default_intent | str? | null | suggested intent |
| produces / consumes | str[] | [] | node-type IDs created / required |
| tools / mcps / apis / clis | str[] | [] | appendage IDs available per session |
| sdk | str[] | [] | SDK IDs per session |
| allowed_kinds | str[] | [] | producible kinds (empty = all) |
Connects: the hub — mode (1), skills (1..), types (0..), appendages (0..), kinds (0..), intent (0..1). Every ID validated at load.
6. skills.yaml — trades
| Field | Type | Default | Meaning |
|---|---|---|---|
| id | str | ... | unique skill identifier |
| label | str | ... | human-readable name |
| type | productivity|governance|domain | "productivity" | descriptive category |
| enabled | bool | true | false = unselectable |
| description | str | "" | what it does |
| capabilities | str[] | [] | capability tags |
| is_advisory | bool | false | review-only skill |
| instructions | markdown? | null | rendered to .vyasa/skills/{id}.md at scaffold; referenced, never inlined |
Connects: stages require 1..* skills; sessions pick 1..*;
gates (score_skill) reference exactly 1 validator skill.
7. gates.yaml — transition checks
| Field | Type | Default | Meaning |
|---|---|---|---|
| id | str | ... | unique gate identifier |
| label | str | ... | human-readable name |
| description | str | "" | what this gate verifies |
| enabled | bool | true | false = skipped (passes) |
| type | schema|dependency|governance|approval|score | "schema" | descriptive category |
| condition | ConditionConfig | ... | structured condition (below) |
| message | str | "Gate condition not met" | failure message |
| on_fail | block|warn|notify|auto | "block" | failure behavior |
| notifications | NotificationConfig[] | [] | platform (slack|teams|discord|email|jira|linear|webhook|pagerduty) + channel? + on (fail|pass|always, d.fail) + template? |
The 12 condition operators — anything else fails at parse; each needs its companions or the load fails:
| Operator | Required companions |
|---|---|
| ALL_HAVE_SECTION / ANY_HAVE_SECTION | section |
| FIELD_EXISTS / FIELD_EQUALS | field (+value) |
| COUNT_AT_LEAST | min_count (≥1) |
| NO_VIOLATIONS | severity |
| DEPENDENCY_APPROVED | — |
| SCORE_ABOVE | score_min (0–100) + score_skill |
| PARENT_COMPLETE | — |
| FILES_EXIST | — |
| FILES_MATCH | field (glob) + value (regex) |
| SECRET_SCAN | — |
Optional on conditions: source (stage_outputs|previous_stage|all)
and node_type filter.
Connects: transitions reference 0..* gates; SCORE_ABOVE →
exactly 1 validator skill; NO_VIOLATIONS reads the violations
store; SECRET_SCAN reads secret_patterns from governance.
8. guardrails.yaml — per-mode limits
| Field | Type | Default | Meaning |
|---|---|---|---|
| patterns | dict[mode-id, write[] / read[] / hidden[] globs] | {} | EMPTY = no restrictions (permissive, visible) |
| headers | dict[type-id, str[]] | {} | required headers per node type |
| extraction | mode + node_type + strategy (full|headers-only|none|[headers]) | [] | content-pull portion control |
Connects: keyed by modes (patterns) and node types (headers, extraction); generates each session's scope card.
9. structure.yaml — kinds (file-routing truth)
Kind ID is the DICT KEY (no id field inside):
| Field | Type | Default | Meaning |
|---|---|---|---|
| label / description | str | "" | identity |
| enabled | bool | true | false = not a valid output target |
| path | str template | ... | final path pattern (src/{module}/controllers/{name}.py) |
| naming_convention | str | "{name}" | {node_id}.md, {name}.py style |
| template | str | "" | initial file content |
| variables | dict[str, str] | {} | default values (session kind_variables override) |
| headers / header_levels | str[] / dict | [] / {} | required sections + 1–6 overrides |
| validation | ValidationRule[] | [] | required_section|required_field|min_length|pattern_match — unknown types fail closed |
Connects: stages scope via allowed_kinds (0..*); sessions
record kind + variables; apply routes by kinds.
10–14. Appendages — tools.yaml / mcps.yaml / apis.yaml / clis.yaml / sdks.yaml
Worker-facing capabilities, scoped per session by when. All five
share the shape:
| Field | Type | Default | Meaning |
|---|---|---|---|
| id | str | ... | unique appendage identifier |
| enabled | bool | true | false = unavailable |
| description | str | "" | what it provides |
| when | scoping | [] | which sessions/stages may use it |
| transport (below) | per file | ... | how the worker reaches it |
Per-file transport:
| File | Transport fields |
|---|---|
| tools.yaml | command + args[] |
| mcps.yaml | endpoint |
| apis.yaml | endpoint + method + auth? |
| clis.yaml | command |
| sdks.yaml | language + package |
Connects: stages scope 0..* of each; every referenced ID must resolve. These EXTERNAL capabilities are not Vyasa's own CLI/API/ MCP surfaces — separate vocabularies, kept separate on purpose.
15. hooks.yaml — 7 lifecycle hooks
| Hook | Fires | Purpose |
|---|---|---|
| pre_tool_use | before every worker tool call | real-time interdiction |
| pre_session | before session start | setup |
| post_session | after session end | teardown / archive |
| pre_apply | before promotion | last check |
| post_apply | after promotion | notify / record |
| pre_gate | before gate evaluation | setup |
| post_gate | after gate decision | notify |
Each is a script path (null = unhooked). Rules live in
.vyasa/hooks/rules.yaml — missing/malformed rules file FAILS
CLOSED (every call denied).
16. traceability.yaml — memory policy
| Field | Type | Default | Meaning |
|---|---|---|---|
| session_ttl_hours | int | defaulted | session expiry → lock expiry |
| snapshot_enabled | bool | defaulted | rollback snapshots on/off |
| metrics_enabled | bool | defaulted | token/duration stats on/off |
| retention | dict (sessions, violations, trace, snapshots) | defaulted | per-record purge counts |
Connects: consumed by session lifecycle, apply, end-metrics, cleanup.
17. governance.yaml — your standing laws (scaffolded per project, user-owned)
Scaffolded into your project (OWASP Agentic Top 10 starter); the runtime never reads templates for it.
| Block | Fields |
|---|---|
rules[] | id (req) / name (d."") / severity (error blocks, warn advises; d.error) / operator (gate DSL) / field? (glob) / value? (regex) / description (d."") / enabled (d.true — false = kept, not enforced) |
secret_patterns[] | id + regex — feeds SECRET_SCAN |
linked_rules[] | source (connection id) + local (path under .vyasa/third-party/governance/) |
pack | id / version metadata dict |
Connects: node types opt in by rule ID (empty = none; unknown ID fails closed); linked packs arrive through connections.
18. connections.yaml — transports that fetch packs
| Field | Type | Default | Meaning |
|---|---|---|---|
| id | str | ... | unique connection identifier |
| direction | inbound|outbound | ... | packs in vs telemetry out |
| protocol | 6-valued | ... | git|file SHIPPED; sftp|ftp|ems|http are declared stubs (fail loud) |
| location | str | ... | endpoint (git URL, dir, URI…) |
| ref | str? | null | PINNED git ref (tag/commit — never main) |
| fingerprint_sha256 | str? | null | expected payload hash — mismatch fails closed |
| verify_signature | bool | true | payload signature check |
| verify_key_id | str? | null | keyring entry |
| encryption | tls|ssh|none | "tls" | transport policy |
| enforcement | strict|advisory | "strict" | strict blocks gates on violation; advisory warns |
| parse | str? | null | payload schema tag (e.g. rule-pack-v1) |
| description | str | "" | what this connection carries |
Connects: governance linked_rules.source → exactly 1 connection
per pack; managed via connections list/add/remove and
governance use/fetch/update/remove.
19. assistants.yaml — declared workers
DICT keyed by assistant id (NOT a list — a - id: list fails to parse):
| Field | Type | Default | Meaning |
|---|---|---|---|
| command / args / model | str / str[] / str? | — | launch line + model injection |
| config_files | str[] | [] | editor configs generated at scaffold |
| env | dict[str, str] | {} | ${VAR} resolved from .env at dispatch (secrets never in YAML) |
| hook_script_path | str? | null | pre-tool-use hook |
| sandbox_mode | advisory|hooks|container | — | enforcement level |
| system_prompt_file_flag / system_prompt_env | str? / str? | null | workspace-context injection (flag + path, env var, or CWD discovery) |
| name_session_flag | str? | null | worker-session naming |
| resume_command | str | — | {assistant_session_name} resume template |
| session_id_query / session_list_* | str? | null | live-session tracking |
| active | bool | false | at most 1 project default (assistant set) |
Connects: sessions bind 0..1 assistant; assistant use launches;
resume re-engages. Built-in fixture entries: claude-code, pi,
aider, open-interpreter, openclaw, goose, opencode, codex.
20. checklists.yaml — scoring rubrics
A checklists: list of dicts (no Pydantic class — dict
convention; unloadable fails loud):
| Field | Type | Default | Meaning |
|---|---|---|---|
| id | str | ... | checklist identifier |
| name | str | ... | human-readable name |
| description | str | "" | what it grades |
| type | str | ... | category |
| criteria | list | [] | per-item rules — each becomes a score item |
Connects: scoring consumes 0..* checklists per session.
21. constraints.yaml — size limits on the definition
| Field | Type | Default | Meaning |
|---|---|---|---|
| node_types | int | null | max node types |
| max_stages | int | null | max stages |
| max_modes | int | null | max modes |
Connects: nothing references it; the engine reads it directly. null = unlimited.
22. verification.yaml — proof tools
| Field | Type | Default | Meaning |
|---|---|---|---|
| id | str | ... | tool identifier |
| enabled | bool | true | false = the authoring lever for inapplicable tools |
| category | str | ... | grouping (lint / type / test…) |
| parse | str? | null | output parser tag |
| description | str | "" | what it proves |
| command | str | ... | shell command; {target} → project root; 120s timeout |
Connects: sessions run 0..* tools for the Proof Pack; failures feed gates and scoring.
23. git.yaml — branch policy (.vyasa/git.yaml, project-level)
| Field | Type | Default | Meaning |
|---|---|---|---|
| base_branch | str | "main" | worktree base |
| work_branch | str | "dev" | integration branch |
| commit_target | current_branch|work_branch | "current_branch" | where applies commit |
| state_commits | legacy flag | — | superseded; retained so old files parse |
| state_tracking | bool | true | timeline kill-switch (support/rollback only) |
Sandbox (engine model — no file of its own): image, hooks_enabled, enforce, timeout_seconds, network, memory_limit_mb, heartbeat_timeout_seconds (d.120 → lock preemption).
Load-time rules (exact)
Every reference must resolve or the load fails and names it:
| From | To | Cardinality |
|---|---|---|
| stage | mode | exactly 1 |
| stage | skills | 1..* (each) |
| stage | node types (produces + consumes) | 0..* (each) |
| stage | tool/mcp/api/cli/sdk | 0..* (each) |
| stage | kinds (allowed_kinds) | 0..* (each) |
| stage | default_intent | 0..1 |
| node type | parent / child / depends_on | 0..* each (DAG — cycles fail) |
| transition | gates | 0..*, ALL evaluated |
| gate (SCORE_ABOVE) | score_skill | exactly 1 |
node type rules: | governance rule IDs | 0..*; unknown ID fails CLOSED |
governance linked_rules | connection | exactly 1 per pack |
Plus fail-closed model validators: SCORE_ABOVE needs score_min + score_skill · COUNT_AT_LEAST needs min_count · section operators need section · FIELD_EQUALS needs field + value · NO_VIOLATIONS needs severity · FILES_MATCH needs field + value · header_levels keys ⊆ headers · unknown operator strings rejected at parse.