Agents
View SourceAfter: You can define agents with schemas, hooks, and the cmd/2 contract.
Agents are immutable data structures that hold state and respond to actions. The core operation is cmd/2, which processes actions and returns an updated agent plus directives for external effects.
Defining an Agent
defmodule MyAgent do
use Jido.Agent,
name: "my_agent", # Required - alphanumeric + underscores
description: "My custom agent", # Optional
category: "example", # Optional
tags: ["demo"], # Default: []
vsn: "1.0.0", # Optional
schema: [ # State schema (see below)
status: [type: :atom, default: :idle],
counter: [type: :integer, default: 0]
],
strategy: Jido.Agent.Strategy.Direct, # Default
skills: [MySkill] # Default: []
endThe cmd/2 Contract
The fundamental operation:
{agent, directives} = MyAgent.cmd(agent, action)Key invariants:
- The returned
agentis always complete—no "apply directives" step needed directivesdescribe external effects only—they never modify agent statecmd/2is a pure function—given same inputs, always same outputs
Action formats:
# Action module with no params
{agent, directives} = MyAgent.cmd(agent, MyAction)
# Action with params
{agent, directives} = MyAgent.cmd(agent, {MyAction, %{value: 42}})
# Full instruction struct
{agent, directives} = MyAgent.cmd(agent, %Instruction{action: MyAction, params: %{}})
# List of actions (processed in sequence)
{agent, directives} = MyAgent.cmd(agent, [Action1, {Action2, %{x: 1}}])State Management
set/2 — Update State
Deep-merges attributes into agent state:
{:ok, agent} = MyAgent.set(agent, %{status: :running})
{:ok, agent} = MyAgent.set(agent, counter: 5)validate/2 — Validate Against Schema
# Validate state, keeping extra fields
{:ok, agent} = MyAgent.validate(agent)
# Strict mode: only schema-defined fields are kept
{:ok, agent} = MyAgent.validate(agent, strict: true)Lifecycle Hooks
Optional callbacks for pure transformations before/after command processing.
on_before_cmd/2
Called before action processing. Transform agent or action:
def on_before_cmd(agent, action) do
# Example: log the action being processed
{:ok, agent} = set(agent, %{last_action: inspect(action)})
{:ok, agent, action}
endUse cases:
- Mirror action params into agent state
- Add default params based on current state
- Enforce invariants before execution
on_after_cmd/3
Called after action processing. Transform agent or directives:
def on_after_cmd(agent, action, directives) do
# Example: auto-validate after every command
{:ok, agent} = validate(agent)
{:ok, agent, directives}
endUse cases:
- Auto-validate state after changes
- Derive computed fields
- Add invariant checks
Schema Options
Agent state is validated against a schema. Two formats are supported:
NimbleOptions (legacy, familiar)
use Jido.Agent,
name: "my_agent",
schema: [
status: [type: :atom, default: :idle],
counter: [type: :integer, default: 0],
config: [type: {:map, :atom, :string}, default: %{}]
]Zoi (recommended for new code)
use Jido.Agent,
name: "my_agent",
schema: Zoi.object(%{
status: Zoi.atom() |> Zoi.default(:idle),
counter: Zoi.integer() |> Zoi.default(0),
config: Zoi.map() |> Zoi.default(%{})
})Both are handled transparently by the Agent module.
Creating Agents
# Create with defaults
agent = MyAgent.new()
# Create with custom ID
agent = MyAgent.new(id: "custom-id")
# Create with initial state
agent = MyAgent.new(state: %{counter: 10})Further Reading
- Actions — Defining actions that transform agent state
- State Operations — Internal state transitions during
cmd/2 - Directives — External effects emitted by agents
- Strategies — Execution strategies for
cmd/2 Jido.Agent— Full module documentation