Building a Plugin
Scaffold new SimpleNS notification plugins with the @simplens/create-simplens-plugin CLI tool
The @simplens/create-simplens-plugin CLI tool generates all required boilerplate for building SimpleNS notification plugins, so you can focus on writing the delivery logic.
Quick Start
The fastest way to create a new plugin is with a single command:
npx @simplens/create-simplens-pluginThis launches an interactive wizard that guides you through configuration step by step.
Installation Methods
Run directly without installation:
npx @simplens/create-simplens-pluginInstall globally for frequent use:
npm install -g @simplens/create-simplens-plugin
create-simplens-pluginRequires Node.js 18+ to run.
Interactive Mode
When you run the CLI without flags, you'll be guided through an interactive wizard:
Plugin Name
Enter a kebab-case identifier (e.g., discord, telegram, twilio-sms).
- Must be lowercase with hyphens only
- Cannot start with
plugin-(this is added automatically) - Example valid names:
discord,slack-webhook,twilio-sms
Display Name
Human-readable name (auto-generated from plugin name as PascalCase).
Examples: Discord, SlackWebhook, TwilioSms
Description
Brief description of what your plugin does.
Must be at least 10 characters.
Channel Identifier
Lowercase alphanumeric channel ID used for routing notifications.
Defaults to the plugin name without hyphens (e.g., twilio-sms → twiliosms).
Author Information
- Author name (required)
- Author email (optional)
Output Directory
Where to create the plugin. Defaults to plugin-<name>.
Git & Dependencies
- Initialize a git repository? (Yes/No)
- Install npm dependencies after generation? (Yes/No)
Example Session
$ npx @simplens/create-simplens-plugin
🔌 Create SimpleNS Plugin
? Plugin name: discord
? Display name: Discord
? Description: Send notifications via Discord webhooks
? Channel identifier: discord
? Author name: John Doe
? Author email: john@example.com
? Output directory: plugin-discord
? Initialize git repository? Yes
? Install dependencies after generation? Yes
✅ Plugin created successfully!
📁 Created plugin-discord/
├── package.json
├── tsconfig.json
├── src/
│ ├── index.ts ← Implement your send() logic here
│ └── index.test.ts
├── README.md
└── .gitignore
🚀 Next steps:
1. cd plugin-discord
2. Edit src/index.ts # Add your delivery logic
3. npm test # Run tests
4. npm run build # Build for publishing
5. npm publish --access publicNon-Interactive Mode (CLI Flags)
For automation, CI/CD pipelines, or scripting, use command-line flags to skip prompts entirely.
Command Reference
create-simplens-plugin [options]| Option | Alias | Description | Default |
|---|---|---|---|
--name <name> | -n | Plugin name (kebab-case) | required with --yes |
--channel <channel> | -c | Channel identifier | Plugin name without hyphens |
--directory <dir> | -d | Output directory | plugin-<name> |
--yes | -y | Skip prompts, use defaults | false |
--no-git | — | Skip git initialization | false |
--no-install | — | Skip npm install | false |
--help | -h | Show help | — |
--version | -V | Show version | — |
Quick Scaffolding
Create a plugin with minimal input:
npx @simplens/create-simplens-plugin --name discord --yesThis uses sensible defaults for all other options.
Full Customization
Specify all options explicitly:
npx @simplens/create-simplens-plugin \
--name twilio-sms \
--channel sms \
--directory ./plugins/twilio-sms \
--no-git \
--no-installCI/CD Example
- name: Generate Plugin
run: |
npx @simplens/create-simplens-plugin \
--name ${{ inputs.plugin_name }} \
--channel ${{ inputs.channel }} \
--yes \
--no-gitWhen using --yes, the --name flag is required. The CLI will exit with an error if not provided.
Generated Files
The CLI generates a complete, ready-to-develop plugin structure:
File Descriptions
| File | Purpose |
|---|---|
package.json | NPM package config with @simplens/sdk dependency |
tsconfig.json | TypeScript configuration for ES modules |
src/index.ts | Main provider class — implement send() here |
src/index.test.ts | Vitest test suite with basic scaffolding |
README.md | Documentation template for your plugin |
.gitignore | Standard ignores for Node.js/TypeScript |
Implementing Your Plugin
After scaffolding, you need to implement the actual notification delivery logic.
Define Your Schemas
In src/index.ts, customize the Zod schemas:
// Define who receives notifications
const recipientSchema = z.object({
channelId: z.string(),
userId: z.string().optional(),
});
// Define notification content
const contentSchema = z.object({
message: z.string(),
title: z.string().optional(),
embeds: z.array(z.object({
title: z.string(),
description: z.string(),
})).optional(),
});Implement the send() Method
Add your API client and delivery logic:
async send(notification: Notification): Promise<DeliveryResult> {
if (!this.config) {
return {
success: false,
error: {
code: 'NOT_INITIALIZED',
message: 'Provider not initialized',
retryable: false
},
};
}
try {
const webhookUrl = this.config.credentials.webhook_url;
await fetch(webhookUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
content: notification.content.message,
}),
});
return { success: true };
} catch (error) {
return {
success: false,
error: {
code: 'DELIVERY_FAILED',
message: error.message,
retryable: true,
},
};
}
}Update the Manifest
Add required credentials and update metadata:
readonly manifest: ProviderManifest = {
name: 'simplens-plugin-discord',
version: '1.0.0',
channel: 'discord',
displayName: 'Discord',
description: 'Send notifications via Discord webhooks',
author: 'Your Name',
homepage: 'https://github.com/your-repo',
requiredCredentials: ['webhook_url'], // List required credentials
};Add Tests
Expand the generated test file with your specific test cases:
it('should send notification successfully', async () => {
// Mock your API client
vi.spyOn(global, 'fetch').mockResolvedValue({
ok: true,
} as Response);
await provider.initialize({
id: 'test',
credentials: { webhook_url: 'https://discord.com/api/webhooks/...' },
options: {}
});
const result = await provider.send({
id: 'test-1',
channel: 'discord' as const,
recipient: { channelId: '123' },
content: { message: 'Hello!' },
created_at: new Date(),
});
expect(result.success).toBe(true);
});Build & Publish
# Build TypeScript
npm run build
# Run tests
npm test
# Publish to npm
npm publish --access publicDefault Configuration
When using --yes mode, these defaults are applied:
| Setting | Default Value |
|---|---|
| Display Name | PascalCase of plugin name |
| Description | "Send notifications via <DisplayName>" |
| Channel | Plugin name without hyphens |
| Author | "Unknown" |
| Empty | |
| Recipient Fields | ["userId"] |
| Content Fields | ["message"] |
| Directory | plugin-<name> |
| Init Git | true |
| Install Deps | true |
Troubleshooting
Error: Plugin name is required when using --yes flag
Always provide --name when using --yes mode:
npx @simplens/create-simplens-plugin --yes --name my-pluginError: Plugin name must be lowercase kebab-case
Use only lowercase letters, numbers, and hyphens. Don't include the plugin- prefix:
- ❌
MyPlugin,Plugin-Discord,DISCORD - ✅
discord,twilio-sms,slack-webhook
Git not found, skipping repository initialization
Install Git or use --no-git to skip this step.
Next Steps
After creating your plugin:
- Implement the
send()method with your delivery logic - Add comprehensive tests for reliability
- Update the README with usage documentation
- Publish to npm with
npm publish --access public - Install the plugin in simplens-core using
npm run plugin:install <npm_package_name>
For more details on the plugin SDK interface, see the Plugin Interface documentation.
Docs