Jido.AI.Skill.Discovery (Jido AI v2.2.0)

Copy Markdown View Source

Discovers skills from project-level and user-level skill directories.

Implements the agentskills.io discovery spec:

  • Project-level: .agents/skills/ directory
  • User-level: ~/.agents/skills/ directory

Precedence Rules

Project-level skills override user-level skills when both have the same name. This follows deterministic precedence: project > user

Metadata Tracking

Each discovered skill includes:

  • name - Skill identifier
  • description - Brief description from SKILL.md frontmatter
  • skill_md_path - Absolute path to the SKILL.md file
  • root_dir - Skill root directory (parent of SKILL.md location)
  • scope - :project or :user indicating source
  • source_metadata - Additional discovery metadata

Usage

# Discover all skills
{:ok, skills} = Jido.AI.Skill.Discovery.discover()

# Discover from specific paths only
{:ok, skills} = Jido.AI.Skill.Discovery.discover_from([".agents/skills/"])

# Get a single skill by name
{:ok, spec} = Jido.AI.Skill.Discovery.find("code-review")

Summary

Functions

Discovers skills from both project and user directories.

Discovers skills from a list of specific paths.

Discovers skills from the project-level .agents/skills/ directory.

Discovers skills from the user-level ~/.agents/skills/ directory.

Finds a specific skill by name across all discovery sources.

Converts discovery metadata into a full Spec by loading the SKILL.md.

Types

discovery_metadata()

@type discovery_metadata() :: %{
  name: String.t(),
  description: String.t() | nil,
  skill_md_path: String.t(),
  root_dir: String.t(),
  scope: scope(),
  source_metadata: map()
}

scope()

@type scope() :: :project | :user | :custom

Functions

discover()

@spec discover() :: {:ok, [discovery_metadata()]} | {:error, term()}

Discovers skills from both project and user directories.

Returns skills with project-level taking precedence over user-level when names collide.

Returns

  • {:ok, [discovery_metadata]} - List of discovered skill metadata
  • {:error, reason} - Discovery failed

Examples

{:ok, skills} = Jido.AI.Skill.Discovery.discover()
# skills will have project-level skills overriding user-level

discover_from(paths, opts \\ [])

@spec discover_from(
  [String.t()],
  keyword()
) :: {:ok, [discovery_metadata()]} | {:error, term()}

Discovers skills from a list of specific paths.

Useful for scanning custom directories or testing.

Options

  • :scope - Assign scope metadata (:project or :user), defaults to :custom

Examples

{:ok, skills} = Jido.AI.Skill.Discovery.discover_from(["priv/skills/"])
{:ok, skills} = Jido.AI.Skill.Discovery.discover_from(["priv/skills/"], scope: :project)

discover_from_project(base_path \\ ".agents/skills")

@spec discover_from_project(String.t()) ::
  {:ok, [discovery_metadata()]} | {:error, term()}

Discovers skills from the project-level .agents/skills/ directory.

Returns

  • {:ok, [discovery_metadata]} - List of project-level skills
  • {:ok, []} - Directory doesn't exist or is empty
  • {:error, reason} - Discovery failed

discover_from_user(base_path \\ default_user_path())

@spec discover_from_user(String.t()) ::
  {:ok, [discovery_metadata()]} | {:error, term()}

Discovers skills from the user-level ~/.agents/skills/ directory.

Returns

  • {:ok, [discovery_metadata]} - List of user-level skills
  • {:ok, []} - Directory doesn't exist or is empty
  • {:error, reason} - Discovery failed

find(name, paths \\ nil)

@spec find(String.t(), [String.t()] | nil) ::
  {:ok, discovery_metadata()} | {:error, :not_found}

Finds a specific skill by name across all discovery sources.

Returns the first matching skill with project-level taking precedence.

When paths is given, searches those directories instead of the default project/user discovery sources — useful for scoped lookups and testing.

Examples

{:ok, metadata} = Jido.AI.Skill.Discovery.find("code-review")
{:error, :not_found} = Jido.AI.Skill.Discovery.find("unknown-skill")
{:ok, metadata} = Jido.AI.Skill.Discovery.find("local-skill", ["priv/skills/"])

to_spec(arg1)

@spec to_spec(discovery_metadata() | map()) ::
  {:ok, Jido.AI.Skill.Spec.t()} | {:error, term()}

Converts discovery metadata into a full Spec by loading the SKILL.md.

Examples

{:ok, metadata} = Jido.AI.Skill.Discovery.find("code-review")
{:ok, spec} = Jido.AI.Skill.Discovery.to_spec(metadata)