Ionic logo

Skill

capacitor-plugin-generator

generate Capacitor plugin scaffolds

Published by Ionic Updated Jul 12
Covers Mobile Capacitor Engineering Ionic

Description

Generates new Capacitor plugin scaffolds and first-pass implementations from conversational requirements or a structured YAML input contract. Use when a user says "generate a Capacitor plugin", "create a Capacitor plugin scaffold", "build a native plugin for iOS and Android", "turn this plugin plan into Capacitor code", or "use this YAML contract to generate a plugin". Do not use for analyzing Cordova source, migrating whole apps, installing existing plugins, upgrading Capacitor versions, or publishing production-ready code without human review.

SKILL.md

Capacitor Plugin Generator

Generate a reviewable Capacitor plugin candidate from either human intent or a structured YAML contract. The output should follow the official Capacitor plugin architecture, but it is a first pass that requires human review before release.

When to Use This Skill

Use this skill when:

  • Creating a new Capacitor plugin from scratch.
  • Adding native functionality (camera, sensors, storage, etc.) to a Capacitor app.
  • Designing plugin architecture and API contracts.
  • Implementing native code for iOS (Swift) or Android (Kotlin/Java).
  • Bridging native APIs to JavaScript/TypeScript.
  • Setting up plugin configuration and build systems.
  • Generating a plugin from a structured YAML contract handed off by the cordova-capacitor-plugin-migration skill.

Do NOT use this skill for:

  • Building standard Capacitor apps (use Capacitor documentation instead).
  • Web-only features that don't require native bridges.
  • Modifying existing Capacitor core plugins.
  • Analyzing Cordova plugin structure (use cordova-capacitor-plugin-migration first; that skill produces the input contract this skill consumes).
  • Upgrading existing plugins to newer Capacitor versions.
  • Publishing production-ready code without human review.

Prerequisites

RequirementUse
Node.js LTS and npmRun the Capacitor plugin generator and package scripts.
XcodeBuild and verify iOS output when iOS is targeted.
Android Studio and Android SDKBuild and verify Android output when Android is targeted.
CocoaPods and GradleResolve native dependencies when required by generated code.
Capacitor plugin knowledgeReview generated native bridge code before publishing.

Agent Behavior

  • Detect whether the user provided conversational intent or structured YAML.
  • In conversational mode, ask only for missing plugin identity, methods, platforms, events, permissions, configuration, and native dependencies.
  • In structured mode, parse references/input-contract.md, skip elicitation, and halt if the optional migration block contains blockers or tier 3 hooks.
  • Treat migration metadata as implementation context only. Do not inspect or analyze Cordova source; that belongs to the migration skill.
  • Prefer the official Capacitor plugin generator, then edit the generated scaffold to implement the requested API.
  • Keep generated code contract-first: TypeScript definitions drive web, iOS, Android, docs, and sample app behavior.
  • Use only Capacitor classes that exist in the installed @capacitor/core, @capacitor/android, and @capacitor/ios packages. Do not invent helper classes, utilities, or import paths. When uncertain whether an API exists, read the package source rather than infer from its name.
  • When the generated TypeScript contract mirrors an existing public API (Capacitor core/community, Capawesome, internal libraries, or a documented JavaScript API the user is replacing), look up the actual string literal values used on the wire. Do not derive them from human-friendly names. Structured-mode YAML pins these values explicitly; conversational-mode generation must consult the source.
  • Keep bridge files thin. Split native logic into implementation, manager, permission, config, and mapper helpers when a method would otherwise become a large mixed-responsibility block.
  • Choose native APIs by intended product behavior, not by demo convenience. If the requested behavior requires permissions, special app settings, or manual app configuration, generate the proper checkPermissions() / requestPermissions() flow and document the manual setup.
  • Clearly report which verification commands were run and which need local human/device validation.
  • Never publish for real from this skill. Run publish checks and npm publish --access public --dry-run only.

Procedures

Phase 1: Determine the Task and Entry Mode

Read references/input-contract.md. If the input is YAML with plugin, platforms, and api, parse it as structured mode and skip questions. If the input is conversational, elicit the minimum missing fields needed to create the same contract shape internally.

Phase 2: Scaffold

Read references/scaffolding.md. Run the official Capacitor plugin generator with non-interactive flags when possible. Enforce name parity: registerPlugin() JavaScript name equals iOS jsName equals Android @CapacitorPlugin(name).

Phase 3: Design the TypeScript API

Read references/api-design.md. Define src/definitions.ts before native implementation. Use options/result interfaces per method, string unions instead of enums, listener signatures for events, and JSDoc with @since everywhere.

Phase 4: Implement the Web Layer

Read references/web-guide.md. Extend WebPlugin, feature-detect browser APIs before use, throw unavailable() when an API exists but is unavailable in the current browser, and throw unimplemented() when no web equivalent exists. Register the web layer through a dynamic import.

Phase 5: Define Method Signatures

Read references/api-design.md. For every method, choose one bridge return type: value, void, or callback. Use callback return types only for streams or long-lived watchers. Keep event names identical across TypeScript, web, iOS, and Android.

Phase 6: Implement iOS

Read references/architecture-patterns.md and references/ios-implementation.md. Use the Bridge pattern by default: a thin Capacitor plugin class delegates to an implementation class. Use a Facade only for complex plugins with multiple native subsystems, permission flows, or lifecycle concerns.

Phase 7: Implement Android

Read references/architecture-patterns.md and references/android-implementation.md. Use the Bridge pattern by default: a thin Plugin class delegates to an implementation class. Use a Facade only for complex plugins with multiple managers, permission flows, services, activities, or lifecycle hooks.

Phase 8: Generate a Sample App

Read references/sample-app.md. Create or update a sample app that exercises the entire public plugin API, including success paths, expected errors, permissions, configuration, and listeners.

Phase 9: Docgen and Verify

Read references/testing-strategies.md and references/publishing.md. Generate API docs from JSDoc with npm run docgen; do not hand-write API docs. Run the relevant verify commands for targeted platforms and record any environment-limited checks.

Phase 10: Publish Checks

Read references/publishing.md. Run the pre-publish checklist and dry run: npm publish --access public --dry-run. Do not publish the generated plugin without explicit human review outside this skill.

Best Practices

DO

  • ✅ Use command-line flags with npm init @capacitor/plugin so the scaffolder runs non-interactively.
  • ✅ Detect entry mode (conversational vs structured YAML) before asking questions. Skip elicitation entirely in structured mode.
  • ✅ Design the TypeScript API first (contract-first), then implement web, iOS, and Android against that contract.
  • ✅ Implement the web layer for testing without devices, even when most methods throw unimplemented().
  • ✅ Inspect the official plugin's native dependencies when mirroring an existing API; declare the same SDKs and write a thin adapter rather than reimplementing.
  • ✅ Document every public symbol with JSDoc and @since.
  • ✅ Run npm run fmt before committing and npm run verify before reporting completion.
  • ✅ Use the two-class pattern (bridge + implementation) on iOS and Android for testability.
  • ✅ Match wire-format string and numeric values exactly when mirroring an existing API. Look up the official definitions.ts rather than guessing from human-friendly names.
  • ✅ Keep event names identical across TypeScript / web / iOS / Android.

DON'T

  • ❌ Mix concerns — keep the plugin focused on one capability.
  • ❌ Skip error handling. Reject with codes from the canonical 4-code taxonomy (UNAVAILABLE, PERMISSION_DENIED, INVALID_PARAMETER, OPERATION_FAILED).
  • ❌ Use callbacks instead of promises in the TypeScript surface.
  • ❌ Forget the web implementation, even for iOS/Android-only features.
  • ❌ Hard-code values that should be configurable. Use references/configuration.md runtime plugin configuration.
  • ❌ Invent Capacitor classes, helpers, or import paths. Verify against the installed @capacitor/core, @capacitor/android, and @capacitor/ios packages.
  • ❌ Call notifyListeners(...) from outside the Plugin subclass — see references/architecture-patterns.md "Event Dispatch Locality".
  • ❌ Publish from this skill. Run dry-run only with npm publish --access public --dry-run.
  • ❌ Inspect or analyze Cordova source — that belongs to the sibling migration skill.

Error Handling

SymptomFix
npm init @capacitor/plugin fails with Refusing to prompt in non-TTY environmentPass all required flags non-interactively: npm init @capacitor/plugin <folder> -- --name "<npm-name>" --package-id "<reverse-dns>" --class-name "<PascalCase>" --description "<one-line>" --author "<name <email>>" --license "<SPDX>" --repo "<url>" --android-lang "<kotlin|java>". See references/scaffolding.md.
npm init @capacitor/plugin fails with invalid option: --android-lang undefined: Must be either 'kotlin' or 'java'The --android-lang flag is required when running non-interactively. Add --android-lang "kotlin" (recommended for new plugins) or --android-lang "java" to the command.
Plugin silently fails to loadMake registerPlugin() name match iOS jsName and Android @CapacitorPlugin(name).
Event not received in JSMake the event name string identical across TypeScript, web, iOS, and Android.
iOS method not callable from JSEnsure the method is marked @objc and listed in pluginMethods.
Android method not callable from JSEnsure the method is public and annotated with @PluginMethod().
npm run verify:ios failsRun pod install --repo-update; then rerun the iOS verify command.
npm run verify:android failsSync Gradle and check Android SDK, compile SDK, and dependency versions.
Android compile error: class X is public, should be declared in a file named X.javaJava requires a public class to live in a file matching its name. When generating multiple Java classes per plugin, place each public class in its own file. Kotlin does not impose this rule.
Android compile error: notifyListeners(...) has protected access in PluginnotifyListeners() is protected on Plugin. Call it only from inside a class that extends Plugin. If another class needs to emit events, return the data to the plugin and dispatch there, or expose a public wrapper on the plugin that calls notifyListeners() internally.
Android compile error: cannot find symbol: class … for a com.getcapacitor.* importThe import does not exist on the installed @capacitor/android surface. Verify imports against the package source before generating; do not infer Capacitor classes from their names.
Android compile error: <method> in <Subclass> cannot override <method> in Plugin; attempting to assign weaker access privileges; was publicA helper on the Plugin subclass collides with a public method that com.getcapacitor.Plugin already defines (e.g., hasPermission, getPermissionState, notifyListeners). Either rename the helper or match the parent's public visibility.
TypeScript build error: Cannot find type definition file for '<name>' or Invalid module name in augmentation, module '<name>' cannot be foundThe augmented module is not installed. Add it to devDependencies (and to tsconfig.json compilerOptions.types if a triple-slash reference is used). Applies to any module augmentation, not just @capacitor/cli.
TypeScript build error: Interface 'X' incorrectly extends interface 'Y'. Property 'Z' is optional in type 'X' but required in type 'Y' (or the symmetric error)Do not redeclare members the built-in lib type already provides. Use the lib type directly, or augment via declare global { interface Y { newMember?: ... } } for genuinely new members only. Use 'name' in target runtime guards for capability checks.
npm run docgen produces empty outputAdd JSDoc to src/definitions.ts; docgen reads the TypeScript contract.
Web API absent in target browserUse unavailable() when the API exists but is missing here; use unimplemented() when no web equivalent exists.
Structured YAML is rejectedValidate against references/input-contract.md; ensure required base fields are present and blockers are empty.
Generated output looks too broadSplit unrelated capabilities into separate plugins and regenerate with a smaller API surface.
Generated native code reimplements logic the official plugin delegates to a native SDKInspect the official plugin's .podspec / Package.swift / android/build.gradle for native SDK dependencies. If present, declare the same SDK and write a thin adapter — see references/api-design.md "Native Dependency Detection".
  • cordova-capacitor-plugin-migration: Analyze Cordova plugins and produce a structured migration plan for this generator.

References

  • references/input-contract.md: Structured YAML contract for generator input.
  • references/scaffolding.md: Generator invocation, name parity, and scaffold verification.
  • references/api-design.md: TypeScript API design, JSDoc, event signatures, and method return types.
  • references/web-guide.md: WebPlugin patterns, dynamic import, feature detection, and errors.
  • references/architecture-patterns.md: Bridge and Facade patterns plus event parity.
  • references/ios-implementation.md: iOS bridge, implementation class, permissions, dependencies, and Podspec.
  • references/android-implementation.md: Android bridge, implementation class, permissions, dependencies, and Gradle.
  • references/configuration.md: Capacitor config keys under plugins.<PluginJSName>.
  • references/testing-strategies.md: Local linking, verify commands, hooks, and review workflow.
  • references/publishing.md: Package fields, docgen, checklist, and dry-run publishing.
  • references/sample-app.md: Sample app requirements that exercise the full API.
  • references/permission-patterns.md: Deep-dive on permission flows — multi-permission DispatchGroup on iOS, location delegate, check-before-use / just-in-time / deferred consumer patterns, opening system settings.
  • references/typescript-implementation.md: Deep-dive on TypeScript layer — singleton plugin pattern, typed error classes, full event listener handle bookkeeping, helper utilities, Jest scaffolding.

© 2026 YourAI.tools. Every skill from an identity-verified publisher.

Independent catalog. Not affiliated with, endorsed by, or sponsored by Anthropic or any listed publisher. All trademarks belong to their respective owners.