Plugins

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

Plugins package reusable Droid extensions so a team can install the same skills, commands, droids, output styles, 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.
Output stylesoutput-styles/<name>.mdSettings picker optionShared instructions for structuring interactive responses.
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 plugin layouts use a .factory-plugin/ directory. 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
AvailableInstall plugins from registered marketplaces. Plugin IDs installed in any scope do not appear here.
InstalledEnable or disable a plugin with Space where policy allows, and open its details or available actions. Org-scoped installs expose only their details.
MarketplacesAdd or update a marketplace, and toggle its auto-update. Only user-added marketplaces can be deleted here. Remove org or project entries from the settings that declare them.

Use CLI commands for scripts and onboarding:

Bash
# Marketplace management
droid plugin marketplace add <source>
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

There is no droid plugin enable or disable command. Enablement is stored in the enabledPlugins setting, and organization-managed activation cannot be changed locally.

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.

When Droid derives a marketplace name from a pinned source, it appends the pin to that name. your-org/plugins#v1.2.0 registers as plugins@v1.2.0, and a plugin in it installs as code-standards@plugins@v1.2.0. A SHA pin uses the first 8 characters. Marketplaces declared in settings keep their extraKnownMarketplaces key instead. Run droid plugin marketplace list to read the registered name back.

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
├── output-styles/
│   └── review-notes.md
├── hooks/
│   ├── hooks.json
│   └── check.sh
├── mcp.json
└── README.md
Warning

Keep commands/, skills/, droids/, output-styles/, 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"]
}
FieldPurpose
nameSource metadata for ecosystem compatibility. Installed identity comes from the marketplace entry.
descriptionSource-level summary for anyone reading the plugin.
versionRelease metadata. Git-based installation still tracks the installed commit hash.
author, homepage, repository, license, keywordsOptional source metadata for attribution and compatibility.

Droid does not require or read the fields inside plugin.json. It identifies an installed plugin from its marketplace entry name and registered marketplace name. A .factory-plugin/ directory identifies the native layout; .claude-plugin/, agents/, or .mcp.json identifies a Claude Code layout for translation. The description and category shown while browsing come from the marketplace entry.

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.

Output styles

An output style lives at output-styles/<name>.md and becomes an option under /settingsOutput style:

output-styles/review-summary.md
---
name: Review Summary
description: Format review results for the team
---
 
Group findings by severity and include file references.

The frontmatter is optional. Output style bodies also support the plugin-root variables described under Hooks.

Output styles apply only to interactive Droid CLI sessions. See Output styles for validation, trust, and fallback behavior.

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

marketplace add takes a marketplace, not a plugin, so a plugin directory on its own is rejected with "This doesn't appear to be a valid marketplace." Wrap the plugin in a local marketplace and install from that:

local-marketplace.txt
my-marketplace/
├── .factory-plugin/
│   └── marketplace.json      # lists my-plugin with "source": "./my-plugin"
└── my-plugin/
    └── .factory-plugin/
        └── plugin.json
Bash
droid plugin marketplace add ./my-marketplace
droid plugin install my-plugin@my-marketplace --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.
  • Output styles appear in /settings, and /diagnostics reports no style errors.
  • 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
nameYesManifest metadata. The registered name is derived from the source or set by the extraKnownMarketplaces key.
descriptionNoOptional manifest metadata.
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.
url{ "source": "url", "url": "https://github.com/org/plugin.git" }Plugin has its own Git repository.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.

The github source object registers a marketplace. For an external repository in plugins[].source, use url, or use git-subdir when the plugin occupies a subdirectory.

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 owner/repo shorthand, a GitHub URL, any other Git URL, or a local path. Shorthand and plain http(s)://github.com/owner/repo[.git] URLs become a github source; other non-path inputs become a url source. Append #<ref> to follow a branch or tag, or @<40-character-sha> to pin an exact commit:

Bash
droid plugin marketplace add Factory-AI/factory-plugins
droid plugin marketplace add 'your-org/plugins#v1.2.0'
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. The Marketplaces tab in /plugins and the plugin settings in the Factory App accept the same forms.

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.
url or git-subdir plugin sourceMarketplace checkout commit hash only. The external commit is not recorded.Updating the plugin clones the external source again at its configured ref or sha, or its default branch.
npm plugin sourceResolved npm package version and metadataEach plugin update resolves the version spec again.
Plugin manifest versionMetadata onlyUseful for humans and release notes, but Git-based installs are tracked by commit.

Automatic synchronization can skip an unchanged project context and a recently checked marketplace for up to six hours. An explicit droid plugin marketplace update requests an immediate update.

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.