# Plugin
`deft/stdext/plugin` is the generic package-plugin host. A plugin is a
Deft package whose manifest carries a discovery tag; the host scans the
configured package roots, evals each manifest, filters by tag, then
mounts and runtime-imports every hit. Per-type registries (AI providers,
editor extensions) are built by consumers on top of it.
import "deft/stdext/plugin" as plugin
## API
| Def | Signature | Description |
|---|---|---|
| `discover` | `{| tag |}` | Scan `pkg/list` for packages tagged `tag`; `@{ %{ name dir main source } }` |
| `load-one` | `{| entry prefix |}` | Mount + runtime-import one plugin; idempotent |
| `load-all` | `{| tag prefix |}` | Discover and load everything; `%{ loaded errors }` |
| `read-manifest` | `{| dir |}` | Eval `<dir>/package.dft` → `%Package` or nil |
| `manifest-main` / `has-tag?` | `{| manifest … |}` | Manifest helpers |
| `intern-module-map` | `{| m |}` | Normalize a Zig module map to keyword keys |
Loading mounts each plugin as `<prefix>-<name>` and imports it; discovery
is deduped by package name with earlier roots winning, so a dev
checkout shadows an installed copy. Loading is idempotent — re-running
discovery after an install reuses existing mounts.
## Contracts
A plugin's entry module declares a runtime contract:
# AI provider package entry implements AiProviderExtension def key :deepseek def label "DeepSeek" # …
The VM conformance-checks the module's exports against the contract
`deftype` at load time; a missing field is a load error, reported by the
consumer (for example `ai/discover-errors`). The contract types live in
Types.
## Example
set r [plugin/load-all "ai-provider" "ai"] for e $r~loaded { echo $e~name } for err $r~errors { [warn $err] }
`deft/stdext/ai/plugins` is the reference consumer; the editor extension
discovery in `deft/editor` follows the same pattern.
## See Also
- Types — the contract schemas
- AI — the reference consumer
- Zig Plugins — native, rather than Deft, extension path