# 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