Skip to content

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:

bash
agentplugins init

You'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 ​

TemplateWhat you get
minimalBare manifest. Good starting point.
loggerA plugin that logs every hook event to ${PLUGIN_DATA}/log.jsonl.
security-guardA preToolUse block-list for dangerous commands.
formatterA postToolUse hook that runs your formatter of choice.

Pick minimal if you're not sure — you can add hooks later.

text
? 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.md

Hooks, 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.

typescript
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)
typescript
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>/:

bash
mkdir -p skills/my-skill
$EDITOR skills/my-skill/SKILL.md
markdown
---
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:

typescript
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:

typescript
mcpServers: {
  filesystem: {
    command: 'npx',
    args: ['-y', '@modelcontextprotocol/server-filesystem', '${HOME}/projects'],
  },
},

5. Build ​

Compile the manifest into each target platform's native format:

bash
agentplugins build
text
Building 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:

bash
agentplugins add ./my-plugin
text
✓ Installed my-plugin@1.0.0 from local path
✓ Symlinked to 4 detected agents.

Then run list to confirm:

bash
agentplugins list

Validate the manifest and surface cross-platform issues:

bash
agentplugins validate

And run the linter to catch common mistakes:

bash
agentplugins lint

See 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:

bash
agentplugins add your-username/my-plugin
text
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
└── LICENSE

TIP

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 ​

Released under the Apache License 2.0.