Skip to content

Plugins

Extend AnyPick with your own provider, client, or gateway catalog — and what enabling one actually grants.

Updated View as Markdown

A plugin adds a provider, a client, or a gateway catalog entry to the anypick you already have installed. It is the answer to “we run our own model endpoint internally” and “we wrote our own coding agent” without forking the CLI.

Install one

anypick plugin add ./acme-provider   # recorded, disabled, digest pinned
anypick plugin list
anypick plugin enable acme-provider  # prompts — this is the trust decision

add never enables. Between the two commands the plugin exists in AnyPick’s registry and does not run.

  off  acme-provider        1.0.0      82aae3b7898d
    /Users/you/src/acme-provider

The short hex is a SHA-256 digest of the whole plugin package (manifest and every shipped file under the directory), pinned when you added it. AnyPick recomputes it and compares before importing the entry module, so code — including helpers the entry imports — that changed since you approved it never executes.

When the code changes

Pull a new version, or rebuild during development, and the plugin stops loading:

  fail acme-provider        1.0.0      82aae3b7898d
    Plugin acme-provider has changed since you trusted it.
    → anypick plugin trust acme-provider

Nothing else breaks — the rest of AnyPick works normally, and anypick doctor reports the refusal. Review the diff, then re-pin:

anypick plugin trust acme-provider

This is intentional friction, not a cache miss. The digest is what you approved.

Turning plugins off

anypick plugin disable acme-provider  # keep it installed, stop loading it
anypick plugin remove acme-provider   # uninstall
ANYPICK_NO_PLUGINS=1 anypick doctor   # skip every plugin for one run

The environment variable is the fast way to tell a plugin bug from a AnyPick bug.

Writing one

A plugin is a directory with a anypick.plugin.json and an ESM entry module:

anypick.plugin.jsonjson
{
  "name": "acme-provider",
  "version": "1.0.0",
  "apiVersion": 1,
  "main": "dist/index.mjs"
}
dist/index.mjsjs
export default {
  activate(ctx) {
    ctx.registerProvider(new AcmeProvider());
  },
};

activate is synchronous and runs during startup, in the same window where AnyPick’s built-in providers register and immediately before the registries are sealed. Register everything there; the context is not usable afterwards.

ctx is deliberately narrow — registerProvider, registerClient, registerCatalogProvider, and nothing else. There is no database handle, no store, and no data root, so a plugin extends the composition graph without receiving a general capability to read the accounts that graph manages.

main must resolve inside the plugin directory; an absolute path or one that escapes with ../ is refused. apiVersion is checked against the version this AnyPick build supports, so a mismatched plugin is refused with a version message rather than a stack trace.

The Provider, ClientAdapter, and CatalogProvider interfaces are exported from the package root, and the contributor guide covers what a good provider implements — particularly its model policy, which is what keeps your provider from inheriting another vendor’s model ids.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close