Skip to main content
Plugins are in beta. Behavior and configuration may change in future releases.
A plugin is a bundle of skills you can install from a GitHub repo, a git URL, or a local folder and reuse across projects. Installing a plugin makes its skills available as /<plugin>:<skill> slash commands, and it can pull in other plugins it depends on automatically. A plugin is just a source that contains:
my-plugin/
├── .devin-plugin/
│   └── plugin.json     # The plugin manifest
└── skills/
    └── review/
        └── SKILL.md    # An ordinary skill
The skills/ directory holds ordinary skills — plugins introduce no new skill format. See Creating Skills for the SKILL.md format.

Installing a plugin

A plugin source can be a GitHub owner/repo, a git URL, or a local path:
# From GitHub
devin plugins install acme/review-tools

# From any git host
devin plugins install https://gitlab.com/acme/review-tools.git

# From a local folder (great for authoring)
devin plugins install ./my-plugin
Before installing, Devin shows what the plugin adds — the skills it provides, any required plugins that will be auto-installed, and any policy it introduces (for example, if it forbids other plugins). Pass -y / --yes to skip the prompt. Plugins are installed at the user level and are available across all your projects.

Managing plugins

# List installed plugins, their versions, and whether any are blocked by policy
devin plugins list

# Show a plugin's skills and its required/optional/forbidden lists
devin plugins info review-tools

# Re-fetch a plugin (or all plugins) at the latest version
devin plugins update review-tools
devin plugins update

# Remove a plugin (auto-installed required plugins are left in place)
devin plugins remove review-tools
Local plugins are linked directly to their source folder, so edits are live: devin plugins install ./my-plugin → edit skills/<name>/SKILL.md → changes apply on the next session, no update needed.

The manifest

.devin-plugin/plugin.json describes the plugin. Only name is required, and it must be unique among installed plugins (it is the /<name>:… namespace).
{
  "name": "review-tools",
  "version": "1.0.0",
  "description": "Code-review skills for our team",
  "requiredPlugins": [
    "acme/secure-base",
    { "source": "github", "repo": "acme/audit-logging" }
  ],
  "optionalPlugins": [
    "acme/deploy-tools",
    { "source": "url", "url": "https://gitlab.com/acme/extra.git" }
  ],
  "forbiddenPlugins": ["sketchy-org/bad-plugin", "acme/*", "*"]
}
Supported metadata fields: name, version, description, author ({ name, email }), homepage, repository, license, and keywords. A dependency entry is a source — either a string shorthand or an object:
  • "owner/repo" → GitHub
  • "https://…", "git@…", "ssh://…" → git URL
  • { "source": "github", "repo": "owner/repo" }
  • { "source": "url", "url": "https://gitlab.com/team/plugin.git" }
All GitHub forms for the same repo (owner/repo, the HTTPS URL, the .git URL, the SSH form) refer to the same plugin identity.

Dependencies and governance

A plugin can declare three lists, which let a single plugin act as a curated, governed collection of other plugins.

requiredPlugins

Auto-installed (recursively) when the plugin is installed. If a required plugin is blocked by policy, the whole install fails — there is no partial install.

optionalPlugins

An allow-list of plugins this plugin endorses. They are not auto-installed; the list only matters as a carve-out against a forbidden entry (see below).

forbiddenPlugins

A deny-list. Each entry is one of:
  • An exact plugin identity, written as owner/repo, a git URL, or a local path.
  • A glob pattern — any entry containing *. The * matches any sequence of characters, including /. Patterns are normalized into canonical-identity space first, so acme/* becomes https://github.com/acme/* (all of acme’s GitHub repos), */secrets matches a repo named secrets under any owner, and https://gitlab.com/acme/* matches any repo under that path.
  • The lone "*", which matches every other plugin (an un-defeatable lockdown).
The policy rules are:
  • Deny wins. A plugin is blocked if any installed plugin forbids it (via its exact identity, a matching glob, or "*").
  • Self-override. A plugin’s own requiredPlugins, optionalPlugins, and itself are exempt from its own forbidden list. So forbiddenPlugins: ["*"] together with optionalPlugins: [B, C] means “allow myself, B, and C; forbid everything else.”
  • No cross-plugin re-permitting. One plugin’s allow-lists cannot re-permit what another plugin forbids. An installed plugin with forbiddenPlugins: ["*"] is an un-defeatable lockdown.
  • Default open. If no installed plugin forbids anything, nothing is blocked.
Policy is enforced at two points:
  • Install time — installing a blocked plugin (or one whose required plugins can’t be satisfied, or whose name collides with an installed plugin) is refused.
  • Load time — if a plugin becomes blocked after install (for example, a forbidding plugin is installed later), it stays on disk but its skills are skipped at session start, with a warning naming the plugin that forbids it.