Extension System
How Aleph discovers, registers, loads, and reloads plugin components while sharing the Skill and MCP backends.
Aleph has two related meanings for Extension:
- The user-facing Hub concept: one
Extensionwith kindSkill,Plugin, orMcp. - The
src/extension/plugin host: the runtime and registry that load plugin components.
The Hub façade routes by kind. The plugin host does not replace SkillSystem or McpManager; it integrates with them.
Architecture
ExtensionManager
├── DiscoveryManager
├── AdapterRegistry
├── PluginRegistry
├── PluginLoader
├── shared SkillSystem
├── HookExecutor
├── ServiceManager
└── ExtensionWatcherThe manager's startup path is:
scan scopes
→ parse and normalize a manifest
→ validate the candidate
→ resolve duplicate origins
→ register static capabilities
→ load Static, MCP, or WASM runtime
→ publish skills and agents
→ synchronize plugin MCP serversThe process-wide SkillSystem receives plugin skill roots, so plugin skills and filesystem skills share source precedence, snapshots, prompt XML, skill_read, status, and lifecycle operations.
Manifest adapters
The preferred format is .claude-plugin/plugin.toml, followed by the read-compatible .claude-plugin/plugin.json. aleph.plugin.toml remains a deprecated compatibility format and emits a warning. The adapter registry also accepts supported Codex and Cursor layouts and a final auto-discovery adapter.
Auto-discovery recognizes skills/, agents/, commands/, hooks/hooks.json, hooks.json, and .mcp.json. A directory containing one of these components can be treated as a static plugin without a manifest.
Unified capability registration
CapabilityDeclaration has six production variants:
pub enum CapabilityDeclaration {
Tool(ToolRegistration),
Hook(HookRegistration),
Service(ServiceRegistration),
Skill(SkillRegistration),
Agent(AgentRegistration),
McpServer(McpServerConfig),
}The registrar validates ownership, classifies the declaration tier, and dispatches it to the matching registry. Tools, hooks, and skills are core; agents are important; services and MCP servers are pluggable. Command Markdown is stored as a command-type skill.
The PluginRegistry tracks plugins and their registered tools, hooks, services, skills, and agents. It keeps qualified keys such as plugin:diagnostics:check alongside short compatibility names. Registration does not grant a plugin permission to bypass tool execution policy.
Runtime integration
| Plugin kind | Host |
|---|---|
| Static | Markdown components are registered without executable code |
| MCP | .mcp.json is translated to namespaced transient MCP servers |
| WASM | Extism loads the module and calls declared exports |
An MCP plugin server ID is plugin:<plugin-id>/<server-name>. The MCP manager owns process health and tool discovery. The extension manager's synchronization is idempotent and non-fatal when no live MCP handle is attached, such as in CLI or test paths.
WASM tool discovery is based on the plugin registration path. The module can register declarations through the WASM registrar; it is not documented as a Node.js IPC runtime.
Hooks and services
Hooks are executed through the shared HookExecutor:
interceptorhooks run in priority order and can alter or stop a protected operation.observerhooks run without becoming a blocking decision point.- The allowed kind depends on the event fire site.
- A matcher is evaluated against
tool_nameonly.
Runtime inventory exposes the resolved kind, priority, actions, consent state, and whether the hook is reachable. Hook output is capped at 64 KiB and hook timeouts at 300 seconds.
Background services require the plugin background permission and both a start and stop handler. Service lifecycle is coordinated during load, enable, disable, uninstall, hot reload, and daemon shutdown.
Discovery precedence
Scope directories are checked high to low:
agent > local > project > userDuplicate plugin IDs are resolved by origin priority:
config > workspace > global > bundledThe active record is loaded; overridden records remain visible for diagnostics. A .disabled marker prevents a directory from becoming a candidate.
Lifecycle safety
ExtensionManager::load_all is protected by a load guard. The manager also tracks active plugin tool snapshots and a monotonic revision so the tool registry can refresh without rebuilding unrelated parts of the loop. Concurrent reload calls are serialized.
Unloading a plugin performs runtime cleanup before deleting files. For MCP plugins, transient servers are removed from the live manager so processes and tools do not survive the plugin lifecycle. Malformed plugin results are returned as errors rather than being reported as successful service results.
Relationship with the Hub
The Hub catalog is implemented in src/hub/ and persists catalog entries in hub_catalog.db. It supplies an InstallSpec and routes a selected Plugin entry to the marketplace installer. The extension host then discovers and loads the installed plugin.
The Hub is the catalog and trust boundary. This module is the plugin runtime and registration boundary. Neither module creates a multi-provider catalog model, and plugin manifests do not declare model providers through a plugin-provider section.
Code locations
src/extension/mod.rs— manager and shared subsystem wiringsrc/extension/manifest/— adapters and normalized manifestssrc/extension/discovery/— candidates, scopes, and conflict resolutionsrc/extension/capability.rs— declarations and tierssrc/extension/registrar/— registration dispatchsrc/extension/registry/— component registrysrc/extension/loader.rs— runtime loadersrc/extension/hooks/— hook executor and consentsrc/extension/watcher.rs— change detection and reloadsrc/hub/— user-facing catalog and install router
Related pages
- Extensions — plugin manifest and runtime details
- Skills — shared skill authoring contract
- Skill System — skill backend
- Extensions Store — unified Hub surface
- Capability System — declarations, permissions, and runtime ledgers
Markdown Parsing & Text Utilities
Streaming-safe Markdown code-fence parser and shared UTF-8-safe text utilities across modules.
Bundled Content
Compile-time-embedded official skills / plugins / templates, extracted on startup via version comparison into `~/.aleph/bundled/`, with symlink-planting rejected.