You need to package reusable instructions/capabilities and load them safely.
After this guide, you can attach trusted Agent Skills with progressive disclosure, use session-scoped activation, validate skill files, and bound custom discovery.
Core Contracts
Jido.AI.SkillJido.AI.Skill.SpecJido.AI.Skill.LoaderJido.AI.Skill.RegistryJido.AI.Skill.AgentIntegrationJido.AI.Skill.PromptJido.AI.Actions.Skill.LoadSkillmix jido_ai.skill
Turnkey Agent Integration
Jido.AI.Agent can wire the complete progressive-disclosure lifecycle from one
option. Because project skills are executable instructions, enabling standard
root discovery is an explicit trust decision:
defmodule MyApp.SupportAgent do
use Jido.AI.Agent,
name: "support_agent",
tools: [MyApp.Search],
system_prompt: "You are a support agent.",
agent_skills: true
endThis discovers .agents/skills/ and ~/.agents/skills/, appends only the compact
name/description catalog to the system prompt, adds
Jido.AI.Actions.Skill.LoadSkill to the tools, and makes the resolved specs
available through reserved tool context for that agent. Discovery and catalog
construction happen when each agent instance initializes, so paths and bundled
resources refer to the runtime filesystem rather than the build host. Skills
that fail strict Agent Skills validation prevent the agent from initializing.
Prefer an explicit list when only particular roots are trusted:
use Jido.AI.Agent,
name: "support_agent",
tools: [MyApp.Search],
agent_skills: ["priv/skills", "/opt/my_app/skills"]Discovery options can set tighter bounds:
agent_skills: [
paths: ["priv/skills"],
trust: true,
max_depth: 4,
max_directories: 500,
exclude_directories: [".git", "node_modules", "deps", "_build"]
]Keyword options must include an explicit trust policy. Omitting it rejects
every discovered root; passing a path list directly is the shorthand for
trusting exactly those roots.
Agent Skills integration is disabled by default so an application never starts trusting repository instructions merely by upgrading a dependency.
Manual Lifecycle: Load, Register, Resolve, Retire
{:ok, spec} = Jido.AI.Skill.Loader.load("priv/skills/code-review/SKILL.md")
{:ok, _pid} = Jido.AI.Skill.Registry.start_link()
:ok = Jido.AI.Skill.Registry.register(spec)
{:ok, loaded} = Jido.AI.Skill.resolve(spec.name)
body = Jido.AI.Skill.body(loaded)
prompt = Jido.AI.Skill.Prompt.render_index([spec.name])
:ok = Jido.AI.Skill.Registry.unregister(spec.name)
:ok = Jido.AI.Skill.Registry.clear()Registry lifecycle guarantees:
- explicit startup via
start_link/1 - lazy startup via
ensure_started/0used by public APIs - safe unregister/clear operations for runtime teardown
Activation And Session Isolation
Activation state is keyed by {session_id, skill_name}. Public activation calls
default to the caller process; pass a stable ID when activation spans processes:
{:ok, activation} =
Jido.AI.Skill.Activation.activate("code-review", session_id: conversation_id)
activation.skill_body
activation.root_dir
activation.resources
# Release activation state when the session ends.
:ok = Jido.AI.Skill.Activation.clear(session_id: conversation_id)The load_skill action derives its session from session_id, then agent_id,
then request_id in the tool context. ReAct supplies agent_id, so separate
agent instances do not share activation state. Its structured result contains:
%{
name: "code-review",
description: "...",
instructions: "# Code Review ...",
root_dir: "/absolute/path/to/code-review",
resources: %{scripts: [...], references: [...], assets: [...]}
}Skill tool results are marked durable in conversation refs. A ReAct context
replacement with reason: :compaction retains the skill output and its matching
assistant tool call.
Lazy Loading Skill Bodies
Use a compact skill index when full skill bodies would make the agent prompt too
large. The index advertises names and descriptions only; the model can call the
packaged load_skill action to retrieve the selected body.
index =
Jido.AI.Skill.Prompt.render_registry_index(
tags: "support-agent",
include_allowed_tools: true
)
# Add `index` to your agent system prompt and expose this action with the agent tools.
Jido.AI.Actions.Skill.LoadSkillThe rendered index includes guidance for the model to call load_skill with the
skill name. render_registry_index/1 accepts :tags and :tag_match so agents
can advertise only the skills intended for that agent.
You can load a skill directly from application code as well:
{:ok, loaded} =
Jido.AI.Actions.Skill.LoadSkill.run(%{name: "code-review"}, %{})
loaded.instructions
loaded.root_dir
loaded.resourcesPrompt.render/2 now omits bodies by default. Eager rendering remains available
for deliberate static-prompt use with include_body: true; use render_index/2
for model-facing catalogs.
Strict And Lenient Validation
Strict loading (lenient: false, the default) enforces the Agent Skills format:
- the declared name exactly matches the parent directory
- descriptions are non-empty and at most 1,024 characters
- license is a string when present
- compatibility is non-empty and at most 500 characters when present
- metadata contains only string keys and string values
allowed-toolsis a space-separated string when present
Lenient loading keeps interoperability behavior: it records diagnostics and can normalize or truncate recoverable values.
Bounded Discovery And Trust
Discovery.discover_from/2 defaults to a maximum depth of 6 and 2,000 visited
directories, skips .git and node_modules, and does not follow file or
directory symlinks. Custom callers can require trust explicitly:
Jido.AI.Skill.Discovery.discover_from(paths,
trust: &MyApp.Trust.skill_root?/1,
max_depth: 4,
max_directories: 500
)An unapproved root returns {:error, {:untrusted_skill_path, absolute_path}};
exceeding the directory bound returns a structured :discovery_limit_exceeded
error.
CLI Surface + Error Handling
mix jido_ai.skill list priv/skills
mix jido_ai.skill show priv/skills/code-review/SKILL.md --body
mix jido_ai.skill validate priv/skills --strict
mix jido_ai.skill validate priv/skills --json
CLI failure behaviors:
mix jido_ai.skill listwith no paths prints usage helpmix jido_ai.skill validatewith no paths prints usage help- unknown commands print
mix jido_ai.skillhelp guidance --strictraises when any skill fails validation (non-zero exit)
Failure Modes
Invalid frontmatter or schema
Symptom:
- loader returns parse/validation error (
NoFrontmatter,InvalidYaml,MissingField,InvalidName)
Fix:
- ensure YAML frontmatter contains required fields
- validate with
mix jido_ai.skill validate ...before loading in runtime
Lookup failure after registration workflow
Symptom:
Jido.AI.Skill.resolve/1orJido.AI.Skill.Registry.lookup/1returnsNotFound
Fix:
- ensure skills were registered into the current runtime registry instance
- confirm normalized names (kebab-case) match lookup keys
Defaults You Should Know
- skill registry stores specs by skill name
- activation registry stores by session ID and skill name
body_refcan be inline or file-backed- allowed tools are normalized to string names
Prompt.render/2ignores unresolved skills, renders only valid specs, and omits bodies by default
Demo + Examples
Run the end-to-end demo script:
mix run examples/scripts/demo/skills_runtime_foundations_demo.exs
Prerequisites:
- run from the repository root
- keep
priv/skills/code-review/SKILL.mdavailable (checked by script)
If required skill files are missing, the demo prints a skip message and continues.
When To Use / Not Use
Use skills when:
- you need reusable instruction packs across agents
Do not use skills when:
- static prompts in agent config are sufficient