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.
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
Read the mental model below — it is small but governs almost every decision.
Pick the reference file from the Capability index that matches the task and read it before editing.
For end-to-end shapes — how the registrations, classes, and plugin.xml of a feature line up — open the matching folder under examples/.
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.
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).
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.
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 { }).
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.
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.
02_runtime_legacy_component_migration.md: Migrating ApplicationComponent, ProjectComponent, or ModuleComponent to services, extensions, listeners, and startup activities.
06_code_insight_formatter_commenter.md: FormattingModelBuilder + Block (indent/wrap/SpacingBuilder/getChildAttributes) for Ctrl+Alt+L, and Commenter for Ctrl+/ line/block comment toggles.
06_code_insight_diagnostics.md: Generic "why does my code-insight provider do nothing?" debug flow (EP/language match, construction, threading, Dumb Mode, ordering, prod-only missing dependencies) plus cross-cutting LineMarkerProvider/FoldingBuilder/Annotator/IntentionAction pitfalls.
07_language_pipeline.md: End-to-end pipeline for adding a new language/DSL (FileType → Lexer → Parser → ParserDefinition → PSI → highlighter/annotator/completion/references/code insights), LSP-backed alternatives, and the order to implement them.
07_language_file_type.md: Language singleton, LanguageFileType, case-sensitive Language ID, and <fileType> registration with mandatory fieldName="INSTANCE".
07_language_syntax_highlighting.md: Lexer-based syntax highlighting (SyntaxHighlighterBase, TextAttributesKey with DefaultLanguageHighlighterColors fallbacks), <lang.syntaxHighlighterFactory> registration, and ColorSettingsPage for user-themable colors.
07_language_annotator.md: Annotator for PSI-based semantic warnings/errors, AnnotationHolder builder API (.create() is mandatory), Annotator vs LocalInspectionTool decision, and stateless/cheap/cached-resolution rules.
07_language_find_usages_provider.md: FindUsagesProvider, WordsScanner, usage presentation, result grouping, Rename, and Safe Delete prerequisites.
07_language_element_patterns.md: PlatformPatterns/StandardPatterns/PsiJavaPatterns matcher DSL — gating completion and reference contributors via .withParent/.withSuperParent/.afterLeaf/.afterSibling/custom PatternCondition.
07_language_injection.md: MultiHostInjector for injecting another language into string literals (regex inside Java strings, SQL inside Kotlin templates) so the inner language gets full PSI/completion/inspection.
07_language_code_vision_inlay_hints_polysymbols.md: Inline editor hints — DeclarativeInlayHintsProvider (2023.2+) and legacy <inlayHintsProvider> for parameter/type hints, <codeVision.provider> for usages/refs counts, and Polysymbols for polyglot web files.
07_language_custom_language_diagnostics.md: Custom-language pitfalls — language= casing ("JAVA" vs "java"), reused stateful Lexer, BNF mixin work in generated *Impl, uncached annotator resolution, no-op setName, missing BAD_CHARACTER and <colorSettingsPage>.
08_ui_surface_selection.md: Choosing between Kotlin UI DSL, JB Swing components, actions, or standard Swing fallback.
09_project_basics.md: Project lookup and lifecycle (e.project, service injection, ProjectManager.getInstance(), defaultProject caveats), messageBus, and isDisposed/isOpen.
09_project_libraries_sdks_facets.md: LibraryTablesRegistrar and modifying libraries via Write Action, AdditionalLibraryRootsProvider/SyntheticLibrary, ProjectJdkTable and custom SdkType/ProjectSdkSetupValidator, and FacetManager/FacetType for per-module tech config.
09_project_workspace_model.md: Modern entity-based project structure — ImmutableEntityStorage/MutableEntityStorage, WorkspaceEntity subclasses (ModuleEntity, ContentRootEntity, LibraryEntity), suspend WorkspaceModel.update, change Flow<VersionedStorageChange>, and SymbolicEntityId/ExternalMappingKey for external-system tracking.
09_project_view.md: Project View tree customization — TreeStructureProvider to re-bucket/hide/decorate children, ProjectViewNodeDecorator for suffix/icon overlays, AbstractProjectViewPane for custom panes, and public selection helpers without internal pane extractor APIs.
09_project_lifecycle.md: Project lifecycle hooks — ProjectActivity (suspend) and StartupActivity.DumbAware via <postStartupActivity>, ProjectManagerListener, ModuleListener, ModuleRootListener.
10_execution_xml_dom_api.md: DOM API for typed XML configs (Spring beans, custom XML DSLs) — DomElement interfaces with @Attribute/@Required/GenericAttributeValue, DomFileDescription, Converter/ResolvingConverter for reference resolution, and <dom.fileDescription>/<dom.extender>.
10_execution_search_everywhere_api.md: Search Everywhere result providers, Remote Development-compatible APIs, serializable presentations, and migration from legacy contributors.
10_execution_diagnostics.md: Run/debug & integration pitfalls — RunProfileState.execute running on EDT, missing ProcessTerminatedListener.attach (no exit-code line), global OkHttpClient on a service blocking unload, DOM isMyFile namespace bugs, EDT-bound ErrorReportSubmitter/HttpRequests.
11_distribution_file_live_templates.md: <internalFileTemplate> for New-File templates (Velocity .ft files under resources/fileTemplates/internal/, name must match) and <defaultLiveTemplates> XML at resources/liveTemplates/.
11_distribution_vcs_extensions.md: VCS plugin EPs — AbstractVcs, ChangeProvider, VcsDirtyScopeManager, ContentRevision/FilePath/VcsRevisionNumber, VcsRoot/VcsRootChecker, diff/merge tools, and when to extend the existing Git plugin via <depends optional config-file> instead of a new AbstractVcs.
11_distribution_plugin_verifier.md: verifyPlugin Gradle task (2.x replacement for runPluginVerifier) — pluginVerification.ides { recommended()/create()/local() }, blocking issues (missing classes, @Internal usage from outside, plugin-class static reachability) vs informational @Experimental warnings.
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"
Define an AnAction subclass — see 02_runtime_actions.md.
Register it under <actions> in plugin.xml — see 01_core_plugin_xml.md.
Make update() cheap; declare getActionUpdateThread() — see 02_runtime_actions.md.
Long work goes through 04_threading_background_work_progress.md or 04_threading_coroutines_2024.md.
"Add support for a new language"
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.
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.
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.
Compare the implementation against examples/simple_language_plugin/.
"Add a tool window with a settings page"
Tool window surface: 08_ui_tool_windows.md.
State persistence: 02_runtime_services.md and 08_ui_settings_persistent_state.md.
Settings page: 08_ui_settings_configurable.md.
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).
"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/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.