# `PhoenixKit.ModuleDiscovery`
[🔗](https://github.com/BeamLabEU/phoenix_kit/blob/v1.7.87/lib/phoenix_kit/module_discovery.ex#L1)

Zero-config auto-discovery of external PhoenixKit modules.

Uses the same pattern as Elixir's protocol consolidation: scans `.beam` files
for persisted `@phoenix_kit_module` attributes via `:beam_lib.chunks/2`.
No module loading required — pure file I/O.

## How It Works

1. `use PhoenixKit.Module` persists `@phoenix_kit_module true` in the `.beam` file
2. This module scans only deps that depend on `:phoenix_kit` (fast, targeted)
3. Reads the persisted attribute from each beam file without loading the module
4. Works at both compile time (route generation) and runtime (ModuleRegistry)

## Fallback

Also reads `Application.get_env(:phoenix_kit, :modules, [])` for backwards
compatibility. Both sources are merged and deduplicated.

# `discover_external_modules`

```elixir
@spec discover_external_modules() :: [module()]
```

Discovers external PhoenixKit modules from beam files + config fallback.

Returns a deduplicated list of module atoms that implement `PhoenixKit.Module`.
Excludes internal modules (those in the `PhoenixKit.Modules` namespace that are
bundled with PhoenixKit itself).

# `module_hash`

```elixir
@spec module_hash() :: binary()
```

Returns a deterministic hash of the current set of discovered external modules.

Used by `__mix_recompile__?/0` (injected into the host router) to detect when
modules are added or removed, triggering router recompilation.

# `scan_beam_files`

```elixir
@spec scan_beam_files() :: [module()]
```

Scans beam files of phoenix_kit-dependent apps for `@phoenix_kit_module` attribute.

Only checks apps that explicitly list `:phoenix_kit` in their dependencies,
keeping the scan fast and targeted.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
