Develop IntelliJ IDEA plugins with two templates, standard plugins and AI-integrated plugins.
This Skill provides guidance for developing IntelliJ IDEA plugins using standardized templates. It covers two types of plugins: standard plugins (without AI) and AI-integrated plugins (with IntelliAI Engine).
Use this Skill when:
template-without-ai or template-with-ai)Use for: Plugins that don't require AI functionality.
Features:
Key Components:
ExampleAction - Single action exampleExampleIcons - Icon managementNotificationUtil - Notification helperExampleBundle - InternationalizationUse for: Plugins that need AI capabilities via IntelliAI Engine.
Additional Features:
Key Components:
SettingsState - Persistent configurationExampleSettingsConfigurable - Settings UIExampleSettingsPanel - Settings panel with AI provider dropdown and prompt templatestemplate-without-ai/
├── src/main/java/dev/dong4j/zeka/stack/idea/plugin/example/
│ ├── action/ # Actions
│ ├── icons/ # Icon management
│ └── util/ # Utilities (Bundle, Notification)
├── src/main/resources/
│ ├── icons/ # Icon resources (SVG)
│ ├── META-INF/
│ │ └── plugin.xml # Plugin configuration
│ └── messages*.properties # Internationalization
├── includes/ # Plugin description and changelog
├── docs/ # User manual
├── build.gradle.kts # Build configuration
└── gradle.properties # Plugin properties
template-with-ai/
├── src/main/java/dev/dong4j/zeka/stack/idea/plugin/example/
│ ├── action/ # Actions
│ ├── icons/ # Icon management
│ ├── settings/ # Settings (State, Configurable, Panel)
│ └── util/ # Utilities
├── ... (same as standard)
└── build.gradle.kts # Includes AI Engine dependencies
For standard plugins:
template-without-ai as baseFor AI-integrated plugins:
template-with-ai as baseUpdate gradle.properties:
pluginGroup=dev.dong4j.zeka.stack
pluginName=Your Plugin Name
pluginVersion=2026.1.1000
kitVersion=2026.1.1000
rootProjectName=your-plugin-name
Update plugin.xml:
Update package names:
dev.dong4j.zeka.stack.idea.plugin.example with your packageplugin.xml referencesStandard Action Pattern:
public class ExampleAction extends AnAction {
public ExampleAction() {
super(
ExampleBundle.message("action.example.title"),
ExampleBundle.message("action.example.description"),
ExampleIcons.EXAMPLE_16
);
}
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
Project project = e.getProject();
PsiFile psiFile = e.getData(CommonDataKeys.PSI_FILE);
if (project == null || psiFile == null) {
NotificationUtil.showError(project, ExampleBundle.message("error.no.file"));
return;
}
// Your action logic here
NotificationUtil.showInfo(project, "Action executed");
}
}
Register in plugin.xml:
<action id="your.package.action.ExampleAction"
class="your.package.action.ExampleAction">
<add-to-group group-id="EditorPopupMenu" anchor="last"/>
</action>
Create Icon Class:
public class ExampleIcons {
@NotNull
private static Icon load(@NotNull String iconPath) {
return IconLoader.getIcon(iconPath, ExampleIcons.class);
}
public static final Icon EXAMPLE_16 = load("/icons/example_16.svg");
}
Add Icon Resources:
src/main/resources/icons/Add Messages:
messages.properties (English):
action.example.title=Example Action
action.example.description=Execute example action
error.no.file=No file found
messages_zh_CN.properties (Chinese):
action.example.title=示例操作
action.example.description=执行示例操作
error.no.file=未找到文件
Use in Code:
String message = ExampleBundle.message("action.example.title");
Create SettingsState:
@State(
name = "ExamplePluginSettings",
storages = @Storage("example-settings.xml")
)
public class SettingsState implements PersistentStateComponent<SettingsState> {
public AIProviderConfig providerConfig;
public boolean showAdvancedSettings = false;
public String systemPrompt = getDefaultSystemPrompt();
public String exampleTemplate = getDefaultExampleTemplate();
public static SettingsState getInstance() {
return ApplicationManager.getApplication().getService(SettingsState.class);
}
}
Create Settings Panel:
public class ExampleSettingsPanel {
private JComboBox<AIProviderConfig> providerComboBox;
private JBTextArea systemPromptTextArea;
// Create AI provider selection panel
private JPanel createAIProviderSelectionPanel() {
List<AIProviderConfig> providers = getAiProviderTypes();
// Build UI with FormBuilder
}
}
Register in plugin.xml:
<applicationService serviceImplementation="your.package.settings.SettingsState"/>
<applicationConfigurable
parentId="tools"
instance="your.package.settings.ExampleSettingsConfigurable"
id="your.package.settings.ExampleSettingsConfigurable"
displayName="Your Plugin"/>
Standard Plugin (build.gradle.kts):
dependencies {
intellijPlatform {
create(providers.gradleProperty("platformType"),
providers.gradleProperty("platformVersion"))
bundledPlugin("com.intellij.java")
// No AI Engine dependency
}
}
AI-Integrated Plugin (build.gradle.kts):
dependencies {
intellijPlatform {
// ... same as standard
// plugin("dev.dong4j.zeka.stack.idea.plugin.common.ai") // Uncomment for marketplace
}
compileOnly("dev.dong4j.zeka.stack:intelli-ai-engine:1.1.0")
}
tasks {
// Add buildAiCommonPlugin and copyAiCommonPlugin tasks
// for local development
}
Build plugin:
./gradlew buildPlugin
Run in sandbox:
./gradlew runIde
Verify:
Package Structure:
action/ - User actionsicons/ - Icon managementsettings/ - Settings (AI-integrated only)util/ - Utilities (Bundle, Notification)Naming Conventions:
*Action.java*SettingsState.java, *SettingsConfigurable.java, *SettingsPanel.java*Icons.java*Bundle.javaUse IntelliJ UI Components:
JBLabel, JBTextField, JBCheckBox (not JLabel, JTextField)FormBuilder for layoutsToolbarDecorator for tablesJBTable for data tablesSettings Page:
FormBuilder for consistent layoutJBTabbedPane for multiple prompt templatesAlways use Bundle:
ExampleBundle.message(key, params...)Key Naming:
action.* - Action labelssettings.* - Settings labelserror.* - Error messagessuccess.* - Success messagesPersistent State:
@State annotationPersistentStateComponentSettings UI:
Configurable or SearchableConfigurableisModified() before savereset() method// Success
NotificationUtil.showInfo(project, ExampleBundle.message("success.action.executed"));
// Error
NotificationUtil.showError(project, ExampleBundle.message("error.no.file"));
// Warning
NotificationUtil.showWarning(project, ExampleBundle.message("warning.message"));
@Override
public void update(@NotNull AnActionEvent e) {
Project project = e.getProject();
PsiFile file = e.getData(CommonDataKeys.PSI_FILE);
e.getPresentation().setEnabled(project != null && file != null);
}
@Override
public void apply() throws ConfigurationException {
if (!validateSettings()) {
throw new ConfigurationException("Invalid settings");
}
settingsPanel.apply(settings);
}
| Feature | Standard Plugin | AI-Integrated Plugin |
|---|---|---|
| AI Engine Dependency | ❌ No | ✅ Yes (compileOnly) |
| Settings Page | ❌ No | ✅ Yes |
| AI Provider Selection | ❌ No | ✅ Yes |
| Prompt Templates | ❌ No | ✅ Yes |
| Build Tasks | Basic | + buildAiCommonPlugin, copyAiCommonPlugin |
| plugin.xml | Actions only | + SettingsState, SettingsConfigurable |
plugin.xml syntax@State annotationgetState() and loadState() methodspublicAIProviderSettings.getInstance().getVerifiedProviders()/icons/IconLoader.getIcon() path is correcttemplate-without-ai/ and template-with-ai/intelli-ai-engine/ projectintelli-ai-changelog/, intelli-ai-javadoc/template-without-ai to your projectgradle.properties with your plugin infoexample to your packageaction/ packagetemplate-with-ai to your projectAIService.getInstance() to call AI