Plugins

Use and build shareable Droid packages for skills, commands, droids, hooks, and MCP servers.

Plugins package reusable Droid extensions so a team can install the same skills, commands, droids, hooks, and MCP servers across projects. Use standalone .factory/ configuration for personal or project-local experiments, then turn the pieces into a plugin when they should be shared, versioned, or governed.

For org-approved catalogs and managed marketplace sources, see Internal Plugin Marketplaces.

What plugins contain

ComponentLocation in a pluginLoaded asUse for
Skillsskills/<name>/SKILL.mdModel-invoked skillReusable procedures and domain knowledge.
Slash commandscommands/<name>.md or executable command files/name commandUser-invoked workflows.
Droidsdroids/<name>.mdTask-callable subagentSpecialized agents with scoped prompts, tools, and models.
Hookshooks/hooks.json plus scriptsLifecycle hooksValidation, policy, formatting, logging, and context injection.
MCP serversmcp.jsonMCP tool configurationExternal tools and data sources made available when the plugin is active.

Native Droid plugins use .factory-plugin/plugin.json. Claude Code plugin layouts are also supported: .claude-plugin/ is translated to .factory-plugin/, agents/ is translated to droids/, and .mcp.json is translated to mcp.json when Droid copies the plugin into its cache.

Manage plugins

Use the interactive UI for browsing and one-off work:

/plugins
TabPurpose
BrowseView and install plugins from registered marketplaces.
InstalledUpdate, uninstall, or inspect installed plugins.
MarketplacesAdd, update, or remove marketplaces.

Use CLI commands for scripts and onboarding:

Bash
# Marketplace management
droid plugin marketplace add <url-or-local-path>
droid plugin marketplace list
droid plugin marketplace update [name]
droid plugin marketplace remove <name>
 
# Plugin management
droid plugin install <plugin@marketplace> --scope user
droid plugin install <plugin@marketplace> --scope project
droid plugin list --scope user
droid plugin update [plugin@marketplace] --scope project
droid plugin uninstall <plugin@marketplace> --scope project

Plugin IDs use pluginName@marketplaceName. Scoped npm package names are supported because Droid splits on the first @ after the first character, so @scope/plugin@marketplace is valid.

Build a plugin

A minimal native plugin looks like this:

my-plugin/
├── .factory-plugin/
│   └── plugin.json
├── commands/
│   └── hello.md
├── skills/
│   └── code-review/
│       └── SKILL.md
├── droids/
│   └── reviewer.md
├── hooks/
│   ├── hooks.json
│   └── check.sh
├── mcp.json
└── README.md
Warning

Keep commands/, skills/, droids/, hooks/, and mcp.json at the plugin root. Do not put them inside .factory-plugin/; that directory is for plugin metadata.

Plugin manifest

Create .factory-plugin/plugin.json:

JSON
{
  "name": "my-plugin",
  "description": "A helpful plugin description",
  "version": "1.0.0",
  "author": {
    "name": "Your Team"
  },
  "homepage": "https://github.com/your-org/my-plugin",
  "repository": "https://github.com/your-org/my-plugin",
  "license": "MIT",
  "keywords": ["review", "security"]
}
FieldSource-validated behavior
namePlugin identity. Include it for native Droid and Claude Code compatibility.
descriptionShown in browsing and installation surfaces when available.
versionDocumentation metadata for the plugin. Git-based installation still tracks the installed commit hash.
author, homepage, repository, license, keywordsOptional metadata for attribution and discovery.

Commands

A Markdown command at commands/review-pr.md becomes /review-pr:

Markdown
---
description: Review the current PR for issues
---
 
Review the current pull request. Focus on: $ARGUMENTS

Skills

A skill lives at skills/<name>/SKILL.md:

Markdown
---
name: code-review
description: Reviews code for correctness, safety, and maintainability. Use when reviewing code, checking PRs, or analyzing code quality.
---
 
Check for logic errors, security issues, missing tests, and unclear ownership. Return specific, actionable findings.

Droids

A droid lives at droids/<name>.md:

Markdown
---
name: reviewer
description: Specialized code reviewer subagent
model: inherit
tools: ["Read", "Grep", "Glob"]
---
 
You are a senior code reviewer. Report correctness, security, and test coverage issues with severity and evidence.

See Custom Droids for the full droid configuration surface.

Hooks

Plugin hooks live at hooks/hooks.json and may reference scripts in the plugin:

JSON
{
  "PostToolUse": [
    {
      "matcher": "Create|Edit|ApplyPatch",
      "hooks": [
        {
          "type": "command",
          "command": "${DROID_PLUGIN_ROOT}/hooks/check.sh",
          "timeout": 30
        }
      ]
    }
  ]
}

Droid expands ${DROID_PLUGIN_ROOT}, $DROID_PLUGIN_ROOT, ${CLAUDE_PLUGIN_ROOT}, and $CLAUDE_PLUGIN_ROOT to the installed plugin cache path when the plugin loads. See Hooks for hook events, input, and output behavior.

MCP servers

Plugin MCP servers use mcp.json at the plugin root:

JSON
{
  "mcpServers": {
    "my-api": {
      "command": "npx",
      "args": ["-y", "@example/mcp-server"],
      "env": {
        "API_KEY": "${MY_API_KEY}"
      }
    }
  }
}

Test locally

During development, add the plugin directory as a local marketplace and install from it:

Bash
mkdir -p my-plugin/.factory-plugin
# create my-plugin/.factory-plugin/plugin.json and any plugin components
 
droid plugin marketplace add ./my-plugin
droid plugin install my-plugin@my-plugin --scope user

Before sharing, verify:

  • The plugin installs from a clean checkout.
  • Commands work with and without $ARGUMENTS.
  • Skills and droids have clear names and routing descriptions.
  • Hook scripts use absolute paths or plugin-root variables.
  • MCP servers do not embed secrets directly in mcp.json.
  • The README explains what the plugin does, when to use it, and prerequisites.

Marketplaces

A marketplace is a catalog of installable plugins. Droid reads .factory-plugin/marketplace.json first and falls back to .claude-plugin/marketplace.json for Claude Code compatibility.

your-marketplace/
├── .factory-plugin/
│   └── marketplace.json
├── plugin-one/
│   └── .factory-plugin/
│       └── plugin.json
└── plugin-two/
    └── .factory-plugin/
        └── plugin.json
JSON
{
  "name": "your-marketplace",
  "description": "A collection of team plugins",
  "owner": {
    "name": "Platform Team"
  },
  "plugins": [
    {
      "name": "plugin-one",
      "description": "Description of plugin one",
      "source": "./plugin-one"
    }
  ]
}
Marketplace fieldRequiredDescription
nameYesMarketplace identifier.
descriptionNoShown when browsing marketplaces.
ownerNoContact metadata.
plugins[].nameYesPlugin identifier inside this marketplace.
plugins[].sourceYesRelative path string or source object.
plugins[].description, category, homepage, tagsNoBrowsing metadata.

Plugin sources

Each marketplace plugin entry has a source field.

Source typeShapeUse whenPinning
Relative path"./plugin-one"Plugin lives inside the marketplace repository. Absolute paths and paths that escape the marketplace directory are rejected.Pin the marketplace source.
github{ "source": "github", "repo": "org/repo", "ref": "v1.0.0" }Plugin or marketplace is in a GitHub repository.ref branch/tag or full 40-character sha.
url{ "source": "url", "url": "https://gitlab.com/org/repo.git" }Plugin or marketplace is on another Git host.ref branch/tag or full 40-character sha.
git-subdir{ "source": "git-subdir", "url": "https://github.com/org/repo", "path": "plugins/foo" }Plugin lives in a subdirectory of a larger repository.ref branch/tag or full 40-character sha.
npm{ "source": "npm", "package": "@org/plugin", "version": "^2.0.0" }Plugin is published to npm or a private npm-compatible registry.version semver, range, or dist-tag.

npm is valid only inside a marketplace's plugins[].source. droid plugin marketplace add npm:<package> is intentionally rejected. To distribute one npm plugin, create a small wrapper marketplace that lists the npm source.

Add and pin marketplaces

droid plugin marketplace add accepts a GitHub URL, any other Git URL, or a local path. For Git URLs, append #<ref> to follow a branch or tag, or @<40-character-sha> to pin an exact commit:

Bash
droid plugin marketplace add https://github.com/Factory-AI/factory-plugins
droid plugin marketplace add 'https://github.com/your-org/plugins#v1.2.0'
droid plugin marketplace add https://github.com/your-org/plugins@1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b
droid plugin marketplace add ./your-local-marketplace

Local marketplace paths are resolved to absolute paths and cannot carry a ref or SHA pin.

npm source details

FieldRequiredDescription
packageYesnpm package name. Scoped packages such as @scope/name are supported.
versionNoVersion, range, or dist-tag. Defaults to latest. URL, path, file:, git+..., and npm: alias specs are rejected.
registryNoHTTPS registry URL with no embedded credentials, query string, or fragment.
authTokenEnvVarNoEnvironment variable name containing the private registry token. Requires registry to have an effect.

Droid installs npm-source plugins in a per-plugin scratch directory with npm install --ignore-scripts --no-save --no-audit --no-fund, then copies the resolved package root into the plugin cache. Lifecycle scripts do not run, global npm configuration is not mutated, and the package must ship ready-to-use files.

Team and enterprise distribution

Register marketplaces and enable plugins through settings when you want teams to get them automatically:

JSON
{
  "extraKnownMarketplaces": {
    "your-org-internal-plugins": {
      "source": {
        "source": "github",
        "repo": "your-org/internal-plugins",
        "ref": "v1.2.0"
      }
    }
  },
  "enabledPlugins": {
    "code-standards@your-org-internal-plugins": true
  }
}

The installation scope follows where the setting is defined: org-managed settings install as org scope, user settings install as user scope, and project settings install as project scope.

Use strictKnownMarketplaces in managed settings when an organization wants to restrict marketplace sources to an approved list. See Internal Plugin Marketplaces for centralized governance.

Versioning and updates

SourceTracked versionUpdate behavior
Relative path inside a Git marketplaceMarketplace commit hashUpdate the marketplace to move the plugin.
github, url, git-subdir plugin sourcePlugin source commit hashUpdate fetches the latest allowed commit unless pinned by sha.
npm plugin sourceResolved npm package version and metadataUpdate follows the version spec, such as latest or ^2.0.0.
Plugin manifest versionMetadata onlyUseful for humans and release notes, but Git-based installs are tracked by commit.

Discover plugins

Factory maintains an official marketplace at Factory-AI/factory-plugins:

Bash
droid plugin marketplace add https://github.com/Factory-AI/factory-plugins

Common official plugins include:

PluginPurpose
droid-controlTerminal, browser, and computer automation for demos, QA, and verification.
droid-evolvedSkills for session navigation, writing, skill creation, design, frontend work, and browser automation.
security-engineerSecurity review, threat modeling, commit scanning, and vulnerability validation.

Droid can also install compatible Claude Code plugins. Claude Code layouts are translated during cache copy, not by mutating the source repository.

Best practices

PracticeWhy it matters
Keep plugins focusedSmall plugins are easier to review, compose, and retire.
Document capabilities and boundariesUsers need to know when to use the plugin, prerequisites, and what data or tools it touches.
Avoid hardcoded machine pathsUse plugin-root variables for plugin files and environment variables for secrets.
Test on a clean machinePlugin installs should not depend on uncommitted local files or global state.
Ship prebuilt npm packages--ignore-scripts means npm plugin sources cannot rely on postinstall builds.
Govern high-trust pluginsUse managed settings and Internal Plugin Marketplaces for approved enterprise distribution.