Amp supports extension through plugins written in TypeScript.
The docs show the most recent version of the Plugin API and examples at: https://ampcode.com/docs/plugin-api
The amp plugins subcommand allows you to exercise plugin code.
The amp plugins show-docs commands tells you the exact plugin API supported by this version of Amp.
When the load_plugin tool is available, use it to load a new plugin or reload one
plugin after changing it. When the reload_plugins tool is available, use it to
reload all plugins — including re-fetching global User/Workspace plugins after a
push — without restarting Amp. Otherwise, tell the user they may need to restart
Amp before plugin changes are active.
Listing installed plugins
Amp plugins are TypeScript/JavaScript extension files. They are not agent modes, built-in tools, or MCP servers; when asked what plugins are installed, enumerate actual plugins rather than listing those. To enumerate:
- Run
amp plugins listfor project-local plugins (.amp/plugins/). - List
~/.config/amp/plugins/for user-local plugins. - Run
amp plugins repositoriesfor the global User/Workspace scopes, then list the root plugin files and plugin directories in each repository it names.
A global scope reported with no plugins yet is simply empty — tell the user they have no global plugins there. No repository exists until the first push creates it, so do not present that as a problem or a missing repository.
Plugin locations
There are three kinds of location:
- Project-local:
.amp/plugins/in the workspace (this repo only). - User-local:
~/.config/amp/plugins/(this machine only, all repos). - Global: User/Workspace Plugins repositories, shared across all of the user's machines and threads.
Discover global repositories first with amp plugins repositories. It lists each
scope (User/Workspace) with its clone URL and amp clone command, whether it
has any plugins yet, and whether the user can write it. If the command is
unavailable or lists no repositories, only the two local directories are
available.
Pick the location:
- If the user names a location (e.g. "project", "just on this machine", "my user plugins"), use it.
- Repository- or app-specific plugins belong project-local, checked in with the project's code.
- In an Amp sandbox/orb, user-local directories do not outlive the sandbox, so a persistent plugin belongs in a global repository (or project-local when it is repo-specific). Default an unqualified request to the User Plugins scope.
- Elsewhere, when global repositories are available, also default an unqualified request to the User Plugins scope (available everywhere the user runs Amp, across machines), briefly mentioning the alternatives so the user can redirect you: project-local (version-controlled with the repo; this project only), user-local (this machine only), and — when its scope is listed and writable — workspace (shared with the whole team). Push mechanics are your job during the writing workflow, not a concern to surface here.
- Global repositories are unavailable only when
amp plugins repositoriesis missing or lists nothing (the feature is not enabled); a scope with no plugins yet is still available and writable. When unavailable, default an unqualified request to user-local, and if the project already has plugins ask whether they want project-local or user-local.
Importing an Amp plugin URL
Inspect an Amp personal plugin URL with read_web_page. If it is inaccessible, say
it may be private or unavailable. If the current user message explicitly asks to
import it, clone the requested User or Workspace Plugins repository. Then run
amp plugins import <url> --repository <clone-directory>.
This downloads and verifies the revision-pinned files but does not commit or push.
For an explicit update request, run amp plugins update <name> in the clone, never
to check or compare.
Use --force only when explicitly asked to replace committed changes.
Review the imported files, then use the signed global repository commit and push
workflow below. Only a workspace admin can push a Workspace import, and the
Workspace scope must be writable. A personal plugin with the same name continues
to take precedence for that user until it is deleted.
For a named member, use list_workspace_members, then
find_shared_plugins_and_skills with their userID, the kind, and the name.
Writing a new plugin
- Pick the location using "Plugin locations" above before running
amp plugins show-docs, inspecting plugin directories, or writing any files. - Get the plugin API understood by this version of amp with
amp plugins show-docs. - Write the plugin in the selected location. Include the optional
export const description = '...'named export (a static string literal of at most 300 characters) summarizing what the plugin adds; listings show it. - For local plugin directories, call
load_pluginwith the plugin path when the tool is available; otherwise ask the user to reload. - Test the plugin's behavior.
Bundling skills
When a plugin needs workflow guidance, use a directory plugin and put each
standard skill package under skills/<skill-name>/SKILL.md. Register it
when the plugin loads:
export default async function (amp) {
await amp.registerSkill({ path: 'skills/<skill-name>' })
}
Amp does not scan skills/ automatically. The path is relative to the plugin
directory, and the skill frontmatter name must match its directory name. Amp
lists the skill as <plugin-name>:<skill-name>; there is no bare alias.
Single-file plugins cannot register skills. Put the registration after any
enablement check when the skill should only be available with the plugin's tools.
After loading the plugin, verify the qualified name with
amp skill info <plugin-name>:<skill-name> and test that the skill can read any
bundled resources it uses.
When a plugin registers many tools, gate them behind a bundled skill so they do
not occupy context in unrelated threads. List the tool names in the skill's
builtin-tools frontmatter field; those tools stay hidden until the skill is
loaded, which also documents their full schemas in the skill content. Only the
plugin's own tools can be gated, and tools not listed in any of the plugin's
skills stay always visible. The skill's description is then the discovery
surface for the whole toolset, so make it state when to use the tools.
Writing to a global repository
- Only offer a scope whose
amp plugins repositoriesentry is writable. If the Workspace scope is read-only for you, write to your User scope instead and suggest that a workspace admin copy or import it into the workspace scope. - A global plugin is a root
.ts/.jsfile or a<name>/directory withindex.tsorindex.jsand its supporting files. - Work in the canonical clone directory, never in the repo root:
~/.cache/amp/repositories/<host>-<scope>-plugins(host from the clone URL, e.g.~/.cache/amp/repositories/ampcode.com-user-plugins). If the directory already holds a clone, reuse it: fetch and reset to the remote's main branch instead of re-cloning.- If the repository exists, clone it there with the
amp clonecommand thatamp plugins repositoriesprints, passing the cache directory as the target (it handles authentication); add the plugin and commit. - If the scope has no plugins yet (no repository to clone),
git initthe cache directory, rungit config credential.helper '!amp git-credential-helper', add the plugin, commit, then add the clone URL as theoriginremote (create-on-first-write creates it on the first push).
- If the repository exists, clone it there with the
- Do not push unless the user explicitly asks or confirms. A new plugin or a
change to an existing one only takes effect after a push, so after committing,
offer to push, naming the destination repository (for example "Ready to
push this to your global user plugins repository so it takes effect?") —
never a bare "Want me to push it?", a destination-less "committed" or "not
pushed", or git mechanics.
After a confirmed push, say where it was published. Explain that new threads
load the new version automatically, but existing threads do not. Offer
reload_plugins(when available) to update the current thread. - Never mix local and global plugins for the same scope in one request.