Plugins
A plugin lives at <workspace>/plugins/<name>/. The host introspects the directory: the manifest names the plugin, and each named subdirectory is a surface. Missing directories are skipped.
Directory layout
my-plugin/
├── package.json # Manifest (required)
├── README.md
├── config.json # User-editable, preserved
├── data/ # Runtime data, preserved
├── hooks/
├── tools/
├── routes/
├── apps/
├── skills/
└── src/ # Internal modules, not walked
- Compiled files win:
.jsover.tsfor the same basename. - A broken surface file fails only itself. Sibling plugins keep loading.
- Each plugin has a 10s import budget.
You can also drop a surface straight into /workspace/<surface>/ without a plugin. A plugin is the distribution unit.
Preserved entries
| Entry | Purpose |
|---|---|
config.json | User-editable config. init reads it. |
data/ | Plugin-owned storage. Path is InitContext.pluginStorageDir. |
.disabled | Sentinel from assistant plugins disable. Skips the plugin. |
Uninstall removes the whole directory. No orphaned state.
State is plugin-owned
Create schema in init (idempotent). Close handles in shutdown. Purge per-conversation rows in conversation-deleted. The assistant database is not a plugin store. Import only from @aevumcadence/plugin-api.
The manifest
{
"name": "@you/my-plugin",
"version": "0.0.1",
"peerDependencies": {
"@aevumcadence/plugin-api": ">=0.8.0"
}
}
name is required. The loader strips the scope. The unscoped portion must be kebab-case. The default- prefix is reserved. A peer-range mismatch is logged while plugins are still stabilizing.
When to write a plugin
When you want to package a capability to share, version, or install across assistants. For a personal one-off, drop the file in the matching workspace directory instead. See Distribution.