# Internal Plugin Marketplaces

Centralize approved Droid plugins across your organization with internal marketplaces and managed settings.

Internal Plugin Marketplaces are private plugin catalogs where organizations maintain approved Droid plugins for company-wide distribution. Instead of individual teams discovering and vetting plugins independently, an internal marketplace provides a curated catalog of capabilities that are pre-approved, maintained, and ready to use.

For day-to-day plugin usage and authoring, see [Plugins](/harness/plugins). Use this page when you need enterprise distribution, managed marketplace sources, and org-level rollout controls.

## Why use Internal Plugin Marketplaces?

| Challenge | Solution |
|-----------|----------|
| **Inconsistent tooling** across teams | Single source of approved plugins ensures everyone uses the same capabilities |
| **Security and compliance review** for each plugin | Vet plugins once at the org level, distribute everywhere |
| **Onboarding new developers** | New team members instantly access all approved capabilities |
| **Role-specific tooling** | Package plugins by team function (security, frontend, data, etc.) |
| **Version control** | Manage plugin versions centrally, roll out updates organization-wide |

<LabeledDivider label='Setup and rollout' />

## Set up an internal plugin marketplace

An internal plugin marketplace is a Git repository containing your organization's approved plugins with a marketplace manifest.

### Repository structure

```text
your-org/droid-plugins/
├── .factory-plugin/
│   └── marketplace.json      # Marketplace manifest
├── plugins/
│   ├── security-toolkit/     # Security team plugins
│   │   ├── .factory-plugin/
│   │   │   └── plugin.json
│   │   └── skills/
│   ├── frontend-standards/   # Frontend team plugins
│   │   ├── .factory-plugin/
│   │   │   └── plugin.json
│   │   └── skills/
│   ├── data-engineering/     # Data team plugins
│   │   └── ...
│   └── platform-tools/       # Platform/DevOps plugins
│       └── ...
└── README.md
```

### Marketplace manifest

Create `.factory-plugin/marketplace.json` to register your plugins:

```json
{
  "name": "acme-corp-plugins",
  "description": "ACME Corp approved Droid plugins",
  "owner": {
    "name": "ACME Platform Team",
    "email": "platform@acme.com"
  },
  "plugins": [
    {
      "name": "security-toolkit",
      "description": "Security review, threat modeling, and vulnerability scanning",
      "source": "./plugins/security-toolkit",
      "category": "security"
    },
    {
      "name": "frontend-standards",
      "description": "React component patterns, accessibility checks, design system integration",
      "source": "./plugins/frontend-standards",
      "category": "frontend"
    },
    {
      "name": "data-engineering",
      "description": "SQL review, pipeline validation, data quality checks",
      "source": "./plugins/data-engineering",
      "category": "data"
    },
    {
      "name": "platform-tools",
      "description": "CI/CD helpers, infrastructure review, deployment automation",
      "source": "./plugins/platform-tools",
      "category": "platform"
    }
  ]
}
```

## Org-level configuration

Configure the marketplace at the organization level so it's automatically available to all users. Add to your org-managed settings:

```json
{
  "extraKnownMarketplaces": {
    "acme-corp-plugins": {
      "source": {
        "source": "github",
        "repo": "your-org/droid-plugins"
      }
    }
  },
  "enabledPlugins": {
    "security-toolkit@acme-corp-plugins": true,
    "platform-tools@acme-corp-plugins": true
  }
}
```

| Field | Purpose |
|-------|---------|
| `extraKnownMarketplaces` | Registers the marketplace so users can browse and install plugins |
| `enabledPlugins` | Enables plugins and installs them at org scope when missing (optional) |

With this configuration:

- The marketplace appears automatically when users run `/plugins`
- Droid installs the enabled plugins automatically during startup
- Users can install additional plugins unless `strictEnabledPlugins` restricts the list

### Restricting marketplaces

To prevent users from adding unapproved marketplaces, use `strictKnownMarketplaces`:

```json
{
  "strictKnownMarketplaces": [
    { "source": "github", "repo": "Factory-AI/factory-plugins" }
  ]
}
```

When `strictKnownMarketplaces` is set:

- Users can only add marketplaces from the approved list
- Plugin installations from non-approved marketplaces are blocked

Marketplaces the organization declares in `extraKnownMarketplaces` count as approved without being repeated in the list, so `strictKnownMarketplaces` only has to name sources outside your own org settings. A local path in the list has to be absolute or start with `~`, since a relative one points at a different directory for every user, and saving one is rejected.

Existing-plugin provenance enforcement is rolling out separately. When it is active for your organization:

- Installed plugins whose marketplace is not approved stop loading
- Installed plugins whose recorded source differs from the approved source stop loading, even when the marketplace name matches

A blocked plugin stays in the installed list and shows the reason in `/plugins`. Approve its marketplace, or have the user reinstall the plugin from a marketplace already on the list. When the name is approved but the source no longer matches, re-add the marketplace to repair the registration, then reinstall the plugin to record the new source.

<Warning>
Before existing-plugin enforcement becomes active, audit installed plugins and approve the marketplaces your teams depend on. Once active, Droid checks installed plugins at the next session rather than waiting for an update.
</Warning>

If an org list saved by an older CLI contains only relative local paths, Droid denies new installs but keeps existing plugins active. Replace those entries with absolute paths or paths that start with `~`.

### Restricting enabled plugins

By default, `enabledPlugins` entries from org, project, and user settings combine. Set `strictEnabledPlugins` to make the entries at the policy level and higher the complete list:

```json
{
  "strictEnabledPlugins": true,
  "enabledPlugins": {
    "security-toolkit@acme-corp-plugins": true,
    "platform-tools@acme-corp-plugins": true
  }
}
```

At org level, project and user settings cannot enable or install other plugins. Their existing entries stay stored but inactive, and can reactivate if the strict policy is removed. Factory's default plugins are also disabled unless they appear in the org list.

<Warning>
Older CLI versions do not recognize or enforce `strictEnabledPlugins`. Require a supported version before relying on this policy.
</Warning>

See [Hierarchical settings and org control](/enterprise/hierarchical-settings-and-org-control#plugins-and-marketplaces) for precedence and the full settings reference.

## User experience

Users manage plugins via the `/plugins` UI:

1. Run `/plugins` to open the plugin manager
2. The Available tab shows plugins from all registered marketplaces including the org marketplace, minus the ones already installed
3. Org-enabled plugins are installed automatically during startup

For CLI access:

```bash
droid plugin install frontend-standards@acme-corp-plugins
droid plugin update frontend-standards@acme-corp-plugins
```

Organization marketplaces are labeled in Marketplaces, and managed installs are labeled in Installed. Available identifies each plugin's source marketplace.

<LabeledDivider label='Catalog management' />

## Organizing plugins

Structure your marketplace around the boundaries your platform team already owns. Common patterns include:

{/* sweep-allow: term-bullets */}

- **Team function**: security, frontend, backend, data, platform, compliance.
- **Capability**: code review, testing, documentation, migrations, security.
- **Project type**: microservices, monoliths, data pipelines, ML projects.

Choose one primary taxonomy so `/plugins` stays predictable for new users.

## Pre-installing plugins

For critical capabilities that everyone needs, set `enabledPlugins` in org-managed settings, alongside `extraKnownMarketplaces` as shown in [Org-level configuration](#org-level-configuration). These plugins:

- Are installed automatically with `org` scope during startup
- Can finish installing after the session becomes usable when a source is slow
- Follow the org settings for their version, so `/plugins` offers an org-scoped plugin no update or uninstall action, only its details

Move a relative-path org plugin by changing the marketplace pin in org-managed settings. For external Git or npm plugins, update the source entry in the marketplace manifest, then advance the marketplace pin so clients receive that change.

## Version management

Relative-path plugins in a Git marketplace use the marketplace checkout commit as their installed version. External Git and npm sources are fetched separately when their plugin is installed or refreshed.

Pin a marketplace source with `ref` (branch or tag) or `sha` (full commit SHA) to control its manifest and relative-path plugins:

```json
{
  "extraKnownMarketplaces": {
    "acme-corp-plugins": {
      "source": {
        "source": "github",
        "repo": "your-org/droid-plugins",
        "ref": "v2.4.0"
      }
    },
    "acme-corp-plugins-frozen": {
      "source": {
        "source": "github",
        "repo": "your-org/droid-plugins",
        "sha": "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b"
      }
    }
  }
}
```

Common patterns:

- Omit `ref` and `sha`  -  follow the repository's default branch
- `ref: "main"`  -  explicitly follow the `main` branch
- `ref: "staging"`  -  early-adopter channel
- `ref: "v1.2.0"`  -  pin to a release tag
- `sha: "<40-char SHA>"`  -  hard pin to a specific commit; marketplace update validates the checkout but does not fetch or move it

See [Plugins · Add and pin marketplaces](/harness/plugins#add-and-pin-marketplaces) for the full source schema.

<Note>
The `version` field in a plugin's own `plugin.json` does not pin anything. Relative-path plugins follow their marketplace pin. External `url` and `git-subdir` entries use `ref` or `sha` on their own source object, while npm entries use `plugins[].source.version`.
</Note>

<LabeledDivider label='Sources and access' />

## Private repository access

For private Git repositories, ensure Droid can authenticate:

### GitHub Enterprise

```bash
# Users authenticate via gh CLI
gh auth login --hostname github.your-company.com
```

### GitLab self-hosted

```bash
# Configure git credentials
git config --global credential.helper store
```

### SSH-based access

Ensure SSH keys are configured for the repository host.

## Local marketplaces

For air-gapped environments or when Git access is restricted, you can use local directory marketplaces. This is useful for:

- Environments without internet access
- Testing plugins before publishing
- Internal distribution via shared network drives

### Setting up a local marketplace

Create a directory with the standard marketplace structure:

```text
/shared/company-plugins/
├── .factory-plugin/
│   └── marketplace.json
└── plugins/
    ├── security-toolkit/
    │   └── .factory-plugin/
    │       └── plugin.json
    └── code-standards/
        └── .factory-plugin/
            └── plugin.json
```

### Adding a local marketplace

Via UI: `/plugins` → Marketplaces tab → "Add new marketplace" → enter absolute path

Via CLI:

```bash
droid plugin marketplace add /shared/company-plugins
```

### Configuration for auto-registration

Use the `local` source type in settings:

```json
{
  "extraKnownMarketplaces": {
    "company-local-plugins": {
      "source": {
        "source": "local",
        "path": "/shared/company-plugins"
      }
    }
  }
}
```

<Note>
When removing a local marketplace from the marketplace list, Droid does **not** delete the source directory. Only Git-cloned marketplaces have their directories removed on deletion.
</Note>

## Marketplaces in a subdirectory (`git-subdir`)

When your marketplace lives in a subdirectory of a larger repository (rather than at the repo root), use the `git-subdir` source type. It works with any Git host via a repository URL and the path to the marketplace root within it:

```json
{
  "extraKnownMarketplaces": {
    "acme-corp-plugins": {
      "source": {
        "source": "git-subdir",
        "url": "https://gitlab.com/acme/monorepo.git",
        "path": "tools/droid-plugins",
        "ref": "main"
      }
    }
  }
}
```

`url` and `path` are required. The selected directory must contain `.factory-plugin/marketplace.json` or `.claude-plugin/marketplace.json`. `ref` (branch or tag) and `sha` (full 40-character commit SHA) are optional and pin the marketplace the same way they do for other Git sources.

## npm-sourced plugins

Individual plugins in a marketplace manifest can be sourced from an **npm registry** instead of a Git path. Use the `npm` source type in a plugin's `source` field (it is a per-plugin source only, not a marketplace source):

```json
{
  "name": "acme-corp-plugins",
  "plugins": [
    {
      "name": "security-toolkit",
      "description": "Security review and vulnerability scanning",
      "source": {
        "source": "npm",
        "package": "@acme/droid-security-toolkit",
        "version": "^2.0.0",
        "registry": "https://npm.internal.acme.com",
        "authTokenEnvVar": "ACME_NPM_TOKEN"
      }
    }
  ]
}
```

| Field | Purpose |
|-------|---------|
| `package` | npm package name (scoped or unscoped). Required. |
| `version` | Exact version, range (`^2.0.0`), or dist-tag (`latest`). Optional. |
| `registry` | Custom https registry URL for private packages. Optional. |
| `authTokenEnvVar` | Name of the environment variable holding the registry auth token. Optional. |

npm-sourced installs record the resolved package version, URL, and integrity when available. A plugin refresh resolves its exact version, range, or dist-tag again. Automatic refresh follows the containing marketplace's update schedule rather than continuously polling the registry.

<LabeledDivider label='In practice' />

## Best practices

| Practice | Checklist |
| --- | --- |
| Establish a review process | Require security review for external dependencies, platform-team code review, isolated-environment testing, and documentation before adding plugins to the marketplace. |
| Document each plugin | Include what the plugin provides, when to use it, when not to use it, prerequisites, dependencies, and example usage. |
| Version semantically | Use **major** versions for breaking command or behavior changes, **minor** versions for backward-compatible capabilities, and **patch** versions for bug fixes. |
| Monitor adoption | Track installation counts, active usage metrics, team feedback, issues, and feature requests. |
| Plan for deprecation | Announce the timeline, provide a migration path, and keep deprecated plugins available read-only during the transition. |

## Example: financial services org

A financial services company sets up its marketplace:

**Mandatory plugins** (pre-installed for everyone):

- `compliance-checks` - PCI-DSS and SOX compliance validation
- `security-scanner` - OWASP vulnerability detection
- `audit-logging` - Enhanced audit trail for all Droid actions

**Team-specific plugins** (available for install):

- `trading-systems` - For quantitative and trading teams
- `risk-models` - For risk management teams
- `regulatory-reporting` - For compliance teams

**Configuration (org-managed-settings.json):**

```json
{
  "extraKnownMarketplaces": {
    "acme-financial-plugins": {
      "source": {
        "source": "github",
        "repo": "acme-financial/droid-plugins"
      }
    }
  },
  "enabledPlugins": {
    "compliance-checks@acme-financial-plugins": true,
    "security-scanner@acme-financial-plugins": true,
    "audit-logging@acme-financial-plugins": true
  }
}
```

This configures the compliance and security plugins for automatic org-scope installation, while specialized teams can add domain-specific capabilities.

<RelatedLinks>
  <RelatedLink href='/harness/plugins' title='Plugins'>
    Plugin basics, installation, and authoring.
  </RelatedLink>
  <RelatedLink href='/harness/subagents' title='Custom Droids'>
    Scoped subagents that plugins can bundle and distribute.
  </RelatedLink>
</RelatedLinks>
