Jido.Skill behaviour (Jido v2.0.0-rc.1)
View SourceA Skill is a composable capability that can be attached to an agent.
Skills encapsulate:
- A set of actions the agent can perform
- State schema for skill-specific data (nested under
state_key) - Configuration schema for per-agent customization
- Signal routing rules
- Optional lifecycle hooks and child processes
Lifecycle
- Compile-time: Skill is declared in agent's
skills:option - Agent.new/1:
mount/2is called to initialize skill state (pure) - AgentServer.init/1:
child_spec/1processes are started and monitored - Signal processing:
handle_signal/2runs before routing, can override or abort - After cmd/2 (call path):
transform_result/3wraps call results
Example Skill
defmodule MyApp.ChatSkill do
use Jido.Skill,
name: "chat",
state_key: :chat,
actions: [MyApp.Actions.SendMessage, MyApp.Actions.ListHistory],
schema: Zoi.object(%{
messages: Zoi.list(Zoi.any()) |> Zoi.default([]),
model: Zoi.string() |> Zoi.default("gpt-4")
}),
signal_patterns: ["chat.*"]
@impl Jido.Skill
def mount(agent, config) do
# Custom initialization beyond schema defaults
{:ok, %{initialized_at: DateTime.utc_now()}}
end
@impl Jido.Skill
def router(config) do
[
{"chat.send", MyApp.Actions.SendMessage},
{"chat.history", MyApp.Actions.ListHistory}
]
end
endUsing Skills
defmodule MyAgent do
use Jido.Agent,
name: "my_agent",
skills: [
MyApp.ChatSkill,
{MyApp.DatabaseSkill, %{pool_size: 5}}
]
endConfiguration Options
name- Required. The skill name (letters, numbers, underscores).state_key- Required. Atom key for skill state in agent.actions- Required. List of action modules.description- Optional description.category- Optional category.vsn- Optional version string.schema- Optional Zoi schema for skill state.config_schema- Optional Zoi schema for per-agent config.signal_patterns- List of signal pattern strings (default: []).tags- List of tag strings (default: []).capabilities- List of atoms describing what the skill provides (default: []).requires- List of requirements like{:config, :token},{:app, :req},{:skill, :http}(default: []).routes- List of route tuples like{"post", ActionModule}(default: []).schedules- List of schedule tuples like{"*/5 * * * *", ActionModule}(default: []).
Summary
Callbacks
Returns child specification(s) for supervised processes.
Pre-routing hook called before signal routing in AgentServer.
Called when the skill is mounted to an agent during new/1.
Returns the signal router for this skill.
Returns the skill specification with optional per-agent configuration.
Returns sensor subscriptions for this skill.
Transform the agent returned from AgentServer.call/3.
Callbacks
@callback child_spec(config :: map()) :: nil | Supervisor.child_spec() | [Supervisor.child_spec()]
Returns child specification(s) for supervised processes.
Called during AgentServer.init/1. Returned processes are
monitored by the AgentServer and tracked in its state.
Parameters
config- Per-agent configuration for this skill
Return Values
nil- No child processes neededSupervisor.child_spec()- Single child process[Supervisor.child_spec()]- Multiple child processes
Example
def child_spec(config) do
%{
id: MyWorker,
start: {MyWorker, :start_link, [config]}
}
end
@callback handle_signal(signal :: term(), context :: map()) :: {:ok, term()} | {:ok, {:override, term()}} | {:error, term()}
Pre-routing hook called before signal routing in AgentServer.
Can inspect, log, or override which action runs for a signal.
Parameters
signal- The incomingJido.Signalstructcontext- Map with:agent,:agent_module,:skill,:skill_spec,:config
Returns
{:ok, nil}or{:ok, :continue}- Continue to normal routing{:ok, {:override, action_spec}}- Bypass router, use this action instead{:error, reason}- Abort signal processing with error
Example
def handle_signal(signal, _context) do
if signal.type == "admin.override" do
{:ok, {:override, MyApp.AdminAction}}
else
{:ok, :continue}
end
end
Called when the skill is mounted to an agent during new/1.
Use this to initialize skill-specific state beyond schema defaults. This is a pure function - no side effects allowed.
Parameters
agent- The agent struct (with state from previously mounted skills)config- Per-agent configuration for this skill
Returns
{:ok, skill_state}- Map to merge into skill's state slice{:ok, nil}- No additional state (schema defaults only){:error, reason}- Raises during agent creation
Example
def mount(_agent, config) do
{:ok, %{initialized_at: DateTime.utc_now(), api_key: config[:api_key]}}
end
Returns the signal router for this skill.
The router determines how signals are routed to handlers.
@callback skill_spec(config :: map()) :: Jido.Skill.Spec.t()
Returns the skill specification with optional per-agent configuration.
This is the primary interface for getting skill metadata and configuration.
Returns sensor subscriptions for this skill.
Called during AgentServer.post_init/1 to determine which sensors
should be started for this skill. Each sensor is started with the
provided configuration.
Parameters
config- Per-agent configuration for this skillcontext- Map containing::agent_ref- The agent reference (name or PID):agent_id- The agent's unique identifier:agent_module- The agent module:skill_spec- The skill specification:jido_instance- The Jido instance name
Returns
A list of {sensor_module, sensor_config} tuples where:
sensor_module- A module implementing sensor behaviorsensor_config- Keyword list or map of sensor configuration
Example
def subscriptions(_config, context) do
[
{MyApp.Sensors.FileSensor, [path: "/tmp/watch", target: context.agent_ref]},
{MyApp.Sensors.TimerSensor, %{interval: 5000, target: context.agent_ref}}
]
end
@callback transform_result( action :: module() | String.t(), result :: term(), context :: map() ) :: term()
Transform the agent returned from AgentServer.call/3.
Called after signal processing on the synchronous call path only.
Does not affect cast/2 or internal state - only the returned agent.
Parameters
action- The signal type or action module that was executedresult- The agent struct to transformcontext- Map with:agent,:agent_module,:skill,:skill_spec,:config
Returns
The transformed agent struct (or original if no transformation needed).
Example
def transform_result(_action, agent, _context) do
# Add metadata to returned agent
new_state = Map.put(agent.state, :last_call_at, DateTime.utc_now())
%{agent | state: new_state}
end