Skip to content

Deploy a local bundle

You have a bundle on disk – a directory or .zip someone handed you (or a legacy .tar.gz), or the output of apm pack. Drop it into a project with one command:

Terminal window
apm install ./path/to/bundle
apm install ./dist/my-pkg-1.0.0.zip

This is a sibling flow to Install packages. Instead of declaring a dependency in apm.yml and resolving it from a registry, you deploy a self-contained bundle directly. apm.yml is not modified – the install is imperative, like dpkg -i next to apt install.

A plugin-format bundle is a directory, zip archive, or legacy gzipped tarball with a plugin.json at the root and primitive folders alongside it:

my-bundle/
+-- plugin.json
+-- agents/
+-- skills/
+-- commands/
+-- hooks/
+-- apm.lock.yaml # optional: bundle integrity manifest

plugin.json requires only a name. APM also recognises plugin.json under .github/plugin/, .claude-plugin/, or .cursor-plugin/. For the full schema see Package anatomy.

The optional apm.lock.yaml carries pack.bundle_files – a SHA-256 manifest written by apm pack. When present, APM verifies every listed file before deploying. When absent, older bundles still install with a warning unless policy requires hashes. With security.integrity.require_hashes: true, APM fails closed before deploy.

$ apm install ./dist/my-pkg-1.0.0.zip --target copilot
[>] Installing local bundle from ./dist/my-pkg-1.0.0.zip
[+] Bundle integrity verified
[+] Deployed 7 files to .github/

Steps APM runs:

  1. Detect. Path exists and contains plugin.json at the bundle root (zip archives and legacy tarballs are extracted to a temp directory first).
  2. Apply cached policy. Resolve the actual targets, then apply any cached org policy to bundle MCP, LSP, canvas, and target rules before files are written. Bundle install never fetches policy from the network. --no-policy skips this local gate for one invocation.
  3. Verify integrity. Hash every file listed in pack.bundle_files; reject any symlink, hash mismatch, or unlisted file.
  4. Deploy. Map agents/, skills/, commands/, hooks/, LSP metadata, and canvas extensions into the harness layout for each --target you passed. For plugin skill declaration precedence, see Package Types.
  5. Record. Write a lockfile entry under the project’s apm.lock.yaml so drift detection can audit the deployed files later.

apm.yml is never touched. Re-running the same command re-deploys (use --force to overwrite locally-edited files). If executable trust blocks bundle MCP, LSP, or canvas content, copy the exact name#version@sha256:<digest> key printed by apm install into executables.allow; changed bundle bytes require a new key. For centrally governed installs, warm the policy cache before distributing an offline bundle. See APM policy.

Most apm install flags target the registry/resolver pipeline and are rejected with a single error when used with a local bundle. The flags that do work:

Flag Use
--target, -t Pick which harness layouts receive files.
--global, -g Deploy to ~/.apm/ instead of the current project.
--force Overwrite locally-edited files on collision.
--dry-run Show what would be deployed; write nothing.
--no-policy Skip policy preflight for this invocation only.
--verbose, -v Print per-file deploy details.
--as ALIAS Override the display label in logs (local-bundle only).

Flags like --update, --only, --dev, --mcp, --registry, and --allow-insecure are not meaningful here – the imperative deploy path does not run the dependency resolver or registry lookup that those flags configure. APM rejects them up front with one consolidated error.

For the full flag list see the apm install reference.

Pass --target to scope the deploy. Without it APM auto-detects from the current project. If the bundle was packed for targets you are not installing into, APM prints a warning naming the missing targets and proceeds with what it can deploy.

A bundle packed with pack.target: all is target-agnostic and installs cleanly into any harness layout.

Bundles produced by the older apm pack --format apm carry an apm.lock.yaml at their root but no plugin.json. apm install rejects these with a targeted error:

'./dist/my-pkg-0.1.0.tar.gz' was packed with '--format apm' (legacy
format). 'apm install <bundle>' requires the plugin format. Repack with
'apm pack --claude-plugin --archive', or use 'apm unpack' to deploy the
legacy bundle.

Two ways forward:

  • Repack. If you own the bundle, run apm pack --archive (no format flag – the default Claude plugin bundle) and install the new artifact.
  • Unpack. If you only have the legacy artifact, use apm unpack <bundle> to extract it. apm unpack is deprecated and will be removed in a future release; prefer repacking when you can.

A plain directory without plugin.json is not treated as a bundle at all. APM falls through to the dependency resolver and treats the path as a local-path dependency – a different flow covered in Install packages.