---
title: Extending AgentsMesh
description: Add new AI tool targets via the scaffolder or the plugin system.
---

import { Aside } from '@astrojs/starlight/components';

AgentsMesh ships support for the most popular AI coding tools, but the ecosystem keeps growing. Two paths let you extend coverage without waiting for a core release:

- **Target scaffold** — generate a new built-in target skeleton and contribute it upstream.
- **Plugin system** — ship a standalone npm package that adds a target at runtime, no fork required.

<Aside type="tip">
  For a full plugin development walkthrough — global mode, conversions, lint hooks, scoped settings, and more — see the **[Building Plugins](../building-plugins/)** guide.
</Aside>

---

## Target Scaffold

The scaffolder emits the 10 files needed to integrate a new target into the AgentsMesh source tree.

```bash
agentsmesh target scaffold foo-ide
agentsmesh target scaffold foo-ide --name "Foo IDE"
agentsmesh target scaffold foo-ide --name "Foo IDE" --force   # overwrite existing files
```

### What gets generated

For `agentsmesh target scaffold foo-ide`:

| File | Purpose |
|------|---------|
| `src/targets/foo-ide/constants.ts` | Path and ID constants (project + global) |
| `src/targets/foo-ide/index.ts` | Full `TargetDescriptor` with project + global layouts, capabilities, conversion support, lint hooks |
| `src/targets/foo-ide/generator.ts` | `generateRules()` stub |
| `src/targets/foo-ide/importer.ts` | `importFrom()` stub |
| `src/targets/foo-ide/linter.ts` | `lintRules()` using shared validator |
| `src/targets/foo-ide/lint.ts` | Per-feature lint hooks stub |
| `src/core/reference/import-maps/foo-ide.ts` | Import path mapper |
| `tests/unit/targets/foo-ide/generator.test.ts` | Generator unit tests |
| `tests/unit/targets/foo-ide/importer.test.ts` | Importer unit tests |
| `tests/e2e/fixtures/foo-ide-project/AGENTS.md` | E2E fixture |

The generated descriptor includes:
- **Global layout** with `rewriteGeneratedPath` for `--global` support
- **`globalSupport`** with global capabilities, detection paths, and layout
- **`supportsConversion`** for commands and agents
- **Per-feature lint hooks** stub (`lint.ts`)

### Post-scaffold steps

The catalog is auto-discovered at build time, so adding a new target does **not** require manual edits to `target-ids.ts`, `builtin-targets.ts`, or the import-maps barrel. The CLI prints the exact next steps:

1. Run `pnpm catalog:generate` — auto-discovers the new target and updates the IDs list, descriptor imports, and import-map barrel between sentinel comments. Also runs as part of `pnpm build` via the `prebuild` hook.
2. Fill in the `TODO(agentsmesh-scaffold)` markers in `src/targets/foo-ide/`.
3. Run `pnpm typecheck && pnpm test -- tests/unit/targets/foo-ide`.
4. Run `pnpm schemas:generate && pnpm matrix:generate`.

<Aside type="note">
  How auto-discovery works: `scripts/generate-target-catalog.ts` scans `src/targets/<dir>/index.ts`, validates that each exports `descriptor`, and patches the AUTO-GENERATED regions of `builtin-targets.ts` and `import-maps/index.ts`. To remove a target, delete its directory and rerun the script. Drift can be checked in CI with `pnpm catalog:generate -- --verify`.
</Aside>

---

## Plugin System

Plugins are npm packages (or local paths) that export one or more `TargetDescriptor` objects. AgentsMesh loads them at runtime — no fork, no core PR required. Plugins have full parity with built-in targets: global mode, feature conversions, scoped settings, hook post-processing, and per-feature lint hooks all work the same way.

### Publishing a plugin

A plugin package must export a `descriptor` (or `descriptors` array, or `default`) that satisfies the `TargetDescriptor` interface:

```js
// agentsmesh-target-foo-ide/index.js
export const descriptor = {
  id: 'foo-ide',
  // Required user-facing metadata. Validation rejects descriptors without it.
  metadata: {
    displayName: 'Foo IDE',
    category: 'ide',
    officialUrl: 'https://example.test/foo-ide',
    shortDescription: 'Foo IDE — a fictional editor with native rule support.',
  },
  generators: {
    name: 'foo-ide',
    generateRules(canonical) {
      return canonical.rules.map((rule) => ({
        path: `.foo-ide/${rule.slug}.md`,
        content: rule.body,
      }));
    },
    async importFrom(_projectRoot, _options) {
      return [];
    },
  },
  capabilities: {
    rules: 'native',
    additionalRules: 'none',
    commands: 'none',
    agents: 'none',
    skills: 'none',
    mcp: 'none',
    hooks: 'none',
    ignore: 'none',
    permissions: 'none',
  },
  emptyImportMessage: 'No Foo IDE config found.',
  lintRules: null,
  project: {
    paths: {
      rulePath: (slug) => `.foo-ide/${slug}.md`,
      commandPath: () => null,
      agentPath: () => null,
    },
  },
  buildImportPaths: async () => {},
  detectionPaths: ['.foo-ide'],
};
```

In `package.json`, declare `agentsmesh` as a peer dependency:

```json
{
  "name": "agentsmesh-target-foo-ide",
  "type": "module",
  "peerDependencies": {
    "agentsmesh": ">=0.6"
  }
}
```

### Consuming a plugin

```bash
# Add plugin from npm
agentsmesh plugin add agentsmesh-target-foo-ide

# Add from a local path (useful during development)
agentsmesh plugin add ./path/to/agentsmesh-target-foo-ide

# List all configured plugins and their load status
agentsmesh plugin list

# Show descriptor details
agentsmesh plugin info foo-ide

# Remove a plugin
agentsmesh plugin remove foo-ide
```

After adding, `agentsmesh generate` runs the plugin's generators alongside built-in targets. Plugin targets also appear in `agentsmesh lint` and `agentsmesh matrix` output.

### How it works

`agentsmesh plugin add` registers the plugin in `agentsmesh.yaml`:

```yaml
plugins:
  - id: foo-ide
    source: agentsmesh-target-foo-ide

pluginTargets:
  - foo-ide
```

At generate time, AgentsMesh dynamically imports each plugin, validates the exported descriptor with a Zod schema, and registers it in the target registry. Invalid descriptors are warned and skipped — one bad plugin does not block other targets. Validation also checks that:

- A `metadata` block is present with `displayName`, `category` (`'cli' | 'ide' | 'agent-platform'`), `officialUrl`, and `shortDescription`.
- Every non-`none` capability has a matching generator, or `emitScopedSettings` for settings-backed features (`mcp`, `hooks`, `ignore`, `permissions`).

Set `AGENTSMESH_STRICT_PLUGINS=1` (or `strict: true` on the plugin entry) to fail the build on plugin load errors instead of warn-and-skip.

---

## Known Limitations

- **Plugin registry/discovery** — no centralized index of community-published plugins yet.
- **SEA (single-binary) + plugins** — dynamic `import()` of npm packages needs special handling in the single-executable build.

<Aside type="note">
  Previous limitations around `import --from`, hardcoded target lists, conversion config, and plugin parity with built-in targets have been resolved. See the [Building Plugins](../building-plugins/) guide for the full plugin feature set.
</Aside>
