Souls Overview
Every AI agent needs an identity: who it is, how it thinks, what model powers it, and which tools it can use. In Runsight, that identity is called a soul.
A soul is a standalone YAML file that defines an agent’s persona, behavior constraints, model configuration, and tool access. Souls live in custom/souls/ and are referenced by workflow blocks using the soul_ref field. This separation keeps agent identity independent from workflow logic — the same soul can power steps across many workflows, and changing a soul’s prompt or model updates every workflow that uses it.
Why souls exist
Section titled “Why souls exist”Workflow engines typically embed agent configuration inline — the prompt, model, and temperature live inside each workflow step. This creates three problems:
- Duplication. The same “Senior Researcher” prompt appears in every workflow that uses it. A prompt revision means editing every copy.
- Coupling. Changing which model an agent uses requires editing every workflow, not just the agent’s configuration.
- No management surface. There is no central place to see all agents, compare prompts, or track which workflows depend on a given agent.
Souls solve these by extracting agent identity into a standalone, reusable artifact. A soul file is the single source of truth for how an agent behaves, regardless of where it is used.
Anatomy of a soul
Section titled “Anatomy of a soul”A soul file is a YAML document with a flat structure. Here is a complete example:
id: researcher_v1role: Senior Researchersystem_prompt: | You are a senior research analyst. Given a topic, you produce a structured report with findings, sources, and confidence levels. Always cite your sources and flag low-confidence claims.provider: openaimodel_name: gpt-4otemperature: 0.3max_tokens: 4096tools: - httpmax_tool_iterations: 5avatar_color: "#4f46e5"Required fields
Section titled “Required fields”| Field | Type | Description |
|---|---|---|
id | str | Unique identifier for this soul. Can differ from the filename. |
role | str | The agent’s role, displayed in the Soul Library UI. |
system_prompt | str | The system instructions that define behavior and constraints. |
Optional fields
Section titled “Optional fields”| Field | Type | Default | Description |
|---|---|---|---|
model_name | str | None | Model to use (e.g., gpt-4o, claude-sonnet-4). Required for execution. |
provider | str | None | Provider for the model (e.g., openai, anthropic). Required for execution. |
temperature | float | None | Sampling temperature override. |
max_tokens | int | None | Output token limit override. |
tools | list[str] | None | Tool IDs this soul can use. Must be declared in the workflow’s tools: section. |
required_tool_calls | list[str] | None | Tool function names the LLM must call before completing. |
max_tool_iterations | int | 5 | Maximum number of tool-use iterations per execution. |
avatar_color | str | None | UI color hint for displaying the soul (hex or HSL). |
How blocks reference souls
Section titled “How blocks reference souls”Workflow blocks reference souls through the soul_ref field. The value is the filename stem of the soul file in custom/souls/, not the soul’s internal id.
version: "1.0"blocks: analyze: type: linear soul_ref: researcherworkflow: name: research_pipeline entry: analyze transitions: - from: analyze to: nullIn this example, soul_ref: researcher resolves to custom/souls/researcher.yaml.
The following block types use soul_ref:
| Block Type | How it uses the soul |
|---|---|
linear | Single LLM call using the soul’s prompt and model. |
gate | Quality-gate LLM call that evaluates output against criteria. |
dispatch | Per-exit soul_ref on each exit definition — each branch gets its own soul. |
Soul discovery and resolution
Section titled “Soul discovery and resolution”When the parser processes a workflow YAML file, it resolves souls in three steps:
-
Discover external souls. The parser scans
custom/souls/for.yamlfiles and loads each into aSoulobject. Only.yamlfiles are discovered —.ymlfiles are ignored. -
Merge inline souls (if present). If the workflow YAML contains an optional
souls:section, those inline definitions are merged over the discovered external souls. When an inline soul has the same key as an external file, the inline definition wins and a warning is logged. -
Resolve
soul_refon each block. Every block’ssoul_refis looked up in the merged souls map. If the reference is not found, the parser raises aValueErrorlisting the available souls and suggesting the file to create.
Discovery runs exactly once per workflow parse, regardless of how many blocks reference souls. Multiple blocks can share the same soul_ref.
One soul per step
Section titled “One soul per step”Each workflow step is powered by exactly one soul. There are no multi-soul nodes or agent-debate patterns in the current architecture. If a workflow needs different perspectives, use separate steps with different souls connected by transitions:
version: "1.0"blocks: draft: type: linear soul_ref: writer review: type: gate soul_ref: editor eval_key: qualityworkflow: name: draft_review entry: draft transitions: - from: draft to: review - from: review to: nullTool governance
Section titled “Tool governance”Souls can declare which tools they need via the tools field. However, every tool a soul references must also appear in the workflow’s top-level tools: whitelist. This two-layer design is intentional — it gives workflow authors explicit control over which tools are available in a given workflow, regardless of what individual souls request.
id: fetcherrole: Data Fetchersystem_prompt: Fetch and summarize data from URLs.provider: openaimodel_name: gpt-4otools: - httpversion: "1.0"tools: - httpblocks: fetch: type: linear soul_ref: fetcherworkflow: name: fetch_pipeline entry: fetch transitions: - from: fetch to: nullIf the soul declares tools: [http] but the workflow does not include http in its tools: section, the parser raises an error naming both the soul and the missing tool.
Inline souls (DX shorthand)
Section titled “Inline souls (DX shorthand)”For quick prototyping, souls can be defined inline within a workflow YAML file under the souls: section. The dictionary key must match the soul’s id field:
version: "1.0"souls: drafter: id: drafter role: Quick Drafter system_prompt: Draft a short summary. model_name: gpt-4o provider: openaiblocks: draft: type: linear soul_ref: drafterworkflow: name: prototype entry: draft transitions: - from: draft to: nullInline souls are convenience sugar for iteration. The external library model (custom/souls/ files) is the primary approach — it enables the Soul Library UI, dependency tracking, and reuse across workflows.
File structure
Section titled “File structure”custom/└── souls/ ├── researcher.yaml ├── editor.yaml ├── fetcher.yaml └── summarizer.yamlSoul files are plain YAML with no wrapper structure — the fields sit at the top level of the file. There is no version: or soul: envelope; the file content maps directly to the soul definition.
What’s next
Section titled “What’s next”- Soul Files — detailed reference for every field, constraints, and validation rules
- Inline Souls — when and how to use inline definitions
- Block Types — which blocks use
soul_refand how