Current section

Files

Jump to
jido usage-rules.md
Raw

usage-rules.md

# Jido Usage Rules
**Jido** is a functional, OTP-based toolkit for building autonomous, distributed agent systems in Elixir.
## Core Components
### Actions - State Transformers
```elixir
defmodule MyAction do
use Jido.Action,
name: "my_action",
description: "Process data",
schema: [input: [type: :string, required: true]]
def run(params, _context) do
{:ok, %{result: String.upcase(params.input)}}
end
end
```
### Agents - Stateful Orchestrators
```elixir
defmodule MyAgent do
use Jido.Agent,
name: "my_agent",
schema: [status: [type: :atom, default: :idle]],
actions: [MyAction]
end
# Usage
{:ok, agent} = MyAgent.new()
{:ok, pid} = MyAgent.start_link(agent: agent)
{:ok, result} = MyAgent.cmd(agent, MyAction, %{input: "test"})
```
### Sensors - Real-time Monitoring
```elixir
defmodule MySensor do
use Jido.Sensor,
name: "my_sensor",
schema: [interval: [type: :pos_integer, default: 5000]]
def mount(opts), do: {:ok, opts}
def deliver_signal(state) do
{:ok, Jido.Signal.new(%{topic: "update", payload: get_data()})}
end
end
```
## Key Patterns
- **Always return tagged tuples**: `{:ok, result}` or `{:error, reason}`
- **Use schemas for validation** in all components
- **Pattern match with function heads** instead of conditionals
- **Actions transform state** (may perform side effects), Agents manage state
- **Plan before execution**: `Agent.plan(agent, actions) |> Agent.run()`
## Common Operations
```elixir
# Get running agent
{:ok, pid} = Jido.get_agent("agent-id")
# Execute single action
{:ok, result} = Agent.cmd(agent, Action, params)
# Chain multiple actions
{:ok, agent} = Agent.plan(agent, [
{Action1, %{input: "data"}},
{Action2, %{threshold: 0.8}}
])
{:ok, results} = Agent.run(agent)
# Start sensor
{:ok, sensor} = MySensor.start_link(id: "sensor1", target: pid)
```
## Error Handling
```elixir
# In Actions
def run(params, _context) do
with {:ok, cleaned} <- validate(params.input),
{:ok, result} <- process(cleaned) do
{:ok, result}
else
{:error, reason} -> {:error, reason}
end
end
# In Agents - use lifecycle hooks
def on_before_run(agent) do
if ready?(agent), do: {:ok, agent}, else: {:error, :not_ready}
end
```
## Testing Patterns
```elixir
# Test Actions
test "processes input" do
assert {:ok, result} = MyAction.run(%{input: "test"}, %{})
assert result.output == "TEST"
end
# Test Agents
test "executes command" do
{:ok, agent} = MyAgent.start_link(id: "test")
assert {:ok, result} = MyAgent.cmd(agent, MyAction, %{input: "test"})
end
```
## Don't
- Skip parameter validation
- Return raw values (use tagged tuples)
- Make Actions stateful
- Create circular dependencies between agents
- Use agents for stateless operations (use Actions)
- Skip error handling