Routing

A state must have EXACTLY ONE of: on, transitions, or approval. Binary (on:) maps exit codes. Named (transitions:) maps outcome keys. Approval prompts the user.

Binary Routing (on:)

Maps exit codes to next states. Code 0 = PASSED, non-zero = FAILED.

on:
  PASSED: next_state      # exit code 0
  FAILED: error_state     # exit code non-zero

Use for: script, command states

NOT suitable for agents — Copilot agents always exit code 0.

Named Routing (transitions:)

Maps outcome keys (from last line of stdout) to next states. The agent/script/command must print the key as its last line.

transitions:
  approve: merge_state
  reject: fix_state
  blocked: done

A reserved default key may be provided as a catch-all mapping that will be used when the state’s reported outcome does not match any explicit key. When default is present the engine routes to that state; when absent an unmapped outcome throws an error (fail-fast).

Note: state runners (agent/script/command) return only their reported outcome key — they must not attempt to resolve routing. The Engine (thin core) is responsible for mapping outcome keys to states and will apply transitions.default as a catch-all when present. This keeps routing centralized and deterministic.

transitions:
  approve: merge_state
  reject: fix_state
  default: done   # catch-all for unknown outcomes

Use for: agent, script, command states

MUST use for agents — this is the correct routing mechanism.

Manual Approval (approval:)

Pauses execution and prompts the user for yes/no. Approval behavior can be customized via an optional workflow resolver configuration file: .raili/<workflow>/config.json (see documentation/approval.md). The config allows tuning approval timeouts so long-running prompts or automated resolvers do not block indefinitely.

approval:
  question: "Proceed with deployment?"
  notify: "alert.sh"      # Optional: run before prompt
  PASSED: deploy          # user approves (Enter)
  FAILED: rework          # user rejects (type anything)

Use for: any state type

Timeout behavior: If approval.timeout is set in .raili/<workflow>/config.json (seconds), Raili enforces that timeout for both interactive prompts and approval resolver executions. When the timeout is exceeded the run fails fast with the message: Approval prompt timeout exceeded.

Terminal State

No on, transitions, approval, or continue defined. Workflow stops here.

done:
  type: engine
  notify: "echo 'Complete'"

Error State

Raili supports an optional top-level error: field that names a state to which the engine will deterministically route if an unhandled exception escapes the normal state handler/routing logic.

Declaration:

initial: start
error: error_state    # ← routes here on unexpected failure

states:
  start:
    type: agent
    agent: main_logic
    transitions:
      ready: done

  error_state:
    type: engine
    notify: "alert.sh 'Workflow failed'"

Key points:

Why use an error state?

Important Notes

Unconditional Routing (continue:)

Raili supports an unconditional routing option continue: that, when present, will route to the specified state immediately after the state’s handler phase, regardless of the outcome or exit code. This is useful when a state performs side-effectful work but the next step should not depend on its result.

Key points:

Example usage:

states:
  build:
    type: script
    script: run_build
    continue: test

  analyze:
    type: agent
    agent: analyzer
    continue: review

Use continue sparingly; when you actually need branching based on results prefer on: or transitions: to keep workflows explicit and deterministic.