# Jido Composer
Build composable agent topologies in Elixir. Mix deterministic workflows (FSM)
with adaptive orchestrators (LLM) in any combination — they nest arbitrarily.
Human approval gates and durable persistence are built in, not bolted on.
## Example: Code Review pipeline
```mermaid
flowchart TD
subgraph CodeReviewPipeline [Workflow: Code Review]
direction TB
subgraph FanOut [FanOut: Parallel Review]
Lint[Lint Action]
Security[Orchestrator: Security Scanner]
Tests[Test Runner Action]
end
FanOut --> Approval[HumanNode: Approve Merge]
Approval -->|approved| Merge[Merge Action]
Approval -->|rejected| Failed[Failed]
end
```
```elixir
# An LLM-driven security scanner (orchestrator)
defmodule SecurityScanner do
use Jido.Composer.Orchestrator,
name: "security_scanner",
model: "anthropic:claude-sonnet-4-20250514",
nodes: [DependencyAuditAction, SecretScanAction, SASTAction],
system_prompt: "Scan code for security issues using all available tools."
end
# A deterministic pipeline that uses the scanner as one parallel branch
{:ok, parallel_review} = Jido.Composer.Node.FanOutNode.new(
name: "parallel_review",
branches: [
lint: LintAction,
security: SecurityScanner, # orchestrator as a branch
tests: TestRunnerAction
]
)
defmodule CodeReviewPipeline do
use Jido.Composer.Workflow,
name: "code_review",
nodes: %{
review: parallel_review,
approval: %Jido.Composer.Node.HumanNode{
name: "merge_approval",
description: "Approve merge to main",
prompt: "All checks passed. Approve merge?",
allowed_responses: [:approved, :rejected]
},
merge: MergeAction
},
transitions: %{
{:review, :ok} => :approval,
{:approval, :approved} => :merge,
{:approval, :rejected} => :failed,
{:merge, :ok} => :done,
{:_, :error} => :failed
},
initial: :review
end
# Run → suspend at human gate → checkpoint → resume later
agent = CodeReviewPipeline.new()
{agent, _directives} = CodeReviewPipeline.run(agent, %{repo: "acme/app", pr: 42})
# Persist while waiting for human
checkpoint = Jido.Composer.Checkpoint.prepare_for_checkpoint(agent)
# Later: resume with approval
{agent, _directives} = CodeReviewPipeline.cmd(agent, {:suspend_resume, %{
suspension_id: suspension.id,
response_data: %{request_id: request.id, decision: :approved, respondent: "lead@acme.com"}
}})
```
## Three Pillars
### Composable Topologies
Workflows and orchestrators both produce `Jido.Agent` modules. Agents are nodes.
Nodes compose at any depth — a workflow can contain an orchestrator as a step,
an orchestrator can invoke a workflow as a tool, and you can nest three or more
levels deep. The uniform `context → context` interface makes every node
interchangeable.
### Human-in-the-Loop
HumanNode gates pause workflows for human decisions. Tool approval gates enforce
pre-execution review on orchestrator tools. Both use the same
`ApprovalRequest`/`ApprovalResponse` protocol. Beyond HITL, the generalized
suspension system handles rate limits, async completions, and custom pause
reasons.
### Durable Persistence
Checkpoint any running or suspended flow to storage. Serialize across process
boundaries — PIDs become `ChildRef` structs, closures are stripped and
reattached on restore. Resume with idempotent semantics and top-down child
re-spawning, even for deeply nested agent hierarchies.
## Installation
```elixir
def deps do
[
{:jido_composer, "~> 0.1.0"}
]
end
```
## Control Spectrum
| Level | Pattern | Example |
| -------------------- | -------------------------------- | -------------------- |
| Fully deterministic | Workflow | ETL pipeline |
| + human gate | Workflow + HumanNode | Approval workflows |
| + adaptive step | Workflow containing Orchestrator | Code review pipeline |
| + deterministic tool | Orchestrator containing Workflow | Customer support |
| Fully adaptive | Orchestrator | Research agent |
## Quick Start: Workflow
Wire actions into a deterministic FSM pipeline:
```elixir
defmodule ETLPipeline do
use Jido.Composer.Workflow,
name: "etl_pipeline",
nodes: %{
extract: ExtractAction,
transform: TransformAction,
load: LoadAction
},
transitions: %{
{:extract, :ok} => :transform,
{:transform, :ok} => :load,
{:load, :ok} => :done,
{:_, :error} => :failed
},
initial: :extract
end
agent = ETLPipeline.new()
{:ok, result} = ETLPipeline.run_sync(agent, %{source: "customer_db"})
# result[:load][:loaded] => 2
```
```mermaid
stateDiagram-v2
[*] --> extract
extract --> transform : ok
transform --> load : ok
load --> done : ok
extract --> failed : error
transform --> failed : error
load --> failed : error
```
See [Getting Started](guides/getting-started.md) for the full walkthrough with
action definitions.
## Quick Start: Orchestrator
Give an LLM tools and let it decide what to call:
```elixir
defmodule AddAction do
use Jido.Action,
name: "add",
description: "Add two numbers",
schema: [value: [type: :float, required: true], amount: [type: :float, required: true]]
@impl true
def run(%{value: v, amount: a}, _ctx), do: {:ok, %{result: v + a}}
end
defmodule MathAssistant do
use Jido.Composer.Orchestrator,
name: "math_assistant",
model: "anthropic:claude-sonnet-4-20250514",
nodes: [AddAction],
system_prompt: "You are a math assistant. Use the available tools."
end
agent = MathAssistant.new()
{:ok, answer} = MathAssistant.query_sync(agent, "What is 5 + 3?")
```
## Composer vs Jido AI
Both libraries are part of the [Jido](https://github.com/agentjido/jido)
ecosystem and share the same action, signal, and LLM foundations. They solve
different problems:
- **Composer** — Composable flows: deterministic pipelines, parallel branches,
human approval gates, checkpoint/resume. You define the structure; the FSM
enforces it.
- **[Jido AI](https://github.com/agentjido/jido_ai)** — AI reasoning runtime: 8
strategy families (ReAct, CoT, ToT, ...), request handles, plugins, skills.
They work together — wrap a Jido AI agent as a node inside a Composer workflow
to get structured flow control around open-ended reasoning. See the
[full comparison](guides/composer-vs-jido-ai.md).
## Documentation
- [Composition & Nesting](guides/composition.md) — Nesting patterns, context
flow, control spectrum
- [Human-in-the-Loop](guides/hitl.md) — HumanNode, approval gates, suspension,
persistence
- [Getting Started](guides/getting-started.md) — First workflow in 5 minutes
- [Workflows Guide](guides/workflows.md) — All DSL options, fan-out, custom
outcomes
- [Orchestrators Guide](guides/orchestrators.md) — LLM config, tool approval,
streaming
- [Observability](guides/observability.md) — OTel spans, tracer setup, span
hierarchy
- [Testing](guides/testing.md) — ReqCassette, LLMStub, test layers
- [Composer vs Jido AI](guides/composer-vs-jido-ai.md) — When to use which, how
they combine
- Interactive demos in `livebooks/`
## License
MIT