Plugin Guide
Plugins extend Arcana's core functionality with custom tools, hooks, and behaviors. Unlike skills (which are instruction sets), plugins can modify the agent's runtime, add new tools, and intercept events.
Plugins vs Skills
| Aspect | Skill | Plugin |
|---|---|---|
| Format | SKILL.md (markdown) | JavaScript/TypeScript module |
| Capability | Instructions & context | Runtime code, tools, hooks |
| Loading | Always available | Requires workspace trust |
| Permissions | Read-only (instructions) | Requires explicit permission |
Plugin Structure
plugins/
my-plugin/
index.js # Entry point
package.json # Dependencies and metadata
README.md # Documentation
Plugin Manifest
{
"name": "my-plugin",
"version": "1.0.0",
"description": "Adds custom functionality to Arcana",
"arcana": {
"permissions": ["shell", "filesystem"],
"hooks": ["before:tool-call", "after:session-end"]
}
}
Plugin Permissions
Plugins must declare their required permissions in the manifest:
| Permission | Grants | Risk |
|---|---|---|
shell | Execute shell commands | High — can modify system |
filesystem | Read/write files | Medium — can modify project |
network | Make HTTP requests | Medium — data exfiltration risk |
memory | Read/write memory database | Low — affects agent context only |
ui | Modify TUI rendering | Low — display only |
Plugin Hooks
Hooks let plugins intercept events in the agent lifecycle:
// before:tool-call — runs before any tool executes
module.exports = {
'before:tool-call': async (context) => {
// context.tool — the tool being called
// context.args — the arguments
// Return false to block the tool call
if (context.tool === 'shell' && context.args.command.includes('rm -rf')) {
return false; // Block dangerous commands
}
},
'after:tool-call': async (context) => {
// Runs after tool execution
console.log(`Tool ${context.tool} completed`);
},
'before:session-start': async (context) => {
// Runs at session start
// Can modify system prompt, inject context
context.systemPrompt += '\nExtra context from plugin';
},
'after:session-end': async (context) => {
// Runs when session ends
// Good for cleanup, logging, analytics
}
};
Available Hooks
| Hook | Description |
|---|---|
before:session-start | Before session initialization |
after:session-end | After session cleanup |
before:tool-call | Before any tool execution |
after:tool-call | After tool execution |
before:prompt | Before sending prompt to LLM |
after:response | After receiving LLM response |
before:memory-write | Before writing to memory |
Loading Plugins
# Plugins are loaded from the project's plugins/ directory
# They require workspace trust to load
# Trust the workspace first
arcana trust
# Then start Arcana — plugins load automatically
arcana
Creating a Plugin
# 1. Create the plugin directory
mkdir -p plugins/my-plugin
# 2. Create package.json
cat > plugins/my-plugin/package.json << 'EOF'
{
"name": "my-plugin",
"version": "1.0.0",
"arcana": {
"permissions": ["shell"],
"hooks": ["before:tool-call"]
}
}
EOF
# 3. Create the plugin entry point
cat > plugins/my-plugin/index.js << 'EOF'
module.exports = {
'before:tool-call': async (ctx) => {
if (ctx.tool === 'shell') {
console.log(`[my-plugin] Shell command: ${ctx.args.command}`);
}
}
};
EOF
# 4. Trust and test
arcana trust
arcana
Security Considerations
- Plugins require workspace trust to load
- Declared permissions are shown to the user at load time
- Plugins run in the same process as Arcana
- Only load plugins from sources you trust
- Review plugin code before enabling in production