jetbrains-plugin-development

star 14

IntelliJ Platform plugin development for JetBrains IDEs. Use when writing, debugging, or migrating a JetBrains plugin — `plugin.xml`, services, actions, PSI/VFS/Document, EDT/BGT threading and Read/Write actions, Kotlin coroutines on the IDE platform, custom languages (Grammar-Kit, JFlex, lexer/parser, syntax highlighting, completion, references), code insight (folding, inspections, intentions, inline completion, inlay hints), Kotlin UI DSL v2, tool windows, settings, run/debug configurations, External System (Gradle/Maven), IntelliJ Platform Gradle Plugin 2.x, dynamic reload, Plugin Verifier, signing, and Marketplace publishing; legacy migrations (`ApplicationComponent`, `getCoroutineScope`, raw `Thread`/`ExecutorService`). Not for end-user IDE configuration or vmoptions tuning.

buYoung By buYoung schedule Updated 4/28/2026

name: jetbrains-plugin-development description: >- IntelliJ Platform plugin development for JetBrains IDEs. Use when writing, debugging, or migrating a JetBrains plugin — plugin.xml, services, actions, PSI/VFS/Document, EDT/BGT threading and Read/Write actions, Kotlin coroutines on the IDE platform, custom languages (Grammar-Kit, JFlex, lexer/parser, syntax highlighting, completion, references), code insight (folding, inspections, intentions, inline completion, inlay hints), Kotlin UI DSL v2, tool windows, settings, run/debug configurations, External System (Gradle/Maven), IntelliJ Platform Gradle Plugin 2.x, dynamic reload, Plugin Verifier, signing, and Marketplace publishing; legacy migrations (ApplicationComponent, getCoroutineScope, raw Thread/ExecutorService). Not for end-user IDE configuration or vmoptions tuning.

JetBrains IDE Plugin Development (IntelliJ Platform SDK)

This skill carries the IntelliJ Platform SDK domain knowledge needed to write, debug, and modify JetBrains IDE plugins competently. It is opinionated toward 2024.1+ targets (Kotlin coroutines, IntelliJ Platform Gradle Plugin 2.x, light services with @Service, dynamic plugin defaults) and calls out where pre-2024.1 patterns are still required.

How to use this skill

  1. Read the mental model below — it is small but governs almost every decision.
  2. Pick the reference file from the Capability index that matches the task and read it before editing.
  3. For end-to-end shapes — how the registrations, classes, and plugin.xml of a feature line up — open the matching folder under examples/.
  4. Before declaring any plugin-modifying task done, walk the Pre-flight checklist.

Do not invent extension point names, attribute names, or API signatures. The Platform is highly specific about strings (language="JAVA" vs "java", EP IDs, attribute spellings); a wrong character is enough to silently disable a feature. When unsure, surface the question to the user with the relevant reference cited — and verify the spelling in the IDE's plugin.xml editor, which auto-completes valid EP names from the loaded plugin set and underlines unknown ones.

Mental model — five invariants you must hold

These five invariants explain almost every "why doesn't this work?" question.

  1. plugin.xml is the contract. A class is invisible to the IDE until it is registered. @Service, @Service(cs) annotations and a few META-INF/ filename conventions are the only exceptions; everything else (extensions, listeners, actions, EPs you define, dependencies) must appear in plugin.xml (or a config-file of an <depends optional> block).
  2. Extensions are stateless; services hold state. EP implementations are constructed once per scope and shared across all calls and threads. Storing mutable state on an extension leaks across projects, threads, and dynamic reloads. Put state in a service (@Service / @Service(Service.Level.PROJECT)), and have extensions look it up on demand.
  3. Threading is non-negotiable. Reading platform model state (PSI, VFS, Document, project model) needs a Read Lock. Writing needs a Write Lock and must start on the EDT (or via the suspending writeAction/backgroundWriteAction). Long work belongs on a background thread with progress and cancellation. EDT freezes are user-visible; lock violations are immediate exceptions or data corruption. New code on 2024.1+ uses Kotlin coroutines (Dispatchers.EDT, readAction { }, writeAction { }, cs.launch { }).
  4. Disposer is how lifecycle works. Resources tie into a Disposable parent and the platform calls dispose() post-order when the parent goes away. Services are usually the right parent. Never use Application or Project directly as a parent — that traps resources past plugin unload and leaks the classloader. CoroutineScope injection on a @Service is the modern alternative to Disposable.
  5. Dynamic plugin reload imposes hard constraints. The default since 2020.1 is require-restart="false". To stay reloadable: every EP your plugin contributes to and defines must be dynamic, no static caches of plugin classes, no object singletons holding state, no listeners parented to Application/Project, no overrides="true" services.

Capability index

Use this section as a router. Do not bulk-read every reference. Start with the single most specific reference below, then add companion references only when the task crosses that boundary.

Reference filenames are prefixed by category for fast scanning: 01_core, 02_runtime, 03_lifecycle, 04_threading, 05_file_model, 06_code_insight, 07_language, 08_ui, 09_project, 10_execution, and 11_distribution.

Common task playbooks

These are decision sketches — they tell you which references to combine, not the full answer.

"Add a new feature triggered by a menu item or shortcut"

  1. Define an AnAction subclass — see 02_runtime_actions.md.
  2. Register it under <actions> in plugin.xml — see 01_core_plugin_xml.md.
  3. Make update() cheap; declare getActionUpdateThread() — see 02_runtime_actions.md.
  4. Long work goes through 04_threading_background_work_progress.md or 04_threading_coroutines_2024.md.

"Add support for a new language"

  1. Start with 07_language_pipeline.md, then walk the step-specific language references in order: 07_language_file_type.md, 07_language_lexer_jflex.md, 07_language_grammar_kit_bnf.md, 07_language_parser_definition_psi_file.md, 07_language_syntax_highlighting.md, 07_language_annotator.md, 07_language_completion.md, and 07_language_references_resolution.md.
  2. For search/refactoring/docs, add 07_language_find_usages_provider.md, 06_code_insight_documentation_target_api.md, or 06_code_insight_refactoring_documentation_structure.md.
  3. For navigation/insights, add the matching editor reference: 06_code_insight_line_markers.md, 06_code_insight_folding.md, 06_code_insight_formatter_commenter.md, 06_code_insight_inspections_intentions_quick_fixes.md, 07_language_postfix_templates.md, or 06_code_insight_surround_with.md.
  4. Compare the implementation against examples/simple_language_plugin/.

"Add a tool window with a settings page"

  1. Tool window surface: 08_ui_tool_windows.md.
  2. State persistence: 02_runtime_services.md and 08_ui_settings_persistent_state.md.
  3. Settings page: 08_ui_settings_configurable.md.
  4. Panel construction: 08_ui_kotlin_ui_dsl.md.

"Migrate threading from Thread/ExecutorService/Task.Backgroundable to coroutines"

Read 04_threading_thread_to_coroutine_migration.md first. Add 04_threading_coroutines_2024.md for API details, 02_runtime_services.md for injected CoroutineScope, and 04_threading_background_work_progress.md when replacing progress indicators.

"Migrate a legacy ApplicationComponent/ProjectComponent to a modern shape"

Read 02_runtime_legacy_component_migration.md first. Add 02_runtime_services.md, 02_runtime_listeners_message_bus.md, 09_project_lifecycle.md, and 02_runtime_deprecated_api_migrations.md as needed.

"Picking a UI surface for a new feature"

Read 08_ui_surface_selection.md first. Then route to 08_ui_kotlin_ui_dsl.md, 08_ui_tool_windows.md, 08_ui_dialogs.md, 08_ui_tables.md, 08_ui_choosers.md, 08_ui_status_bar_widgets.md, 08_ui_notifications.md, or 08_ui_data_context.md based on the chosen surface.

"A registered extension does nothing in the running IDE"

Read 01_core_extension_diagnostics.md. Add 01_core_plugin_xml.md, 01_core_dependencies.md, or 01_core_extensions.md if the diagnosis points to descriptor, dependency, or EP spelling issues.

"A code-insight feature does nothing in production"

Read the provider-specific reference first — for example 06_code_insight_folding.md, 06_code_insight_line_markers.md, 07_language_annotator.md, 07_language_completion.md, 07_language_inline_completion.md, or 06_code_insight_inspections_intentions_quick_fixes.md. Then read 06_code_insight_diagnostics.md for cross-cutting pipeline checks.

"React to typing, Enter, Backspace, or editor actions"

Read 02_runtime_typed_handlers_editor_actions.md first. Add 06_code_insight_editor_model.md, 05_file_model_documents.md, and 04_threading_read_write_actions.md if the handler changes text or caret state.

"Add gray inline suggestions or an inline completion provider"

Read 07_language_inline_completion.md first. Add 06_code_insight_editor_model.md, 05_file_model_documents.md, and 04_threading_coroutines_2024.md if the provider needs editor state, document reads, debouncing, or cancellable background work.

"Work on Next Edit Suggestions"

Read 07_language_next_edit_suggestions.md first. Do not invent a Next Edit provider EP; if the user wants a third-party implementable suggestion source, route the implementation through 07_language_inline_completion.md.

"Make a plugin Remote Development-ready"

Read 01_core_split_mode_remote_development.md first. Add 08_ui_tool_windows.md, 08_ui_dialogs.md, 02_runtime_typed_handlers_editor_actions.md, or 06_code_insight_file_editor_provider.md when the feature has frontend UI or latency-sensitive editing behavior.

"Add a custom editor, preview, or embedded browser"

Read 06_code_insight_file_editor_provider.md first for editor tabs. Add 08_ui_jcef_embedded_browser.md only when the custom editor or tool window genuinely needs browser rendering.

Pre-flight checklist before declaring work done

Run through this whenever you touch plugin code or plugin.xml. Most regressions show up here.

  • plugin.xml parses (open in IDE, no red underlines; XML DTD validation enabled).
  • <depends>com.intellij.modules.platform</depends> is present.
  • Every new EP usage cites a real EP — verified against the IDE's plugin.xml completion (which only offers EPs from the plugins your <depends> resolved). Language IDs spelled correctly (case-sensitive).
  • Every new extension implementation is final/class (not object), parameterless constructor (or only Project/Module/CoroutineScope), no static initializers, no work in the constructor.
  • Every service is a light service (@Service) unless there is a real reason not to. Constructors only take 0–2 of: Project, Module, CoroutineScope. No other services injected via constructor.
  • Every new Disposable registers under a plugin-controlled parent, not Application/Project.
  • Long-running work runs off the EDT, calls ProgressManager.checkCanceled() or uses coroutine suspension points, and re-throws ProcessCanceledException / CancellationException rather than swallowing them.
  • PSI/Document writes are inside a WriteCommandAction (or writeCommandAction { }), so they participate in undo.
  • No new Dispatchers.Main, GlobalScope, kotlinx.coroutines.runBlocking, raw new Thread(...), or Executors.new*ThreadPool() — replaced with Dispatchers.EDT, injected cs, runBlockingCancellable, and AppExecutorUtil.
  • Run Plugin DevKit inspections: "Non-default constructors for service and extension class", "Cancellation check in loops", "Plugin XML errors". They catch most violations automatically.
  • runIde boots, the changed feature works in the sandbox, and the IDE log (idea.log in the sandbox config dir) has no new exceptions related to the plugin.
  • If targeting multiple IDE versions: the verifyPlugin Gradle task (2.x; older guides may call it runPluginVerifier) passes against the declared sinceBuild and a recent build.
  • If altering existing functionality: confirm dynamic reload still works (autoReload = true, install/uninstall in sandbox without IDE restart).

Conventions used across this skill

  • "EDT" = Event Dispatch Thread (Swing UI thread). "BGT" = any non-EDT thread.
  • "PCE" = com.intellij.openapi.progress.ProcessCanceledException.
  • "EP" = extension point. "Light service" = service declared via @Service (no plugin.xml).
  • API stability tags follow @ApiStatus: Internal is forbidden for plugin code, Experimental may break across versions, Obsolete has a stable replacement, plain public is stable. Where a reference notes "Experimental", treat it as a deliberate trade-off.
  • Code samples are Kotlin where the platform offers a Kotlin-friendly API (which is most of 2024.1+); Java appears when an API has no Kotlin form or when describing legacy code.

Where to look inside this skill

The skill is self-contained — references explain the why, examples show the how:

  • references/ — capability-indexed deep dives. Read the one that matches your task before editing.
  • examples/simple_language_plugin/ — full custom-language skeleton.
  • examples/action_basics/AnAction + dynamic ActionGroup + keymap registration.
  • examples/settings_persistence/@Service + SimplePersistentStateComponent + Kotlin UI DSL v2 Configurable.
  • examples/inline_completion_provider/ — minimal InlineCompletionProvider plus plugin.xml registration.
  • examples/folding_builder/ — minimal FoldingBuilderEx plus plugin.xml registration for a known host language.

When the user reports a behaviour you can't explain from these alone, stop and ask rather than fabricate API names or attribute spellings. The IDE's plugin.xml editor (with auto-complete and validation against the resolved plugin set) is the authoritative live verification surface.

Install via CLI
npx skills add https://github.com/buYoung/skills --skill jetbrains-plugin-development
Repository Details
star Stars 14
call_split Forks 3
navigation Branch main
article Path SKILL.md
More from Creator