name: add-plugin
description: Use this skill when the user wants to add, refactor, or generalize a agentpay <plugin> integration like Bitrefill. Follow the shared plugin registration path under src/plugins, keep plugin-specific API or scraping code under src/lib/<plugin> or src/lib/<plugin>/, reuse the existing Rust daemon signing and policy path through the shared CLI plugin context instead of reimplementing signing, and add focused CLI tests for the new plugin.
Add Plugin
Use this skill when the task is "add another plugin like Bitrefill" or "make plugin onboarding more reusable."
Ground Truth
src/cli.tsis the main CLI entrypoint, but plugin-specific command trees should not be wired inline there.src/plugins/types.tsdefines the sharedCliPluginContextand the generic plugin registrar shape.src/plugins/index.tsis the registry for built-in plugins.src/plugins/bitrefill.tsis the reference implementation for a plugin that owns its own command tree.- Plugin-specific HTTP or browser/bootstrap code belongs in
src/lib/<plugin>.tsorsrc/lib/<plugin>/. - Signing, policy checks, manual approval handling, and raw transaction broadcast plumbing stay on the existing AgentPay path exposed through
CliPluginContext.
Default Architecture
- Create
src/plugins/<plugin>.ts. - Register the plugin in
src/plugins/index.ts. - Keep plugin-local API normalization, transports, cookies, scraping, or challenge handling in
src/lib/<plugin>*. - Keep
src/cli.tsresponsible only for assembling shared dependencies and callingregisterBuiltinCliPlugins(...). - Reuse
context.agent.runJson(...)pluscontext.broadcast.*for any payment flow that reaches the daemon.
Implementation Rules
- Do not add another large inline
.command('<plugin>')block tosrc/cli.ts. - Do not reimplement signing, nonce management, or policy logic in the plugin.
- If the plugin needs onchain payment, default to preview-first behavior and make live payment explicit with
--broadcast. - If the plugin only needs a quote plus an optional live payment path, prefer one
buy-style command over a redundant separatepricecommand. - Keep plugin-specific error handling inside the plugin module when possible.
- If a remote API needs browser bootstrap, Cloudflare handling, or cookies, isolate that behind the plugin's transport/client layer instead of leaking it into the shared CLI.
- Pass only shared helpers through
CliPluginContext; keep plugin business logic inside the plugin module.
Deterministic Workflow
- Inspect
src/plugins/bitrefill.tsto copy the current plugin structure and command style. - Add or extend the plugin client under
src/lib/<plugin>*. - Add a new
CliPluginimplementation undersrc/plugins/<plugin>.ts. - Register it in
src/plugins/index.ts. - If the plugin needs signing or broadcast, use
context.config,context.agent, andcontext.broadcastinstead of shelling around the shared flow. - Add a focused CLI test file or extend the closest existing one under
test/. - Run the plugin-focused tests and at least one
agentpay <plugin> --helpsmoke check.
Testing Rule
- Prefer mocked CLI/integration tests over live third-party dependencies.
- Cover command registration, happy path output, unsupported modes, and any explicit challenge or approval state.
- If the plugin supports
--broadcast, cover both preview-only and broadcast-backed flows.
References
- Read
src/plugins/types.tsfor the shared context contract. - Read
src/plugins/index.tsfor plugin registration. - Read
src/plugins/bitrefill.tsfor the current plugin pattern. - Read the matching
src/lib/<plugin>*module only when implementing that plugin's remote API behavior.