Extension System
Plugin and skill management with WASM and Node.js runtimes, manifest-driven registration, and unified hook execution.
The extension module provides a unified extension system for Aleph. It supports both plugins (WASM and Node.js runtimes) and skills, with manifest-driven registration, a unified registry, and hook-based integration.
Design Philosophy
- Unified registry — Everything a plugin can provide (tools, channels, HTTP routes) is registered in a single
PluginRegistry - Capability declarations — Plugins declare what they provide via
CapabilityDeclaration(see Capability System) - Sandboxed runtimes — WASM plugins run in a sandbox; Node.js plugins run in separate processes
- Hot reload — Extensions can be added, updated, or removed without restarting
Architecture
┌─────────────────────────────────────────────────────────────────────────┐
│ ExtensionManager │
│ - Orchestrates discovery, loading, registration, integration │
└────────────────────────────┬───────────────────────────────────────────┘
│
┌───────────────────┼───────────────────┐
▼ ▼ ▼
PluginRegistry PluginLoader SkillSystem
(unified registry) (Node.js, WASM) (skills, agents)
│ │ │
└───────────────────┼───────────────────┘
│
▼
HookExecutor
(unified hooks)Core Components
ExtensionManager
Central coordinator for all extensions:
pub struct ExtensionManager {
registry: PluginRegistry,
loader: PluginLoader,
skill_system: SkillSystem,
}
impl ExtensionManager {
pub async fn discover(&self,
) -> Result<Vec<PluginManifest>> { /* ... */ }
pub async fn load(
&self,
manifest: &PluginManifest,
) -> Result<LoadedPlugin> { /* ... */ }
pub async fn register(
&self,
plugin: LoadedPlugin,
) -> Result<()> { /* ... */ }
}PluginRegistry
Unified registry for all plugin-provided capabilities:
pub struct PluginRegistry {
tools: HashMap<String, ToolRegistration>,
channels: HashMap<String, ChannelRegistration>,
hooks: HashMap<String, HookRegistration>,
http_routes: Vec<HttpRouteRegistration>,
providers: HashMap<String, ProviderRegistration>,
}Registration types:
Tool— Callable functions for the agentHook— Event interceptorsChannel— Messaging interface integrationsProvider— AI model backendsHttpRoute— REST API endpointsCli— CLI commandsService— Background servicesCommand— In-chat commandsSkill— Prompt-based skillsAgent— Agent definitionsMcpServer— MCP server configurations
PluginLoader
Loads plugins from different sources:
pub struct PluginLoader;
impl PluginLoader {
pub async fn load_wasm(
&self,
path: &Path,
) -> Result<WasmPlugin> { /* ... */ }
pub async fn load_nodejs(
&self,
path: &Path,
) -> Result<NodeJsPlugin> { /* ... */ }
}WASM runtime: Uses Extism for sandboxed execution. Limited I/O, fast startup.
Node.js runtime: Spawns Node.js process with IPC communication. Full Node.js API access.
Manifest
Plugins declare their capabilities in a manifest file:
[plugin]
id = "my-plugin"
name = "My Plugin"
version = "1.0.0"
[[capabilities]]
type = "tool"
name = "my_tool"
description = "Does something useful"
[[capabilities]]
type = "hook"
event = "message_received"Manifest formats:
plugin.toml— TOML formatplugin.json— JSON formatcc-plugin.json— Claude Code compatible.mcp.json— MCP server config
Scope
Plugins operate within a scope that limits their access:
pub struct PluginScope {
allowed_apis: Vec<String>,
file_access: FileAccessPolicy,
network_access: NetworkAccessPolicy,
}Hook System
Hooks allow plugins to intercept and modify system events:
pub enum HookEvent {
MessageReceived { message: Message },
ToolInvoked { name: String, args: Value },
ResponseGenerated { text: String },
}
pub trait HookHandler: Send + Sync {
async fn handle(
&self,
event: &HookEvent,
) -> HookResult;
}HookResult:
Continue— Proceed with the eventIntercept { modified }— Replace the event with modified versionBlock { reason }— Cancel the event
Discovery
Extensions are discovered from multiple locations:
~/.aleph/plugins/— User-installed plugins./.aleph/plugins/— Project-level plugins- Built-in plugins bundled with Aleph
The PluginWatcher monitors these directories for changes and triggers hot reload.
Safety Properties
- Sandboxed WASM — Extism provides memory isolation and capability-based security
- Scope enforcement — Plugins can only access declared APIs
- Manifest validation — All manifests are validated before loading
- No
static mut— UsesOnceLockfor lazy initialization
Code Location
src/extension/mod.rs—ExtensionManagersrc/extension/registry.rs—PluginRegistrysrc/extension/loader.rs—PluginLoadersrc/extension/manifest/— Manifest parsingsrc/extension/runtime/— WASM and Node.js runtimessrc/extension/hooks/— Hook systemsrc/extension/watcher.rs— Hot reload watchersrc/extension/scope.rs— Permission scopes
See Also
- Capability System — Plugin capability declarations
- Skill System — Skill management
- Extensions — Conceptual overview (if exists)