# `Jido.Discovery`
[🔗](https://github.com/agentjido/jido/blob/v2.3.0/lib/jido/discovery.ex#L1)

Fast, persistent catalog of Jido components (Actions, Sensors, Agents, Plugins, Demos).

Discovery uses `:persistent_term` for optimal read performance. The catalog is built
asynchronously during application startup and can be refreshed on demand.

## Component Discovery

Discovery automatically finds and indexes:

- **Actions** - Discrete units of work (`__action_metadata__/0`)
- **Sensors** - Event monitoring components (`__sensor_metadata__/0`)
- **Agents** - Autonomous workers (`__agent_metadata__/0`)
- **Plugins** - Reusable capability packs (`__plugin_metadata__/0`)
- **Demos** - Example implementations (`__jido_demo__/0`)

## Component Metadata

Each discovered component includes:

```elixir
%{
  module: MyApp.CoolAction,
  name: "cool_action",
  description: "Does cool stuff",
  slug: "abc123de",
  category: :utility,
  tags: [:cool, :stuff]
}
```

## Usage

    # List components with optional filters
    Jido.Discovery.list_actions(category: :utility, limit: 10)
    Jido.Discovery.list_sensors(tag: :monitoring)

    # Find by slug
    Jido.Discovery.get_action_by_slug("abc123de")

    # Refresh catalog
    Jido.Discovery.refresh()

    # Get last update time
    {:ok, timestamp} = Jido.Discovery.last_updated()

## Filtering Options

- `:limit` - Maximum results to return
- `:offset` - Results to skip (pagination)
- `:name` - Filter by name (partial match)
- `:description` - Filter by description (partial match)
- `:category` - Filter by category (exact match)
- `:tag` - Filter by tag (must have exact tag)

Filters use AND logic - all specified filters must match.

## Performance

Reads are extremely fast (direct memory access) and never block.
All processes can read concurrently without contention.

# `component_metadata`

```elixir
@type component_metadata() :: %{
  module: module(),
  name: String.t(),
  description: String.t(),
  slug: String.t(),
  category: atom() | nil,
  tags: [atom()] | nil
}
```

# `component_type`

```elixir
@type component_type() :: :actions | :sensors | :agents | :plugins | :demos
```

# `catalog`

```elixir
@spec catalog() :: {:ok, map()} | {:error, :not_initialized}
```

Returns the full catalog for inspection.

# `get_action_by_slug`

```elixir
@spec get_action_by_slug(String.t()) :: component_metadata() | nil
```

Retrieves an Action by its slug.

# `get_agent_by_slug`

```elixir
@spec get_agent_by_slug(String.t()) :: component_metadata() | nil
```

Retrieves an Agent by its slug.

# `get_demo_by_slug`

```elixir
@spec get_demo_by_slug(String.t()) :: component_metadata() | nil
```

Retrieves a Demo by its slug.

# `get_plugin_by_slug`

```elixir
@spec get_plugin_by_slug(String.t()) :: component_metadata() | nil
```

Retrieves a Plugin by its slug.

# `get_sensor_by_slug`

```elixir
@spec get_sensor_by_slug(String.t()) :: component_metadata() | nil
```

Retrieves a Sensor by its slug.

# `init_async`

```elixir
@spec init_async() :: Task.t()
```

Initializes the discovery catalog asynchronously.

Call this from your application supervisor's start callback.
The catalog will be built in the background without blocking startup.

# `last_updated`

```elixir
@spec last_updated() :: {:ok, DateTime.t()} | {:error, :not_initialized}
```

Returns the last time the catalog was updated.

# `list_actions`

```elixir
@spec list_actions(keyword()) :: [component_metadata()]
```

Lists all Actions with optional filtering and pagination.

# `list_agents`

```elixir
@spec list_agents(keyword()) :: [component_metadata()]
```

Lists all Agents with optional filtering and pagination.

# `list_demos`

```elixir
@spec list_demos(keyword()) :: [component_metadata()]
```

Lists all Demos with optional filtering and pagination.

# `list_plugins`

```elixir
@spec list_plugins(keyword()) :: [component_metadata()]
```

Lists all Plugins with optional filtering and pagination.

# `list_sensors`

```elixir
@spec list_sensors(keyword()) :: [component_metadata()]
```

Lists all Sensors with optional filtering and pagination.

# `refresh`

```elixir
@spec refresh() :: :ok
```

Refreshes the component catalog by rescanning all loaded applications.

