States
States are the fundamental building blocks of FlowState workflows. Each state invokes a tool and determines what happens next based on the result.
State Anatomy
Section titled “State Anatomy”A complete state definition:
state-name: tool: bash # Required: which tool to invoke arguments: # Tool-specific arguments command: echo "Hello" output: var(result) # Optional: capture stdout next: another-state # Optional: next state on success on-error: # Optional: error handlers 1: handle-error _: fallback goto: # For switch tool only "true": path-a "false": path-b _: default-pathRequired Fields
Section titled “Required Fields”The tool to execute. Must be one of the built-in tools or a registered custom tool.
my-state: tool: bash arguments: command: ls -laarguments
Section titled “arguments”A key-value map of arguments passed to the tool. Required arguments depend on the tool:
| Tool | Required Arguments |
|---|---|
bash | command |
claude | prompt |
claude-code | prompt |
codex | prompt |
gemini | prompt |
ask-user | question |
get-gh-issue | issue-number |
parallel | tasks |
sub-flow | workflow |
pause | reason |
switch | value |
Optional Fields
Section titled “Optional Fields”The state to transition to after successful execution. If omitted, the workflow ends after this state.
step-1: tool: bash arguments: command: echo "Step 1" next: step-2
step-2: tool: bash arguments: command: echo "Step 2" # No next - workflow ends hereoutput
Section titled “output”Capture the tool’s stdout to a variable or file.
# Capture to variableget-version: tool: bash arguments: command: cat VERSION output: var(app_version)
# Capture to filesave-logs: tool: bash arguments: command: docker logs myapp output: file(./logs/app.log)See Variables for output capture details.
on-error
Section titled “on-error”Map exit codes to error-handling states. The special key _ serves as a wildcard matching any unhandled exit code.
risky-operation: tool: bash arguments: command: ./might-fail.sh on-error: 1: handle-permission-error 2: handle-not-found _: handle-unknown-error next: success-stateSee Error Handling for patterns and best practices.
Used exclusively with the switch tool for conditional branching. Maps evaluated values to target states.
check-environment: tool: switch arguments: value: "{{ env }}" goto: production: deploy-prod staging: deploy-staging _: deploy-devState Transitions
Section titled “State Transitions”Linear Flow
Section titled “Linear Flow”Most workflows follow a linear path through states:
start-at: step-1
states: step-1: tool: bash arguments: command: echo "First" next: step-2
step-2: tool: bash arguments: command: echo "Second" next: step-3
step-3: tool: bash arguments: command: echo "Third"Conditional Branching
Section titled “Conditional Branching”Use the switch tool with goto for conditional paths:
check-status: tool: bash arguments: command: cat ./status.txt output: var(status) next: branch
branch: tool: switch arguments: value: "{{ status }}" goto: ready: proceed pending: wait-more _: handle-unknown
proceed: tool: bash arguments: command: echo "Proceeding..."
wait-more: tool: pause arguments: reason: "Waiting for status to change" next: check-statusError Recovery
Section titled “Error Recovery”Error states can rejoin the main flow or terminate:
fetch-data: tool: bash arguments: command: curl https://api.example.com/data output: var(data) on-error: _: retry-fetch next: process-data
retry-fetch: tool: bash arguments: command: sleep 5 next: fetch-data # Retry the original operation
process-data: tool: bash arguments: command: 'echo "{{ data }}"'Terminal States
Section titled “Terminal States”A state without next is terminal - the workflow ends after it executes. This applies to success and error handlers alike:
# Normal terminal statefinal-step: tool: bash arguments: command: echo "Workflow complete" # No next - workflow ends
# Error terminal statefatal-error: tool: bash arguments: command: echo "Unrecoverable error" >&2 # No next - workflow ends with whatever exit code this producesState Naming Conventions
Section titled “State Naming Conventions”State names should be:
- Descriptive:
fetch-user-datanotstep-1 - Kebab-case:
validate-inputnotvalidateInput - Action-oriented:
send-notificationnotnotification
Reserved patterns to avoid:
- Names containing
/(used for subflow state paths) - Names starting with
_(may have special meaning in future versions)