Skip to content

Build a Plugin

Build a plugin when an integration needs a reviewed manifest for provider domains, credentials, OAuth, MCP endpoints, runtime dependencies, or bundled provider skills.

Use local app/plugins while iterating in one app. Publish an npm package when more than one app or team should use the integration.

Use the same shape locally and in packages:

Plugin package
my-junior-plugin/
├── package.json
├── plugin.yaml
└── skills/
└── my-provider/
└── SKILL.md

The package must include the manifest and skills in package.json:

package.json
{
"name": "@acme/junior-my-provider",
"type": "module",
"files": ["plugin.yaml", "skills"]
}

A plugin can be manifest-only:

plugin.yaml
name: my-provider
description: Internal workflow bundles

Add credential, MCP, API header, command env, and runtime dependency declarations only when the provider needs them.

Provider integrations should declare the authority surface in the manifest instead of hiding it in skill instructions:

plugin.yaml
name: my-provider
description: My provider integration
credentials:
type: oauth-bearer
domains:
- api.my-provider.example
auth-token-env: MY_PROVIDER_AUTH_TOKEN
auth-token-placeholder: host_managed_credential
oauth:
client-id-env: MY_PROVIDER_CLIENT_ID
client-secret-env: MY_PROVIDER_CLIENT_SECRET
authorize-endpoint: https://my-provider.example/oauth/authorize
token-endpoint: https://my-provider.example/oauth/token
mcp:
url: https://api.my-provider.example/mcp

This lets Junior validate and load the provider surface before a turn starts. Bundled skills are discovered from the package skills/ directory; they are not listed inside plugin.yaml.

If a skill needs a CLI or system package inside the sandbox, declare that in plugin.yaml:

plugin.yaml
runtime-dependencies:
- type: npm
package: my-provider-cli
version: 1.2.3
runtime-postinstall:
- cmd: my-provider-cli
args: ["install-assets"]

Junior merges runtime dependency declarations from all loaded plugins and prepares them with junior snapshot create.

Install the plugin next to @sentry/junior, then list it in juniorNitro:

nitro.config.ts
import { defineConfig } from "nitro";
import { juniorNitro } from "@sentry/junior/nitro";
export default defineConfig({
modules: [
juniorNitro({
plugins: {
packages: ["@acme/junior-my-provider"],
},
}),
],
});

Do not use the removed pluginPackages option. junior check rejects it.

Run validation before deploy:

Terminal window
pnpm exec junior check
pnpm exec junior snapshot create

junior check validates manifest and skill structure. junior snapshot create verifies runtime dependency snapshot inputs when your plugin declares them.

Use Plugins for packaged plugin registration, then verify auth behavior with Plugin Auth & Context.