Skip to content

SOUL.yaml Reference

One SOUL.yaml file fully defines an agent — its identity, trigger, model, tools, memory, and behavior — and Soulacy hot-loads it the moment you save.

Quick Start

agents/assistant/SOUL.yaml
id: assistant
name: Assistant
description: General-purpose helper

trigger: channel
channels: [http]

llm:
  provider: openai
  model: gpt-4o-mini
  temperature: 0.2

system_prompt: |
  You are concise, helpful, and careful.

max_turns: 6
enabled: true

Validate any file before deploying:

sy agent validate path/to/SOUL.yaml          # human-readable
sy agent validate path/to/SOUL.yaml --json   # machine-readable

Annotated Complete Example

# ── Identity ──────────────────────────────────────────────
id: research-writer          # stable runtime ID: URLs, logs, agent__<id> tool names
name: Research Writer        # display name
description: Researches topics and writes a brief.   # shown to peer agents too
version: "1.0.0"
tags: [research, writing]
labels: { owner: ops }

# ── Trigger ───────────────────────────────────────────────
trigger: channel             # primary start mode: channel | cron | oneshot | webhook | internal
channels: [http, telegram]   # channel adapter IDs this agent serves
surfaces: [chat, telegram]   # optional UI/invocation surfaces; empty = derived

# ── Model ─────────────────────────────────────────────────
llm:
  provider: anthropic
  model: claude-sonnet-4-6
  temperature: 0.2
  max_tokens: 2048
  allowed_providers: [anthropic]   # refuse to run on any other provider
  tool_choice: auto                # auto | none | required | <tool name> (turn 1 only)

system_prompt: |
  Produce a short brief. Cite sources when available.

# ── Tools ─────────────────────────────────────────────────
tools:                       # agent-local Python tools — see Agent Tools page
  - name: summarize_csv
    description: Summarize a CSV file and return compact JSON.
    python_file: tools/summarize_csv.py
    timeout: 2m
    parameters:
      type: object
      properties:
        path: { type: string }
      required: [path]

builtins: [web_search, kb_search]  # restrict Go-native built-ins; [] = none; absent = default
knowledge: [company-docs]          # KBs searchable via kb_search
skills: [csv-analysis]             # Agent Skills (or ["*"] for all installed)
agents: [critic]                   # peer agents exposed as agent__critic
mcp_servers: [github]              # MCP allowlist by server
mcp_tools: [mcp__github__search_repositories]   # …or by full tool name
capabilities: [system]             # SEC-3: grant privileged OS tools (shell_exec, write_file, …)
system_tools: false                # legacy alias for capabilities: [system]
env: [GITHUB_TOKEN]                # SEC-5: extra host env var NAMES passed to tool subprocesses
confirm_tools: [write_file, shell_exec]   # pause for approval; ["*"] = all built-ins

# ── Memory ────────────────────────────────────────────────
memory:
  read_scopes: [agent, session]
  write_scopes: [agent]
  max_tokens: 2000

brain_memory:                # long-term memory layers
  episodic:   { enabled: true, max_inject: 5 }
  semantic:   { enabled: true, max_inject: 5 }
  procedural: { enabled: true, auto_update: false }

# ── Reasoning loop ────────────────────────────────────────
reasoning:
  strategy: react            # auto | react | plan_execute | flow | custom name
  max_steps: 6
  step_timeout: 30s
  total_timeout: 3m

# ── Schedule (cron / oneshot triggers) ────────────────────
schedule:
  cron: "0 8 * * *"
  run_missed_on_startup: true
  missed_startup_window: 24h
  output: { channel: telegram, to: "123456789", template: "{reply}" }

notify_on_failure:
  channel: telegram
  to: "123456789"
  include_error: true

security:
  passphrase: "change-me"

# ── Runtime ───────────────────────────────────────────────
max_turns: 10
stream_reply: true
enabled: true
run_timeout: 10m             # whole-run wall-clock cap (default 15m)

Identity

Field Type Notes
id string Required stable runtime ID. Avoid whitespace and path separators.
name string Human-readable display name.
description string Also shown to other agents when this agent is exposed as a peer tool.
version, tags, labels misc Optional metadata for packaging and filtering.

Trigger and Channels

trigger is the agent's primary start mode:

Trigger Meaning
channel Inbound channel traffic (HTTP, Telegram, Slack, Discord, WhatsApp).
cron Run on a cron schedule. Requires schedule.cron.
oneshot Run once at schedule.at.
webhook Activated by an HTTP POST to the agent's endpoint.
internal Callable by peer agents, not normally user-facing.

channels binds the agent to channel adapter IDs. Platform credentials and inbound routing live in config.yaml — the agent only declares which adapters it serves.

surfaces controls where the same agent is visible or invokable. Leave it empty for Soulacy to derive a conservative default from trigger and channels; set it explicitly when one agent should serve multiple interfaces. This is the preferred way to make a scheduled agent interactive without duplicating it:

trigger: cron
channels: [telegram, slack]
surfaces: [schedule, chat, telegram, slack]
schedule:
  cron: "0 7 * * *"
  output: { channel: telegram, to: "@daily_brief" }

With that shape, the scheduler fires the agent, the Chat picker can test it, and mapped Telegram/Slack bots can route inbound messages to the same agent. The channel credentials and bot mappings still live under config.yaml.

LLM Block

Field Notes
provider / model Model selection. Empty provider falls back to llm.default_provider in config.yaml.
temperature, max_tokens Sampling temperature and output token cap.
base_url Per-agent override for OpenAI-compatible endpoints.
output_schema JSON Schema enforced on the final reply, with one repair re-prompt.
tool_choice First-turn tool policy: auto, none, required, or a specific tool name such as agent__researcher. Later turns are always auto.
allowed_providers Guard list; the engine refuses to run on any provider outside it. Recommended for cron agents on local models: allowed_providers: [ollama].

Tools, Skills, Knowledge, Peers

These are covered in depth on their own pages:

  • Agent Toolstools: (Python), builtins:, mcp_servers:/mcp_tools:, system_tools:, confirm_tools:.
  • Skillsskills: names, or ["*"] for all installed.
  • Peer Agents & Built-insagents: peer list and built-ins modes.

knowledge: lists knowledge base names this agent may search via the built-in kb_search tool. Empty means no KB catalog is injected at all.

Memory

memory controls classic session/cross-session memory injection (read_scopes, write_scopes, max_tokens).

brain_memory controls the long-term layers — see Agent Memory & Rulebooks:

Layer Keys Effect
episodic enabled, max_inject Injects past task records.
semantic enabled, max_inject Injects knowledge chunks.
procedural enabled, auto_update Injects the agent's rulebook; auto_update: true lets reasoning runs rewrite it (versioned, lockable).

Reasoning

The reasoning: block switches the agent from a single LLM call to a multi-step loop — see Reasoning Strategies:

Key Default Meaning
strategy (off) auto, react, plan_execute, flow, or a custom registered name.
max_steps 8 Hard ceiling for ReAct iterations.
max_plan_steps 6 Plan decomposition cap for plan_execute.
step_timeout 30s Per-step deadline.
total_timeout 180s Whole-task deadline.

The reasoning backend is derived automatically from llm.provider — there is nothing extra to configure.

Workflow

workflow: replaces the free-form LLM loop with a checkpointed pipeline. Two shapes are supported:

  • Linear steps (workflow.steps) — see Workflow Steps.
  • Cyclic graphs (workflow.nodes / edges / entry / max_node_executions) with conditional routing and bounded loops — see Flow Graphs. When nodes are declared they take precedence over steps.

Schedule

Cron and one-shot agents use schedule:

trigger: cron
schedule:
  cron: "0 8 * * *"
  run_missed_on_startup: true     # catch up after host downtime
  missed_startup_window: 24h      # only replay fires within this window
  output:                         # publish successful runs to a channel
    channel: telegram
    to: "123456789"
    template: "{reply}"

When run_missed_on_startup is true, Soulacy replays at most one missed fire per startup — the latest one inside missed_startup_window (default 24h) — so a long outage never floods downstream channels.

Use notify_on_failure to route errors somewhere a human will see them. Channel-triggered runs reply with errors automatically; cron and manual runs fail silently unless this block is set.

Security and Runtime

security.passphrase requires every new session to present the exact string before the agent answers anything; it is enforced in Go before the LLM runs, so no prompt injection can bypass it. security.passphrase_prompt customizes the challenge message.

Field Notes
max_turns Cap on LLM turns per run.
stream_reply Stream tokens to channels that support it.
enabled false parks the agent without deleting it.
run_timeout Whole-run wall-clock cap (5m, 30m, 1h; default 15m). Raise it for agents that call slow tools.

Tip

The GUI agent editor (Agents page) round-trips every field on this page, including the tri-state builtins modes and per-tool timeouts — you never have to hand-edit YAML unless you prefer to.