# `MobDev.Plugin.RuntimeManifest`
[🔗](https://github.com/genericjam/mob_dev/blob/master/lib/mob_dev/plugin/runtime_manifest.ex#L1)

Builds the host's **runtime plugin manifest** — the device-readable record of
the activated plugins' tier-3/4 contributions.

Tiers 3 and 4 are pure-Elixir and runtime-wired: the host needs to know, on
device, which screens exist, what lifecycle/settings/notification declarations
each plugin made — but `MobDev.Plugin.activated/0` is compile-time only. So at
build time this module gathers those sections (running any spec-v2
`:screens_generator` under the host-config audit) and emits a terms file
(`priv/generated/mob_plugins.exs`) that the core `Mob.Plugins` module reads at
boot. It mirrors the `driver_tab` / `MobPluginBootstrap` codegen pattern, but
for serializable Elixir data instead of native symbols.

Only the behavioral data lives here. Migration files and font/image assets are
physically copied into the host at build time (see `native_build`), not carried
in this manifest.

Everything emitted must be serializable terms — atoms, tuples, maps, strings,
integers. The manifest validator forbids closures in plugin sections so this
always holds.

# `build`

```elixir
@spec build([{Path.t(), map() | nil}]) :: map()
```

Builds the merged runtime manifest map from `{plugin_dir, manifest}` pairs.

Static `:screens` and spec-v2 `:screens_generator` output are combined (each
tagged with its plugin); generators run under `MobDev.Plugin.with_host_config_audit/3`
so an undeclared host-config read fails the build.

# `render`

```elixir
@spec render(map()) :: String.t()
```

Renders the manifest map to the contents of `priv/generated/mob_plugins.exs` —
a self-describing `.exs` that evaluates back to the map.

# `validate_generated_screens`

```elixir
@spec validate_generated_screens(term(), atom() | nil) :: [map()]
```

Validates a `:screens_generator`'s output, raising on malformed specs.

A generator must return a list of `%{module: atom, default_route: binary}`
maps (a bare map is wrapped). This mirrors `MobDev.Plugin.Manifest`'s static
`:screens` validation so generator-produced screens are held to the same
shape contract — otherwise a typo'd or wrong-typed spec would be written into
`mob_plugins.exs` and silently dropped at boot (`Mob.Plugins.register_screens/0`
pattern-matches `%{module:, default_route:}` and skips non-matching maps),
making the plugin's screen vanish with no build-time error.

Returns the validated screen list (without the `:plugin` tag, which the caller
adds). Public for testing.

# `write`

```elixir
@spec write(Path.t(), map()) :: Path.t()
```

Writes the rendered manifest to `<host_root>/priv/generated/mob_plugins.exs`
and returns the path.

---

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