Core Integration Patterns
Resource Extension Setup
- Add
extensions: [AshJido]to Ash resources that should generate Jido actions. - Put the
jidosection near the resourceactionssection so the exposed tool surface is easy to audit. - Prefer explicit
action :nameentries for hand-curated tool catalogs. - Use
all_actionswhen the resource's public Ash action surface is already the intended tool surface.
Individual Action Configuration
jido do
action :create
action :read, name: "list_users", description: "List users"
action :update, tags: ["user-management", "data-modification"]
endBulk Action Exposure
jido do
all_actions
all_actions except: [:internal_action, :admin_only]
all_actions only: [:create, :read, :update]
endall_actionsexpands only Ash actions withpublic?: trueby default.- Generated schemas include only public accepted attributes and public action arguments by default.
- Use explicit
action :private_actionentries for deliberate private-action exposure. - Use
include_private?: trueonly for trusted/internal catalogs that may expose private Ash actions or private inputs. - Ash authorization, policies, data-layer constraints, and runtime validation remain authoritative when generated actions execute.
Naming and Modules
Default Action Names
:createactions default to"create_<resource>".:readaction:readdefaults to"list_<resources>".:readaction:by_iddefaults to"get_<resource>_by_id".- Other read actions default to
"<resource>_<action_name>". :updateactions default to"update_<resource>".:destroyactions default to"delete_<resource>".- Custom actions default to
"<resource>_<action_name>", except common verbs like:activateand:archive, which become"<verb>_<resource>".
Module Generation
- Default modules are generated under the resource namespace, for example
MyApp.Accounts.User.Jido.Create. name:changes the Jido action name used for discovery and tool payloads.module_name:changes the generated Elixir module.- If the same Ash action is exposed more than once, give each entry an explicit
module_name:so modules do not collide.
Context Requirements
AshJido resolves the Ash domain in this order:
context[:domain]- the resource's static
domain:configuration ArgumentErrorif neither is available
context = %{
domain: MyApp.Accounts,
actor: current_user,
tenant: "org_123",
authorize?: true,
scope: MyApp.Scope.for(current_user),
context: %{request_id: "req_123"},
timeout: 15_000
}- Pass
actor:for policy-aware authorization. - Pass
tenant:for multi-tenant resources. - Pass
scope:when using Ash scopes. - Pass
context:for Ash action context metadata. - Pass
signal_dispatch:to override generated-action signal dispatch at runtime.
Query Parameters
Generated read actions accept optional query parameters by default:
MyApp.Blog.Post.Jido.Read.run(
%{
filter: %{status: %{in: ["draft", "published"]}},
sort: [%{"field" => "inserted_at", "direction" => "desc"}],
limit: 20,
offset: 40
},
%{domain: MyApp.Blog}
)filteruses Ashfilter_inputsyntax.sortsupports JSON-style maps, keyword lists, or strings like"-inserted_at,title".limitandoffsetsupport pagination.loadis available only when the action configuresallowed_loads.- Query params use Ash's safe public input parsing and honor policies.
- Disable query params with
query_params?: false. - Allow runtime relationship loads with
allowed_loadsorread_allowed_loads. - Bound result sizes with
max_page_sizeorread_max_page_size.
Signals and Telemetry
Resource Publications
Use AshJido.Notifier with publish or publish_all for Ash-native lifecycle
publications to a Jido signal bus:
defmodule MyApp.Blog.Post do
use Ash.Resource,
domain: MyApp.Blog,
extensions: [AshJido],
notifiers: [AshJido.Notifier]
jido do
signal_bus MyApp.SignalBus
signal_prefix "blog"
publish :create, "blog.post.created", include: [:id, :title]
publish_all :update, include: :changes_only
end
endpublish supports include: :pkey_only | :all | :changes_only | [:field],
metadata: [:actor, :tenant, :changes, :previous_state], and condition: fun.
Generated-Action Signals
Use emit_signals?: true when signal dispatch should be tied to generated
action execution:
jido do
action :create,
emit_signals?: true,
signal_dispatch: {:pid, target: self()},
telemetry?: true
end- Generated-action signals require
signal_dispatchfrom the DSL or context. - Both generated-action signals and notifier publications use
AshJido.SignalFactory. - Default signal types are
{prefix}.{resource}.{action}. - Default signal sources are
/ash/{resource}/{action_type}/{action}. - Default subjects are
/{resource}/{primary_key}when a primary key exists. - Generated-action signals put primary key data in
signal.databy default; usesignal_includeto widen the payload intentionally. - Notifier publications use the configured
includemode forsignal.data. - Ash metadata lives in
signal.extensions["jido_metadata"].
Telemetry
Telemetry is opt-in with telemetry?: true and emits:
[:jido, :action, :ash_jido, :start][:jido, :action, :ash_jido, :stop][:jido, :action, :ash_jido, :exception]
Telemetry metadata includes resource/action/module identity, domain and tenant presence, actor presence, read-load/query configuration, signal enablement, and signal delivery counters.
Tools and Sensor Bridge
- Use
AshJido.Tools.actions/1to list generated action modules for a resource or domain. - Use
AshJido.Tools.tools/1to export name/description/schema/function maps for generic agent and LLM integrations. - Use
AshJido.SensorDispatchBridge.forward/2,forward_many/2, orforward_or_ignore/2to feed dispatchedJido.Signalmessages intoJido.Sensor.Runtime.
Output and Mutation Semantics
output_map?: trueis the default and converts Ash structs to public-field maps.- Set
output_map?: falseto preserve Ash structs. - Read actions return lists.
- Create and update actions return the resulting record.
- Update and destroy actions require the resource primary key fields in params.
- Resources with the default
[:id]primary key still useid. - Destroy actions also pass through declared Ash destroy action arguments.
- Custom Ash actions use
Ash.run_action!; non-map results are wrapped for Jido output validation.
Error Handling
Ash errors are converted to Jido.Action.Error exceptions:
Ash.Error.InvalidbecomesJido.Action.Error.InvalidInputError.Ash.Error.ForbiddenbecomesJido.Action.Error.ExecutionFailureErrorwithdetails.reason == :forbidden.Ash.Error.FrameworkbecomesJido.Action.Error.InternalError.Ash.Error.UnknownbecomesJido.Action.Error.InternalError.- Other exceptions become
Jido.Action.Error.ExecutionFailureError.
Field-level validation errors are preserved in error.details.fields, and the
original Ash error is preserved in error.details.ash_error.
Best Practices
Security
- Prefer Ash
public?: trueboundaries for generated tool catalogs. - Use
include_private?: trueonly for trusted/internal tools. - Keep Ash policies as the authorization source of truth.
- Use
except:or explicit action entries to avoid exposing destructive or administrative actions unintentionally. - Bound large read actions with
max_page_size.
AI Integration
- Use clear verb-first
name:values for agent-facing tools. - Add concise
description:text and focusedtags:. - Use
category:for routing;all_actionsdefaults to"ash.<action_type>"when no category override is provided. - Export tool payloads through
AshJido.Tools.tools/1for generic integrations. - For
Jido.AI.Agent, configure generated action modules directly intools:.
Documentation
- Generated modules include docs pointing back to the Ash resource/action.
- Keep README, guides, changelog, and these usage rules in sync when changing DSL options, runtime behavior, or generated schemas.
- Do not edit
CHANGELOG.mddirectly in normal PRs; the release workflow generates it from conventional commits throughgit_ops. - Run
mix docsandmix doctor --raiseafter public documentation changes.
Troubleshooting
Domain Not Provided
- AshJido uses
context[:domain]first, then the resource's staticdomain:. - Provide
%{domain: MyApp.Domain}when overriding or when the resource has no static domain. - Ensure the resource is registered in the provided domain.
Action Not Found
- Verify the action exists in the resource
actionssection. - Check spelling and exact action name.
- For
all_actions, ensure the action is public or opt in withinclude_private?: true.
Query Parameter Errors
- Confirm the target is a read action and
query_params?is enabled. - Use public Ash attributes for
filterandsort. - Use
max_page_sizeto make pagination bounds explicit.
Signal Dispatch Errors
emit_signals?: truerequiressignal_dispatchin the DSL or context.- Use
AshJido.Notifierandsignal_busfor resource-level Jido bus publications. - Use
signal_typeandsignal_sourceonly when the default envelope should be overridden.
Module Compilation Issues
- Ensure
jido,jido_action, andjido_signaldependencies are available. - Give duplicate generated entries explicit
module_name:values. - Check for circular resource/module references.