Autonomous agent framework for Elixir, built for distributed, autonomous behavior and dynamic workflows.
Reliable, observable, and loaded with sophisticated agent features.
The name "Jido" (自動) comes from the Japanese word meaning "automatic" or "automated", where 自 (ji) means "self" and 動 (dō) means "movement".
- Features
- Do You Need an Agent?
- Quick Start
- Installation
- Core Concepts
- Learning
- Community
- Contributing
Note
This README is for the unreleased main branch. Please reference the official documentation on hexdocs for the latest stable release.
Jido's primary goals are reliability, composability, and observability in agent-based systems.
-
🧩 Composable Actions
- Build complex behaviors from discrete, validated actions
- Compose Actions at runtime into dynamic workflows
- Comprehensive error handling and compensation
- Clear contracts with schema validation
-
🔄 Flexible Messaging via Signals
- Cloudevents compatible messaging envelope
- Asynchronous and synchronous request/response
- Flexible routing and filtering
- Adapter based output dispatching
-
🤖 Autonomous Agents
- OTP-native agent process supervision
- Asynchronous and synchronous request/response
- Dynamic workflow control
- State-aware self-directed behavior
-
📡 Real-time Sensors
- Extension to consume external system events
- Simple custom sensor development
- Configurable event filtering
-
🧪 Testing Tools
- Easily tested architecture
- Behavioral verification
- Mock sensors and actions
- Integration test helpers
Agents are powerful but not always necessary. Consider using Jido when you need:
- Dynamic workflow orchestration
- Adaptive decision making
- Complex state management
- Autonomous operation
- Distributed coordination
Learn more about when to use agents →
Define and start an agent with a few lines of code. Direct it using Signals, and receive results via the Agent's PID:
# First, define our Calculator agent with supported operations
iex> defmodule CalculatorAgent do
...> use Jido.Agent,
...> name: "calculator",
...> actions: [Actions.Add, Actions.Subtract, Actions.Multiply, Actions.Divide]
...> # Omitting the router that maps the "add" signal to the Add Action
...> end
{:module, CalculatorAgent, <<...>>, %{}}
# Start the agent process
iex> {:ok, pid} = CalculatorAgent.start_link()
{:ok, #PID<0.123.0>}
# Send a synchronous request to the agent
iex> {:ok, result} = CalculatorAgent.call(pid, Signal.new(%{type: "add", data: %{a: 1, b: 2}}))
{:ok, 3}
# Send an asynchronous request to the agent
iex> {:ok, request_id} = CalculatorAgent.cast(pid, Signal.new(%{type: "multiply", data: %{a: 2, b: 4}}))
{:ok, "req_abc123"}
# Receive the result of the asynchronous request
iex> flush()
{:jido_agent, "req_abc123", 8}
:ok
This example barely scratches the surface of what Jido can do. For more examples, see the Getting Started Guide and Jido Workbench to play with our growing catalog of real-life examples.
Add Jido to your dependencies:
def deps do
[
{:jido, "~> 1.0.0"}
]
end
You may also want to add Jido ecosystem dependencies:
- jido_ai for LLM-driven agents
- jido_chat for chat based messaging
- jido_memory for persistent agent memory
You can see examples of each of these in the Jido Workbench.
Jido provides a robust foundation for building autonomous agents that can plan, execute, and adapt their behavior in distributed Elixir applications. Think of it as a toolkit for creating smart, composable workflows that can evolve and respond to their environment.
Agents are a hot topic right now, but they aren't a silver bullet. In particular, Large Language Models (LLMs) are powerful yet slow and costly—if your application doesn't require dynamic decision-making or complex planning, consider whether you really need an Agent at all.
- LLMs aren't required for all tasks — Avoid building them into your core logic unless necessary
- Agents as Dynamic ETL — Agents dynamically direct data ingestion, transformation, and output based on:
- LLMs (e.g., GPT)
- Classical planning algorithms (A*, Behavior Trees, etc.)
- Simplicity often wins — If you don't need these dynamic behaviors, you probably don't need an Agent. This library is likely overkill compared to straightforward code.
An Agent is a system where LLMs or classical planning algorithms dynamically direct their own processes. Some great definitions from the community:
- "Agents are Dynamic ETL processes directed by LLMs" — YouTube
- "Agents are systems where LLMs dynamically direct their own processes" — Anthropic Research
- "AI Agents are programs where LLM outputs control the workflow" — Hugging Face Blog
If your application doesn't involve dynamic workflows or data pipelines that change based on AI or planning algorithms, you can likely do more with less.
💡 NOTE: This library intends to support both LLM planning and Classical AI planning (ie. Behavior Trees as a design principle via Actions. See
jido_ai
for example LLM actions.
This space is evolving rapidly. Last updated 2025-01-01
- 🧩 Composable Actions: Build complex behaviors from simple, reusable actions
- 🤖 Autonomous Agents: Self-directing entities that plan and execute workflows
- 📡 Real-time Sensors: Event-driven data gathering and monitoring
- 🔄 Adaptive Learning: Agents can modify their capabilities at runtime
- 📊 Built-in Telemetry: Comprehensive observability and debugging
- ⚡ Distributed by Design: Built for multi-node Elixir clusters
- 🧪 Testing Tools: Rich helpers for unit and property-based testing
Add Jido to your dependencies:
def deps do
[
{:jido, "~> 1.0.0"}
]
end
Actions are the fundamental building blocks in Jido. Each Action is a discrete, reusable unit of work with a clear interface:
defmodule MyApp.Actions.FormatUser do
use Jido.Action,
name: "format_user",
description: "Formats user data by trimming whitespace and normalizing email",
schema: [
name: [type: :string, required: true],
email: [type: :string, required: true]
]
def run(params, _context) do
{:ok, %{
formatted_name: String.trim(params.name),
email: String.downcase(params.email)
}}
end
end
Workflows chain Actions together to accomplish complex tasks. Jido handles data flow and error handling between steps:
alias MyApp.Actions.{FormatUser, EnrichUserData, NotifyUser}
{:ok, result} = Jido.Workflow.Chain.chain(
[FormatUser, EnrichUserData, NotifyUser],
%{
name: "John Doe ",
email: "[email protected]"
}
)
Agents are stateful entities that can plan and execute Actions. They maintain their state through a schema and can adapt their behavior:
defmodule MyApp.CalculatorAgent do
use Jido.Agent,
name: "calculator",
description: "An adaptive calculating agent",
actions: [
MyApp.Actions.Add,
MyApp.Actions.Multiply,
Jido.Actions.Directives.RegisterAction
],
schema: [
value: [type: :float, default: 0.0],
operations: [type: {:list, :atom}, default: []]
]
def on_after_run(agent, result) do
# Track which operations we've used
ops = [result.action | agent.state.operations] |> Enum.uniq()
{:ok, %{agent | state: %{agent.state | operations: ops}}}
end
end
Sensors provide real-time monitoring and data gathering for your agents:
defmodule MyApp.Sensors.OperationCounter do
use Jido.Sensor,
name: "operation_counter",
description: "Tracks operation usage metrics",
schema: [
emit_interval: [type: :pos_integer, default: 1000]
]
def mount(opts) do
{:ok, Map.merge(opts, %{counts: %{}})}
end
def handle_info({:operation, name}, state) do
new_counts = Map.update(state.counts, name, 1, & &1 + 1)
{:noreply, %{state | counts: new_counts}}
end
end
Start your agents under supervision:
# In your application.ex
children = [
{Registry, keys: :unique, name: Jido.AgentRegistry},
{Phoenix.PubSub, name: MyApp.PubSub},
{Jido.Agent.Supervisor, pubsub: MyApp.PubSub},
{Jido.Agent.Server,
agent: MyApp.CalculatorAgent.new(),
name: "calculator_1"
}
]
Supervisor.start_link(children, strategy: :one_for_one)
- Service Orchestration: Coordinate complex workflows across multiple services
- Data Processing: Build adaptive ETL pipelines that evolve with your data
- Business Automation: Model complex business processes with autonomous agents
- System Monitoring: Create smart monitoring agents that adapt to system behavior
- Transaction Management: Handle multi-step transactions with built-in compensation
- Event Processing: Process and react to event streams in real-time
- 📘 Getting Started Guide
- 🧩 Actions & Workflows
- 🤖 Building Agents
- 📡 Sensors & Monitoring
- 🔄 Agent Directives
We welcome contributions! Here's how to get started:
- Fork the repository
- Run tests:
mix test
- Run quality checks:
mix quality
- Submit a PR
Please include tests for any new features or bug fixes.
See our Contributing Guide for detailed guidelines.
Jido is built with a test-driven mindset and provides comprehensive testing tools for building reliable agent systems. Our testing philosophy emphasizes:
- Thorough test coverage for core functionality
- Property-based testing for complex behaviors
- Regression tests for every bug fix
- Extensive testing helpers and utilities
Jido provides several testing helpers:
Jido.TestSupport
- Common testing utilities- Property-based testing via StreamData
- Mocking support through Mimic
- PubSub testing helpers
- Signal assertion helpers
# Run the test suite
mix test
# Run with coverage reporting
mix test --cover
# Run the full quality check suite
mix quality
While we strive for 100% test coverage, we prioritize meaningful tests that verify behavior over simple line coverage. Every new feature and bug fix includes corresponding tests to prevent regressions.
Apache License 2.0 - See LICENSE.md for details.