Creating Plugins
This guide walks through creating a plugin from scratch: scaffolding, writing hooks, adding skills and MCP servers, building, testing, and publishing.
1. Scaffold
Run agentplugins init to bootstrap a plugin from a template:
agentplugins initYou'll be prompted for:
- Plugin name — kebab-case identifier.
- Description — minimum 10 characters.
- Template — one of the starter templates.
- Targets — which platforms to compile for (default: all).
Templates
| Template | What you get |
|---|---|
minimal | Bare manifest. Good starting point. |
logger | A plugin that logs every hook event to ${PLUGIN_DATA}/log.jsonl. |
security-guard | A preToolUse block-list for dangerous commands. |
formatter | A postToolUse hook that runs your formatter of choice. |
Pick minimal if you're not sure — you can add hooks later.
? Plugin name (kebab-case) › my-plugin
? Description › Does awesome things across every agent
? Template › minimal
? Targets › claude, codex, copilot, gemini, kimi, opencode, pimono
✓ Created my-plugin/
my-plugin/agentplugins.config.ts
my-plugin/package.json
my-plugin/tsconfig.json
my-plugin/.gitignore
my-plugin/README.mdHooks, skills, and commands are declared inline in agentplugins.config.ts — there is no separate SKILL.md or hooks/ directory in the scaffold. Open agentplugins.config.ts to start editing.
2. Write hooks
Open agentplugins.config.ts and add hooks to the hooks object. See the Hooks guide for the 19 universal hooks and the three handler types.
import { definePlugin } from '@agentplugins/core'
export default definePlugin({
name: 'my-plugin',
version: '1.0.0',
description: 'Does awesome things across every agent',
hooks: {
preToolUse: {
matcher: 'bash',
handler: {
type: 'command',
command: '${PLUGIN_ROOT}/hooks/pre-tool-use.sh',
},
},
sessionStart: {
handler: {
type: 'inline',
handler: async () => ({
additionalContext: 'my-plugin is active.',
}),
},
},
},
})defineConfig — extended config format
Use defineConfig instead of definePlugin when you need to:
- Target a subset of platforms without editing the manifest
- Wire in a private adapter for an internal harness
- Add build pipeline plugins (custom lint rules, IR transforms, post-emit hooks)
import { defineConfig } from '@agentplugins/core'
export default defineConfig({
manifest: {
name: 'my-plugin',
version: '1.0.0',
description: 'Does awesome things across every agent',
hooks: { /* ... */ },
},
// Override which targets are built — does not affect the manifest
targets: ['claude', 'codex'],
})definePlugin and defineConfig produce the same dist output for the same manifest. Pick definePlugin for simple cross-platform plugins; reach for defineConfig when you need the extras above.
See Extending the Build Pipeline for plugins: [...] and custom adapters.
TIP
Place hook scripts under hooks/ and reference them with ${PLUGIN_ROOT}/hooks/.... The placeholder resolves to the plugin's directory in the universal store at runtime.
3. Add skills
Drop a SKILL.md file into skills/<skill-name>/:
mkdir -p skills/my-skill
$EDITOR skills/my-skill/SKILL.md---
name: my-skill
description: Teaches the agent how to do something specific.
tags:
- productivity
---
# My Skill
When the user asks to do X, follow these steps:
1. ...
2. ...Then declare it in the manifest:
skills: [
{
name: 'my-skill',
description: 'Teaches the agent how to do something specific.',
path: './skills/my-skill/SKILL.md',
tags: ['productivity'],
},
],See the Skills guide for the full SKILL.md spec.
4. Add MCP servers
Wire external tools and data sources into the agent with MCP servers:
mcpServers: {
filesystem: {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-filesystem', '${HOME}/projects'],
},
},5. Build
Compile the manifest into each target platform's native format:
agentplugins buildBuilding my-plugin@1.0.0
claude → dist/claude/.claude-plugin/plugin.json ✓
codex → dist/codex/.codex-plugin/plugin.json ✓
copilot → dist/copilot/plugin.json ✓
gemini → dist/gemini/gemini-extension.json ✓
kimi → dist/kimi/kimi.plugin.json ✓
opencode → dist/opencode/plugin.ts + opencode.json ✓
pimono → dist/pimono/index.ts + package.json ✓
Built 7 targets in 142ms.Inspect dist/ to see exactly what each adapter emitted.
6. Test locally
Install the plugin from your local working copy to verify the symlinks land in the right place:
agentplugins add ./my-plugin✓ Installed my-plugin@1.0.0 from local path
✓ Symlinked to 4 detected agents.Then run list to confirm:
agentplugins listValidate the manifest and surface cross-platform issues:
agentplugins validateAnd run the linter to catch common mistakes:
agentplugins lintSee Linting for the full rule set.
7. Publish
Push the plugin to a public GitHub repository. Once it's on GitHub, anyone can install it:
agentplugins add your-username/my-pluginRecommended repository layout
my-plugin/
├── agentplugins.config.ts # manifest (or agentplugins.json)
├── SKILL.md # optional root skill
├── skills/
│ └── my-skill/
│ └── SKILL.md
├── hooks/
│ ├── pre-tool-use.sh
│ └── session-start.sh
├── bin/
│ └── my-server # MCP server binary (if any)
├── README.md
└── LICENSETIP
Tag releases with semver (v1.0.0, v1.1.0, ...). agentplugins update resolves to the latest tag, and users can pin a specific version with agentplugins add user/repo@1.0.0.
Next steps
- Manifest reference — every field.
- Hooks — the 19 lifecycle events.
- Extending the Build Pipeline — custom adapters, lint rules, and pipeline plugins.
- CLI reference — every command and flag.

