Search
Search docs, blog posts, and ecosystem packages with citations.
Enter a query to see grounded citations.
We can't find the internet
Attempting to reconnect
Search docs, blog posts, and ecosystem packages with citations.
Define typed state, implement a validated action, and run your first command.
Complete Installation and setup before starting this tutorial. Run this notebook top to bottom. You do not need a Mix project.
Mix.install([
{:jido, "~> 2.0"}
])
An agent is an immutable struct backed by a typed schema. The schema enforces types and defaults so state transitions stay consistent across runs.
defmodule CounterAgent do
use Jido.Agent,
name: "counter_agent",
description: "Tracks a simple counter",
schema: Zoi.object(%{
count: Zoi.integer() |> Zoi.default(0)
})
end
This module provides new/1, set/2, validate/2, and cmd/2. The agent is data, not a process. When you need supervision or long-lived runtime state, wrap it in a Jido.AgentServer.
Actions are the only way to change agent state. Each action defines a schema for its inputs and implements run/2. The first argument is validated params. The second is the execution context, which includes context.state - the current agent state.
defmodule IncrementAction do
use Jido.Action,
name: "increment",
description: "Increments the counter by a specified amount",
schema: Zoi.object(%{
by: Zoi.integer() |> Zoi.default(1)
})
@impl true
def run(params, context) do
current = Map.get(context.state, :count, 0)
{:ok, %{count: current + params.by}}
end
end
Params are schema-validated before run/2 is called, so params.by is always an integer. The return value is a partial state map that cmd/2 merges into the agent.
cmd/2 takes the current agent and an action instruction, runs the action, and returns a two-element tuple: the updated agent and a list of directives. The original agent is unchanged.
agent = CounterAgent.new()
{updated_agent, directives} =
CounterAgent.cmd(agent, {IncrementAction, %{by: 3}})
The updated agent reflects the new state. Directives are outbound instructions that describe side effects for the runtime to handle later.
updated_agent.state
directives
The directives list is empty because this action is pure. If an action needed to emit an event or schedule work, it would return Jido.Agent.Directive structs alongside the state changes.
If you pass params that fail schema validation, cmd/2 returns the original agent unchanged and a list containing a Directive.Error struct.
{error_agent, error_directives} =
CounterAgent.cmd(agent, {IncrementAction, %{by: "not_a_number"}})
error_agent.state
error_directives
The agent state remains %{count: 0} - the same as before the failed command. The error directive wraps a Jido.Error with context about what went wrong.