Create a Vibe Plugin
A plugin is a directory containing a plugin.json manifest (Agent Plugins 1.0
schema) plus optional component directories and config files. Vibe discovers
plugins under .vibe/plugins/ (project scope, requires trusted folder) and
~/.vibe/plugins/ (user global).
Plugin discovery locations
| Scope | Path | When |
|---|---|---|
| Project | <project>/.vibe/plugins/<name>/ | trusted folder only |
| User global | ~/.vibe/plugins/<name>/ | always |
Each subdirectory under a plugins root is one plugin package. The first match wins: project plugins take precedence over user plugins with the same name.
Plugin directory structure
my-plugin/ plugin.json # required — Agent Plugins 1.0 manifest mcp.json # optional — MCP server definitions libraries.json # optional — Node/Python library dependencies connectors.json # optional — managed connector requirements skills/ # optional — one subdirectory per skill my-skill/ SKILL.md ai.mistral.vibe/ # optional — Vibe-specific extensions hooks.toml # Vibe extension only knowledge/ # one subdirectory per knowledge folder topic-name/ KNOWLEDGE.md agents/ # one .toml per subagent researcher.toml INSTRUCTIONS.md # optional plugin-wide instructions (not loaded)
Step 1 — plugin.json (required)
The manifest is a JSON file with $schema and name as required fields.
json{ "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json", "name": "my-plugin", "version": "1.0.0", "description": "What this plugin provides.", "author": { "name": "Author Name", "email": "author@example.com", "url": "https://example.com" }, "homepage": "https://example.com/my-plugin", "repository": "https://github.com/example/my-plugin", "license": "MIT", "keywords": ["productivity", "finance"], "extensions": {} }
Rules:
namemust match^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$(1-64 chars), no--or...$schemamust be exactlyhttps://agent-plugins.org/schemas/1.0.0/plugin.schema.json. Any other schema URL produces a fatalplugin.schema.version_unsupportederror.- All fields other than those listed above are rejected (
extra="forbid").
Step 2 — Vibe extension (optional)
To use Vibe-specific components (hooks, knowledge, agents, libraries,
connectors), add an ai.mistral.vibe extension to plugin.json:
json{ "extensions": { "ai.mistral.vibe": { "schemaVersion": 1, "toolNamespace": "myPlugin", "toolOverrides": { "lookup": { "name": "search", "exposure": "direct_and_programmatic" } } } } }
Without this extension, Vibe only loads plugin.json, skills/, and
mcp.json. The toolNamespace defaults to a TypeScript identifier derived
from the plugin name. It must not be one of the reserved namespaces:
file_system, self, process, agent, vibe.
vibe is reserved for built-in plugins shipped with the CLI; user plugins
must choose a different namespace.
toolOverrides rename or restrict tool exposure. Each key matches a discovered
tool name from MCP servers or connectors. exposure is one of
programmatic, direct, or direct_and_programmatic.
Step 3 — Skills (optional)
Place skills under skills/ — one subdirectory per skill, each containing a
SKILL.md. The skill name in SKILL.md frontmatter must match the directory
name.
skills/ format-reports/ SKILL.md
Skills follow the standard SKILL.md format with YAML frontmatter (name,
description, user-invocable, allowed-tools). Plugin skills are namespaced
as <namespace>:<skill-name> at runtime.
Step 4 — MCP servers (optional)
Define MCP servers in mcp.json. Three transport types are supported:
json{ "$schema": "https://agent-plugins.org/schemas/1.0.0/mcp.schema.json", "mcpServers": { "lookup": { "type": "stdio", "command": "node", "args": ["${PLUGIN_ROOT}/server/index.js"], "env": { "DEBUG": "true" }, "cwd": "." }, "remote-api": { "type": "streamable-http", "url": "https://api.example.com/mcp", "headers": { "X-Custom-Header": "value" } } } }
Rules:
command,args, andenvvalues support${PLUGIN_ROOT}and${PLUGIN_DATA}variable expansion.PLUGIN_ROOTandPLUGIN_DATAare also injected automatically intoenv; do not set them yourself (rejected with an error).envvariable namesPLUGIN_ROOTandPLUGIN_DATAare reserved.cwdof.means the plugin root.streamable-httpservers support staticheadersonly; use OAuth at the Vibe config level for authenticated remote servers.ssetransport is detected but not supported — it produces a diagnostic.- The
commandfor stdio servers is resolved relative to the plugin root when it is a bare filename; absolute paths are used as-is.
Step 5 — Hooks (optional, Vibe extension only)
Place hooks in ai.mistral.vibe/hooks.toml. Format is identical to the Vibe
hooks.toml format, but hooks run in the plugin root directory with
PLUGIN_ROOT and PLUGIN_DATA in the environment.
toml[[hooks]] name = "guard-lookup" type = "pre_tool" match = "myPlugin.lookup" command = "python guard.py" strict = true [[hooks]] name = "post-agent-lint" type = "post_agent" command = "eslint --quiet ."
Limits:
- Maximum 128 hooks per plugin.
- File size limit: 64 KB.
- Hook names must be unique within the plugin. Runtime names are prefixed as
<plugin-name>:<hook-name>.
Step 6 — Knowledge (optional, Vibe extension only)
Place knowledge folders under ai.mistral.vibe/knowledge/. Each folder
contains a KNOWLEDGE.md with YAML frontmatter:
ai.mistral.vibe/ knowledge/ accounting-policy/ KNOWLEDGE.md reference.md
KNOWLEDGE.md frontmatter:
yaml--- name: accounting-policy description: How revenue is recognized and reported. display_name: Accounting Policy icon: book ---
Rules:
namemust match the directory name (^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$).descriptionis 5-300 characters.- Maximum 100 knowledge folders per plugin.
KNOWLEDGE.mdentrypoint limit: 256 KB.- No symbolic links inside knowledge directories.
- Knowledge is namespaced as
<namespace>:<name>.
Step 7 — Agents (optional, Vibe extension only)
Place subagent definitions under ai.mistral.vibe/agents/. Each .toml file
defines one subagent:
ai.mistral.vibe/ agents/ researcher.toml
researcher.toml:
tomlschemaVersion = 1 agentType = "subagent" displayName = "Researcher" description = "Searches the knowledge base and summarizes findings." safety = "safe" activeModel = "mistral-medium-3.5" instructions = "You are a research assistant." enabledTools = ["read_file", "grep"] disabledTools = ["bash"] [tools.bash] permission = "never" allowlist = ["ls"] denylist = ["rm"]
Rules:
schemaVersionmust be 1.agentTypemust be"subagent"(the only supported type).- Filename must be lowercase kebab-case (
^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$). safetyis one of"safe","neutral","destructive","yolo".- Maximum 128 agents per plugin, 64 KB per file.
- Tool lists cannot contain duplicates or empty names.
- Agent names are namespaced as
<namespace>:<filename-stem>.
Step 8 — Libraries (optional, Vibe extension only)
Declare Node and Python library dependencies in libraries.json:
json{ "schemaVersion": 1, "node": { "@productivity/finance": "./node/finance", "lodash": "./node/lodash" }, "python": { "vibe_finance": "./python/vibe_finance", "utils": "./python/utils.py" } }
Rules:
- Node aliases must match
^(?:@[a-z0-9][a-z0-9._-]*/)?[a-z0-9][a-z0-9._-]*$(max 214 chars). - Python aliases must match
^[A-Za-z_][A-Za-z0-9_]*$(max 128 chars). - Source paths are relative to the plugin root, using forward slashes only.
No
..or absolute paths. - Python library sources can be a directory (package) or a single
.pyfile. - Node library sources must be directories.
- No symbolic links inside library directories.
- Library aliases that collide across plugins are all dropped.
- Maximum 128 entries per language.
Step 9 — Connectors (optional, Vibe extension only)
Declare required managed connectors in connectors.json:
json{ "schemaVersion": 1, "connectors": [ { "id": "github", "tools": ["create_issue", "list_issues"] }, { "id": "linear", "tools": ["create_issue"] } ] }
Rules:
- Connector IDs must be unique within the plugin.
- Tool names per connector must be unique, 1-256 characters.
- Maximum 128 connector requirements.
- A connector requirement is a declaration: it appears whether or not the account has the connector. Availability is reported as a diagnostic.
Diagnostic codes
When a plugin fails to load or has issues, Vibe emits typed diagnostics. The most common ones:
| Code | Fatal | Meaning |
|---|---|---|
plugin.manifest.invalid | yes | plugin.json missing, unreadable, or invalid |
plugin.schema.version_unsupported | yes | unsupported schema version |
plugin.compatibility.format_unrecognized | yes | no supported manifest found |
plugin.namespace.reserved | yes | namespace is reserved |
plugin.namespace.collision | yes | two plugins claim one namespace |
plugin.name.collision | yes | two plugins share a name at the same scope |
plugin.path.outside_root | yes | a declared path escapes the plugin root |
plugin.skill.invalid | no | one SKILL.md failed to parse |
plugin.hooks.invalid | no | one hook entry failed validation |
plugin.knowledge.invalid | no | one knowledge folder failed validation |
plugin.agent.invalid | no | one agent document failed validation |
plugin.libraries.invalid | no | libraries.json failed to load |
plugin.library.invalid | no | one library path is invalid |
plugin.library.alias_collision | no | library alias shared across plugins |
plugin.connectors.invalid | no | connectors.json failed to load |
plugin.mcp.connection_failed | no | an MCP server did not answer |
plugin.mcp.authorization_required | no | an MCP server needs authorization |
plugin.tool_override.unused | no | a toolOverrides key matched no tool |
Fatal diagnostics drop the entire plugin. Non-fatal diagnostics drop only the offending component; the rest of the plugin survives.
Compatibility with other plugin formats
Vibe also detects and adapts plugins authored for other agents:
| Format | Marker | Adapted as |
|---|---|---|
| Claude Code | .claude-plugin/plugin.json | skills, MCP servers, hooks |
| Codex | .codex-plugin/plugin.json | skills, MCP servers |
| Kimi Code | kimi.plugin.json or .kimi-plugin/plugin.json | skills, MCP servers, hooks |
| OpenCode | .opencode/ directory | skills only (executable modules unsupported) |
If markers for more than one format are present, the plugin is rejected as
ambiguous. Native Agent Plugins 1.0 (a valid plugin.json with the correct
$schema) always takes precedence.
When creating a new plugin, always use the native Agent Plugins 1.0 format.
Workflow
- Determine the plugin name, scope (project vs user global), and which components the user needs.
- Create the directory at
.vibe/plugins/<name>/(project) or~/.vibe/plugins/<name>/(user). - Write
plugin.jsonwith the required$schemaandnamefields. - Add the
ai.mistral.vibeextension toplugin.jsonif any Vibe-specific components (hooks, knowledge, agents, libraries, connectors) are needed. - Add component directories and files per the instructions above.
- Tell the user to run
/reloadto pick up the new plugin without restarting.

