Plugin Development
This library is currently in early development (pre-1.0). The plugin API is subject to change without notice. If you're interested in building a plugin, please wait until the API stabilizes or be prepared to update your code frequently.
Overview
a16n uses a plugin architecture to support different AI coding tools. Each plugin handles:
- Discovery - Finding agent customization files in a project
- Emission - Writing converted files to the target format
Plugin Interface
Plugins implement the A16nPlugin interface from @a16njs/models. See the Models API Reference for complete interface documentation.
The key methods are:
discover(root)- Scan a directory and return found customizationsemit(models, root, options)- Write customizations to disk in the plugin's format
import type { A16nPlugin } from '@a16njs/models';
import { CustomizationType } from '@a16njs/models';
const myPlugin: A16nPlugin = {
id: 'my-agent',
name: 'My Agent',
supports: [CustomizationType.GlobalPrompt, CustomizationType.FileRule],
async discover(root: string) {
// Return { items: [...], warnings: [...] }
},
async emit(models, root, options) {
// Return { written: [...], warnings: [...], unsupported: [...] }
}
};
export default myPlugin;
Key Concepts
Customization Types
Plugins declare which types they support via the supports array:
GlobalPrompt- Always-applied system promptsAgentSkill- Description-triggered contextual rulesFileRule- File pattern-triggered rulesAgentIgnore- File ignore patternsManualPrompt- Slash commands
See Understanding Conversions for detailed explanations.
Discovery
Discovery scans a project directory and returns customizations in the intermediate representation:
async discover(root: string): Promise<DiscoveryResult> {
const items: AgentCustomization[] = [];
const warnings: Warning[] = [];
// Scan for config files specific to this tool
// Parse and convert to AgentCustomization items
return { items, warnings };
}
Emission
Emission converts intermediate representation back to the plugin's native format:
async emit(
items: AgentCustomization[],
root: string,
options?: EmitOptions
): Promise<EmitResult> {
const written: WrittenFile[] = [];
const warnings: Warning[] = [];
const unsupported: AgentCustomization[] = [];
for (const item of items) {
if (this.supports.includes(item.type)) {
// Convert and write file
} else {
unsupported.push(item);
}
}
return { written, warnings, unsupported };
}
Project Structure
Recommended plugin structure:
packages/plugin-example/
├── src/
│ ├── index.ts # Plugin entry point & exports
│ ├── discover.ts # Discovery logic
│ └── emit.ts # Emission logic
├── test/
│ ├── fixtures/ # Test fixtures
│ ├── discover.test.ts
│ └── emit.test.ts
├── package.json
├── tsconfig.json
└── README.md
Learning from Existing Plugins
The best way to understand plugin development is to study the existing implementations:
@a16njs/plugin-cursor
The Cursor plugin demonstrates:
- MDC file parsing (YAML frontmatter + markdown body)
- Multiple file types (rules, commands, ignore files)
- Frontmatter-based type classification
Key files:
discover.ts- Glob-based file discovery, MDC parsingemit.ts- MDC generation with proper frontmattermdc.ts- MDC format utilities
@a16njs/plugin-claude
The Claude plugin demonstrates:
- Single-file aggregation (
CLAUDE.mdmerging) - Settings JSON handling
- Hook configuration generation for FileRules
Key files:
discover.ts- CLAUDE.md parsing, settings.json readingemit.ts- Section-based file merging, hook generation
Publishing
Community plugins can be published to npm:
- Scoped:
@a16njs/plugin-<name>(requires organization membership) - Unscoped:
a16n-plugin-<name>(anyone can publish)
a16n automatically discovers installed plugins matching these patterns.
See Also
- Models API Reference - Plugin interface documentation
- Plugin: Cursor - Cursor implementation details
- Plugin: Claude - Claude implementation details
- Understanding Conversions - Type taxonomy
- GitHub Repository - Source code