Current section
Files
Jump to
Current section
Files
README.md
# AshJido
[](https://hex.pm/packages/ash_jido)
[](https://hexdocs.pm/ash_jido/)
[](https://github.com/agentjido/ash_jido/actions/workflows/ci.yml)
[](https://github.com/agentjido/ash_jido/blob/main/LICENSE)
AshJido compiles selected Ash APIs into native Jido v3 Actions. It keeps Ash as the source of business rules, authorization, and data access. It uses Jido for execution, Flow orchestration, Agents, and persistence lifecycle.
## Main features
- Domain-first compilation from Ash code interfaces
- Resource action fallback for APIs that do not have code interfaces
- Static Zoi input and output schemas
- Native execution with `Jido.Exec`
- Native composition with `Jido.Flow`
- Fixed compile-time domains and namespaced Ash context
- Public, non-sensitive result serialization
- Explicit filter, sort, load, and pagination allowlists
- Ash-backed Jido persistence with atomic compare-and-swap
- Ash notifier publications to a Jido Signal bus
AshJido does not add a second Action, Flow, Agent, or Signal runtime.
## Installation
Add AshJido to `mix.exs`:
```elixir
def deps do
[
{:ash_jido, "~> 3.0.0-beta.1"}
]
end
```
Or use Igniter:
```bash
mix igniter.install ash_jido
```
Version 3 uses the Hex releases of `jido`, `jido_action`, and `jido_signal` version 3.
## Define the Ash API
Define normal Ash actions and public domain code interfaces:
```elixir
defmodule MyApp.Accounts.User do
use Ash.Resource,
domain: MyApp.Accounts,
data_layer: AshPostgres.DataLayer
attributes do
uuid_primary_key :id
attribute :name, :string, allow_nil?: false, public?: true
attribute :email, :string, allow_nil?: false, public?: true
attribute :secret, :string, sensitive?: true
end
actions do
defaults [:read]
create :register do
accept [:name, :email]
end
end
end
defmodule MyApp.Accounts do
use Ash.Domain, extensions: [AshJido]
resources do
resource MyApp.Accounts.User do
define :register_user, action: :register
define :get_user, action: :read, get_by: [:id]
define :list_users, action: :read
end
end
jido do
expose :register_user
expose :get_user
expose :list_users,
filters: [:email],
sorts: [:name],
pagination: [type: :offset, max_page_size: 100]
end
end
```
This creates these normal Jido Actions:
- `MyApp.Accounts.Jido.RegisterUser`
- `MyApp.Accounts.Jido.GetUser`
- `MyApp.Accounts.Jido.ListUsers`
## Run a generated Action
```elixir
{:ok, output} =
Jido.Exec.run(
MyApp.Accounts.Jido.RegisterUser,
%{name: "Ada", email: "ada@example.com"},
%{ash: %{actor: current_user, tenant: tenant}}
)
%{
result: %{id: id, name: "Ada", email: "ada@example.com"},
page: nil,
metadata: nil
} = output
```
The domain is part of the generated descriptor. Run-time context can contain these `context.ash` values:
- `actor`
- `tenant`
- `scope`
- `tracer`
- `context`
- `timeout`
- `authorize?: true`
A caller cannot supply a different domain or set `authorize?: false`.
## Stable contracts
Generated Actions use static Zoi schemas. Unsupported custom Ash types fail at compile time unless the exposure supplies a `schema_overrides` entry.
All successful calls return this shape:
```elixir
%{
result: result,
page: page_or_nil,
metadata: metadata_or_nil
}
```
Ash resource structs become maps. The serializer includes public, non-sensitive fields only. It omits unloaded and forbidden fields.
## Resource fallback
Use the extension on a resource when a code interface is not available:
```elixir
defmodule MyApp.Accounts.User do
use Ash.Resource,
domain: MyApp.Accounts,
extensions: [AshJido]
jido do
action :register
action :update_profile, identity: :unique_email
end
end
```
This form generates modules under `MyApp.Accounts.User.Jido`.
## Jido Flow
Generated modules are normal Jido Actions. Use them directly in `Jido.Flow`:
```elixir
defmodule MyApp.Flows.RegisterAndFetch do
use Jido.Flow, name: "register_and_fetch"
flow do
step "register",
action: MyApp.Accounts.Jido.RegisterUser,
params: %{name: input(:name), email: input(:email)}
step "fetch",
action: MyApp.Accounts.Jido.GetUser,
params: %{id: result("register", [:result, :id])}
output result("fetch")
end
end
Jido.Exec.run(
MyApp.Flows.RegisterAndFetch,
%{name: "Ada", email: "ada@example.com"},
context
)
```
AshJido does not provide a Flow wrapper. Flow steps keep separate Ash transaction boundaries. Design compensation in the Flow when a later step can fail.
## More guides
- [Getting started](guides/getting-started.md)
- [Jido Flow composition](guides/flow.md)
- [Ash persistence adapter](guides/persistence.md)
- [Jido Signal publications](guides/signals.md)
- [Migration from AshJido v1](guides/v3-migration.md)
- [Usage rules](usage-rules.md)