Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.sirenspec.dev/llms.txt

Use this file to discover all available pages before exploring further.

File Structure

A SirenSpec workflow is a YAML file with a top-level mapping. Three fields are required; the rest are optional.
version: "0.1"         # required
agents: {}             # required
nodes: {}              # required
edges: []              # optional
input: {}              # optional
state: {}              # optional
guardrails: []         # optional

version

Required. The schema version string. Currently only "0.1" is supported.
version: "0.1"

agents

Required. A mapping of agent IDs to agent definitions. Each agent wraps an LLM with a system prompt.
agents:
  assistant:
    model: "openai:gpt-4o-mini"
    system: "You are a helpful assistant."
    guardrails: ["injection", "length"]   # optional
FieldRequiredTypeDescription
modelYesstringProvider URI — provider:model format.
systemYesstringSystem prompt sent to the model.
guardrailsNolist of stringsAgent-level guardrail override. Replaces the workflow-level list.
See Agents for full agent documentation and Providers for valid model URIs.

nodes

Required. A mapping of node IDs to node definitions. Two node types are supported: Agent node (default) — binds an LLM agent to an output path:
nodes:
  answer:
    agent: assistant
    writes: output.reply
Tool node — invokes an HTTP endpoint or Python callable:
nodes:
  fetch_diff:
    type: tool
    tool: http
    config:
      url: "https://api.example.com/data"
      method: GET
    output_key: data

Agent node fields

FieldRequiredTypeDescription
agentYesstringAgent ID from the agents map.
writesYesstringDot-notation context path where the agent’s response is stored.
retryNoobjectPer-node retry policy. Overrides defaults.retry. See Retry Policies.
on_failureNoobjectFailure action when retries are exhausted. Overrides defaults.on_failure. See Retry Policies.
See Tool Nodes for the full tool node field reference and adapter documentation.

Context paths

The writes field uses dot-notation to specify where output is written in the workflow context:
Path prefixDescription
output.*Final output — included in the trace’s output field.
working.*Intermediate state — readable by downstream nodes but not in final output.
Examples:
  • output.reply — final response available in the JSON trace.
  • working.intent — intermediate classification readable by the next node.
  • working.triage.intent — nested intermediate state.

edges

Optional. A list of directed edges connecting nodes. If omitted, all nodes are treated as roots and execute in definition order.
edges:
  - from: classify
    to: reply

  - from: triage
    to: handle_refund
    when: working.triage.intent == "refund"

  - from: triage
    to: handle_general
    when: working.triage.intent == "general"
FieldRequiredTypeDescription
fromYesstringSource node ID.
toYesstringDestination node ID.
whenNostringPython expression evaluated after the source node completes.

when expressions

The when field enables conditional branching. The expression is evaluated after the source node writes its output to the context. Available names in when expressions:
NameTypeDescription
workingobjectThe current working context (dot-access).
outputobjectThe current output context (dot-access).
true / false / nullliteralsYAML boolean/null literals.
No Python built-ins or imports are available — the namespace is intentionally restricted.
# Activate handle_refund only if the triage agent classified the intent as "refund"
edges:
  - from: triage
    to: handle_refund
    when: working.triage.intent == "refund"
If a when expression raises an error (missing key, syntax error, type mismatch), it is treated as false and the edge is not traversed. Edges without when are always traversed.

input

Optional. A static input message for the first node. Can be overridden at runtime with the --input CLI flag.
input:
  message: "What is the capital of France?"
FieldRequiredTypeDescription
messageNostringStatic user message passed to the first (root) node.
If neither input.message nor --input is provided, the CLI exits with an error.

state

Optional. Initial state to seed the workflow context before execution begins.
state:
  working:
    seed: "initial value"
  output:
    default_reply: "No answer yet."
State is merged into the corresponding working and output context buckets at startup. Nodes can read and overwrite these values during execution.

defaults

Optional. Workflow-wide defaults for retry and failure handling, inherited by all nodes that do not specify their own.
defaults:
  retry:
    max_attempts: 3
    backoff: exponential
    base_delay: 1.0
    on: [429, network_error]
  on_failure:
    action: abort
See Retry Policies for the full field reference.

guardrails

Optional. A list of guardrail names applied globally to all agents. Defaults to ["injection"] if omitted.
guardrails:
  - injection
  - length
ValueDescription
injectionDetects prompt-injection patterns. Applied by default.
lengthTruncates output to 4000 characters.
An empty list ([]) disables all guardrails for the entire workflow. Individual agents can override this with their own guardrails field. See Guardrails for full details.

Complete Example

version: "0.1"

agents:
  triage_agent:
    model: "openai:gpt-4o-mini"
    system: |
      Classify the user's message as either a refund request or a general enquiry.
      Reply with ONLY one word — either "refund" or "general" — and nothing else.

  refund_handler:
    model: "openai:gpt-4o-mini"
    system: |
      You are a customer-support specialist handling refund requests.
      Acknowledge the request warmly and outline the refund process in two or three sentences.

  general_handler:
    model: "openai:gpt-4o-mini"
    system: |
      You are a helpful customer-support agent.
      Answer the user's question clearly and concisely in two or three sentences.

nodes:
  triage:
    agent: triage_agent
    writes: working.triage.intent

  handle_refund:
    agent: refund_handler
    writes: output.reply

  handle_general:
    agent: general_handler
    writes: output.reply

edges:
  - from: triage
    to: handle_refund
    when: working.triage.intent == "refund"

  - from: triage
    to: handle_general
    when: working.triage.intent == "general"

guardrails:
  - injection
  - length