Installing a plugin

Drop a plugin's native artifacts straight into your agents' config dirs.

build compiles a plugin to a tree of native artifacts. install goes one step further and writes those artifacts into the real directories your harnesses read — so you (or anyone you share the plugin with) can open the agent and use the skills, commands, and tools immediately.

npx ap-sdk install

Looking for plugins? Browse the plugin directory.

Install reuses the exact same output as build, so installed files are byte-for-byte identical — it just relocates each feature into the harness's live config dir instead of an output folder.

Scope: project vs global

By default, install is project-scoped — it writes into the harness dirs in your current working directory (.claude/, .gemini/, .cursor/, …), so the plugin only applies to that repo. Pass --global (-g) to install into the home-directory dirs instead, making it available everywhere.

ScopeFlagWrites to
Project(default)./.claude/, ./.gemini/, …
Global--global, -g~/.claude/, ~/.codex/, …

Target specific harnesses

Without --target, install writes to every supported harness. Narrow it with -t (comma-separated):

npx ap-sdk install -t claude,cursor

Preview first

--dry-run plans the install and prints exactly what would be written — per harness, per feature — without touching the filesystem:

npx ap-sdk install --dry-run

What gets written

Install projects every feature in the plugin into each harness's native layout:

  • Skills → the harness's skills dir (skills/<name>/SKILL.md, …)
  • Commands → commands / prompts / workflows, in the right format per harness
  • Subagents → the harness's agents dir, when supported
  • MCP servers → merged into the harness's MCP config
  • Hooks → merged into the harness's hook config
  • Instructions → merged into the harness's context file (CLAUDE.md, …)
  • Companion files (plugin.files) → relocated under the harness's config root (e.g. .claude/), preserving each file's subpath and executable bit

Merges are idempotent and non-destructive. MCP servers, hooks, and instructions are merged into existing JSON/markdown under a delimited block keyed by the plugin id — re-running updates that block in place and leaves the rest of the file untouched. Install refuses to overwrite a config file it can't parse rather than clobber it.

Features a harness doesn't support are skipped with a one-line note (for example, a harness without subagents), never written as the wrong file.

Installing a plugin you didn't write

A plugin is just a module that default-exports definePlugin(...). To install one from a file — including a plugin shipped inside a dependency — point the CLI at it:

npx ap-sdk install ./path/to/plugin.ts -t claude
npx ap-sdk install ./node_modules/some-plugin/plugin.js -g

TypeScript plugin files load directly via the bundled tsx loader; plain .js/.mjs files need no loader.

Install straight from GitHub

Pass a GitHub source instead of a path and the CLI downloads the repo, checks it's a compatible ap-sdk plugin, and installs it — no clone or manual download. Accepts owner/repo, github:owner/repo, or a full github.com URL, with an optional #ref (branch, tag, or commit):

npx ap-sdk install owner/repo
npx ap-sdk install owner/repo#v1.2.0 -t claude
npx ap-sdk install github:owner/repo --path examples/git-helper

Before anything is written, the source is fetched to a temp checkout and run through the same validation as a local plugin. If it doesn't default-export a valid definePlugin(...) result, the install is aborted with the reason — nothing touches your harness dirs.

To check compatibility without installing, use check on the same source:

npx ap-sdk check owner/repo

Use --path <dir> when the plugin lives in a subdirectory, and set GITHUB_TOKEN for private repos or to raise the API rate limit. The plugin's @jalco/ap-sdk import is resolved to the SDK running the install, so simple plugins need no dependency install of their own.

From npm

Use the npm: source form to fetch a published package, run the same compatibility check, and install only if it default-exports a valid ap-sdk plugin:

npx ap-sdk install npm:@acme/git-helper
npx ap-sdk install npm:@acme/git-helper@1.2.3 -t claude
npx ap-sdk check npm:@acme/git-helper@next

Version pinning uses the suffix after the package name (npm:name@1.2.3 or a dist-tag like npm:name@next). Scoped names keep their scope: npm:@scope/name@1.2.3.

Packages can point at a non-root plugin file with package metadata:

package.json

{
  "ap-sdk": { "plugin": "./dist/plugin.js" }
}

If that field is absent, the CLI looks for the usual plugin.ts, plugin.js, or ap-sdk.config.ts; use --path <dir> for packages that contain the plugin inside a subdirectory.

Uninstalling

Every non-dry-run install records exactly what was written in .ap-sdk/install-manifest.json for project installs, or ~/.ap-sdk/install-manifest.json for global installs. Remove a recorded plugin with:

npx ap-sdk uninstall git-helper
npx ap-sdk uninstall git-helper --dry-run
npx ap-sdk uninstall git-helper --global

Uninstall deletes only recorded files and removes only the plugin's entries from shared configs (instruction blocks, MCP servers, hooks). Installs made before this manifest existed have no record, so they cannot be auto-removed.

Programmatic install

Everything the CLI does is available as a function, so you can install from your own script or a postinstall step:

install.ts

import installPlugin from "./plugin";
import { installSkills } from "@jalco/ap-sdk";

const installed = installSkills(installPlugin, {
  targets: ["claude", "cursor"],
  scope: "project", // or "global"
  dryRun: false,
});

for (const item of installed) {
  console.log(item.harness, item.kind, item.name, "→", item.files);
}

installSkills returns an InstalledItem[] describing every file written (or, in a dry run, every file that would be written) plus any per-harness notes.

Next steps