## ADDED Requirements ### Requirement: Workflow definition structure A workflow YAML SHALL have a top-level `name`, `description`, and `nodes:` array. It MAY have `provider`, `model`, `interactive`, `mutates_checkout`, `tags`. #### Scenario: Minimal valid workflow - **WHEN** a YAML file contains a `name`, `description`, and at least one node - **THEN** the loader SHALL parse it as a valid workflow definition #### Scenario: Missing name - **WHEN** a YAML file lacks a `name` field - **THEN** the loader SHALL reject it with a validation error ### Requirement: Seven node types The engine SHALL support exactly 7 node types, mutually exclusive per node: `command`, `prompt`, `bash`, `script`, `loop`, `approval`, `cancel`. #### Scenario: Node with exactly one mode field - **WHEN** a node has `prompt:` but no other mode field - **THEN** it SHALL be classified as a PromptNode #### Scenario: Node with multiple mode fields - **WHEN** a node has both `prompt:` and `bash:` - **THEN** the loader SHALL reject it with a mutual-exclusivity error #### Scenario: Node with no mode field - **WHEN** a node has none of the 7 mode fields - **THEN** the loader SHALL reject it ### Requirement: Common node fields All node types SHALL support `id`, `depends_on`, `when`, `trigger_rule`, `retry`, `timeout`, `output_type`, `always_run`. #### Scenario: Node id must be unique - **WHEN** two nodes in the same workflow share the same `id` - **THEN** the loader SHALL reject the workflow ### Requirement: Prompt node A PromptNode SHALL have a `prompt:` string field containing the AI prompt text. #### Scenario: Empty prompt rejected - **WHEN** a node has `prompt: ""` - **THEN** the loader SHALL reject it ### Requirement: Bash node A BashNode SHALL have a `bash:` string field and MAY have `timeout` (ms). AI-specific fields SHALL be ignored with a warning. #### Scenario: Bash node with timeout - **WHEN** a bash node includes `timeout: 30000` - **THEN** the executor SHALL kill the subprocess after 30 seconds ### Requirement: Script node A ScriptNode SHALL have `script:` (inline or named), `runtime:` (`bun` or `uv`), MAY have `deps:` and `timeout:`. #### Scenario: Script with deps - **WHEN** a script node has `runtime: bun` and `deps: ["lodash"]` - **THEN** the executor SHALL install dependencies before running the script #### Scenario: Named script from disk - **WHEN** `script: analyze` and a file `scripts/analyze.ts` exists - **THEN** the executor SHALL load and run it ### Requirement: Loop node A LoopNode SHALL have `loop:` with `prompt`, `until`, `max_iterations`, and optional `fresh_context`, `interactive`, `gate_message`, `until_bash`. #### Scenario: Loop with completion signal - **WHEN** the AI response contains the `until` string - **THEN** the loop SHALL stop and the node SHALL complete #### Scenario: Loop exceeds max_iterations - **WHEN** the loop reaches `max_iterations` without the completion signal - **THEN** the node SHALL fail ### Requirement: Cancel node A CancelNode SHALL have a `cancel:` string containing a reason. It SHALL terminate the workflow run. #### Scenario: Cancel terminates workflow - **WHEN** a cancel node executes - **THEN** the workflow SHALL be marked as cancelled with the cancel reason