---
title: Plugin Guide
url: https://arcana.otnelhq.com/docs/plugin-guide
---

# 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



```bash
# 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



```bash
# 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
