Create a Vibe plugin package — the Agent Plugins 1.0 format with optional Vibe extensions for skills, MCP servers, hooks, knowledge, agents, libraries, and connectors. Use when the user wants to create, scaffold, or author a plugin for Mistral Vibe.
70
85%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
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).
| 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.
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)The manifest is a JSON file with $schema and name as required fields.
{
"$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:
name must match ^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$ (1-64 chars), no --
or ...$schema must be exactly
https://agent-plugins.org/schemas/1.0.0/plugin.schema.json. Any other
schema URL produces a fatal plugin.schema.version_unsupported error.extra="forbid").To use Vibe-specific components (hooks, knowledge, agents, libraries,
connectors), add an ai.mistral.vibe extension to plugin.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.
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.mdSkills 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.
Define MCP servers in mcp.json. Three transport types are supported:
{
"$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, and env values support ${PLUGIN_ROOT} and
${PLUGIN_DATA} variable expansion.PLUGIN_ROOT and PLUGIN_DATA are also injected automatically into env;
do not set them yourself (rejected with an error).env variable names PLUGIN_ROOT and PLUGIN_DATA are reserved.cwd of . means the plugin root.streamable-http servers support static headers only; use OAuth at the
Vibe config level for authenticated remote servers.sse transport is detected but not supported — it produces a diagnostic.command for stdio servers is resolved relative to the plugin root
when it is a bare filename; absolute paths are used as-is.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.
[[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:
<plugin-name>:<hook-name>.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.mdKNOWLEDGE.md frontmatter:
---
name: accounting-policy
description: How revenue is recognized and reported.
display_name: Accounting Policy
icon: book
---Rules:
name must match the directory name (^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$).description is 5-300 characters.KNOWLEDGE.md entrypoint limit: 256 KB.<namespace>:<name>.Place subagent definitions under ai.mistral.vibe/agents/. Each .toml file
defines one subagent:
ai.mistral.vibe/
agents/
researcher.tomlresearcher.toml:
schemaVersion = 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:
schemaVersion must be 1.agentType must be "subagent" (the only supported type).^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$).safety is one of "safe", "neutral", "destructive", "yolo".<namespace>:<filename-stem>.Declare Node and Python library dependencies in libraries.json:
{
"schemaVersion": 1,
"node": {
"@productivity/finance": "./node/finance",
"lodash": "./node/lodash"
},
"python": {
"vibe_finance": "./python/vibe_finance",
"utils": "./python/utils.py"
}
}Rules:
^(?:@[a-z0-9][a-z0-9._-]*/)?[a-z0-9][a-z0-9._-]*$
(max 214 chars).^[A-Za-z_][A-Za-z0-9_]*$ (max 128 chars)... or absolute paths..py file.Declare required managed connectors in connectors.json:
{
"schemaVersion": 1,
"connectors": [
{
"id": "github",
"tools": ["create_issue", "list_issues"]
},
{
"id": "linear",
"tools": ["create_issue"]
}
]
}Rules:
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.
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.
.vibe/plugins/<name>/ (project) or
~/.vibe/plugins/<name>/ (user).plugin.json with the required $schema and name fields.ai.mistral.vibe extension to plugin.json if any Vibe-specific
components (hooks, knowledge, agents, libraries, connectors) are needed./reload to pick up the new plugin without
restarting.d4b3223
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.