diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 53d08204098..61ee8f2e57e 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -126,9 +126,11 @@ Requires Java 21 (see [Prerequisites](#prerequisites)). From `packages/kilo-jetb
```bash
./gradlew typecheck # Compile-check all Kotlin sources
./gradlew test # Run all tests (backend + frontend)
-./gradlew runIde # Launch sandboxed IntelliJ with the plugin
+./gradlew --no-configuration-cache runIdeSplitMode # Launch local split-mode sandbox and prepare the CLI
```
+Use `./gradlew runIde` only for a monolithic sandbox; prepare the CLI first with `bun run build --prepare-cli`.
+
Or via the root turbo filter to run only JetBrains checks from the repo root:
```bash
diff --git a/packages/kilo-docs/pages/contributing/architecture/jetbrains-plugin.md b/packages/kilo-docs/pages/contributing/architecture/jetbrains-plugin.md
index d54224b8f8a..bbfa42efc4d 100644
--- a/packages/kilo-docs/pages/contributing/architecture/jetbrains-plugin.md
+++ b/packages/kilo-docs/pages/contributing/architecture/jetbrains-plugin.md
@@ -124,7 +124,7 @@ Split mode changes path and UI assumptions:
## Development checks
-JetBrains Kotlin toolchain is Java 21. Check `java -version` before Gradle verification.
+JetBrains Kotlin toolchain is Java 21. Gradle commands report missing or incompatible Java clearly; check Java only when diagnosing that failure mode.
| Check | Command from `packages/kilo-jetbrains/` |
|---|---|
@@ -132,9 +132,9 @@ JetBrains Kotlin toolchain is Java 21. Check `java -version` before Gradle verif
| Tests | `./gradlew test` |
| Full plugin build | `bun run build` |
| Gradle plugin assembly with prepared CLI binaries | `./gradlew buildPlugin` |
-| Sandbox IDE | `./gradlew runIde` |
-| Split backend sandbox | `./gradlew runIdeBackend` |
-| Split-mode run configs | `./gradlew generateSplitModeRunConfigurations` |
+| Split-mode sandbox | `./gradlew --no-configuration-cache runIdeSplitMode` |
+| Split backend sandbox | `./gradlew --no-configuration-cache runIdeBackend` |
+| Monolithic sandbox IDE | `./gradlew runIde` after `bun run build --prepare-cli` |
Run `Plugin DevKit | Code | Frontend and Backend API Usage` inspection when moving code across split boundary.
diff --git a/packages/kilo-jetbrains/.run/Run IDE (Backend).run.xml b/packages/kilo-jetbrains/.run/Run IDE (Backend).run.xml
index 84c1fe34e03..cfa3d9997d4 100644
--- a/packages/kilo-jetbrains/.run/Run IDE (Backend).run.xml
+++ b/packages/kilo-jetbrains/.run/Run IDE (Backend).run.xml
@@ -5,7 +5,7 @@
-
+
diff --git a/packages/kilo-jetbrains/.run/Run IDE (Frontend).run.xml b/packages/kilo-jetbrains/.run/Run IDE (Frontend).run.xml
index 9613fd9791f..337d1e72f31 100644
--- a/packages/kilo-jetbrains/.run/Run IDE (Frontend).run.xml
+++ b/packages/kilo-jetbrains/.run/Run IDE (Frontend).run.xml
@@ -5,7 +5,7 @@
-
+
diff --git a/packages/kilo-jetbrains/.run/runIdeSplitMode.run.xml b/packages/kilo-jetbrains/.run/runIdeSplitMode.run.xml
index 3fd81ac0533..58cae943e2e 100644
--- a/packages/kilo-jetbrains/.run/runIdeSplitMode.run.xml
+++ b/packages/kilo-jetbrains/.run/runIdeSplitMode.run.xml
@@ -1,7 +1,29 @@
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ false
+ false
+ false
+ false
+ false
diff --git a/packages/kilo-jetbrains/AGENTS.md b/packages/kilo-jetbrains/AGENTS.md
index fb38dd51ad6..57e27724e28 100644
--- a/packages/kilo-jetbrains/AGENTS.md
+++ b/packages/kilo-jetbrains/AGENTS.md
@@ -171,8 +171,8 @@ For blocking I/O in coroutines, move the dispatcher switch inside the callee usi
### Dev Storage Isolation
-- In development (`runIdeBackend` / `runIde`), the Gradle property `kilo.dev.storage.isolated=true` makes the backend set `XDG_DATA_HOME`, `XDG_CONFIG_HOME`, `XDG_STATE_HOME`, and `XDG_CACHE_HOME` to `/.kilo-dev/{data,config,state,cache}` before spawning the CLI. The worktree root comes from the `kilo.dev.worktree.root` JVM system property (auto-set by Gradle from the project directory).
-- The checked-in `Run IDE (Backend)` run configuration enables isolation by default (`-Pkilo.dev.storage.isolated=true`). Developers can disable it by passing `-Pkilo.dev.storage.isolated=false`.
+- In development (`runIdeSplitMode`, `runIdeBackend`, `runIdeFrontend`, or `runIde`), the Gradle property `kilo.dev.storage.isolated=true` makes the backend set `XDG_DATA_HOME`, `XDG_CONFIG_HOME`, `XDG_STATE_HOME`, and `XDG_CACHE_HOME` to `/.kilo-dev/{data,config,state,cache}` before spawning the CLI. The worktree root comes from the `kilo.dev.worktree.root` JVM system property (auto-set by Gradle from the project directory).
+- The checked-in `Run IDE (Backend)`, `Run IDE (Frontend)`, and `Run IDE (Split Mode)` run configurations enable isolation by default (`-Pkilo.dev.storage.isolated=true`). Developers can disable it by passing `-Pkilo.dev.storage.isolated=false`.
- Use standard `XDG_*_HOME` env vars for this isolation. Do not introduce custom `KILO_DATA_DIR`, `KILO_GLOBAL_CONFIG_DIR`, `KILO_STATE_DIR`, or `KILO_CACHE_DIR` env vars — the CLI core already respects `XDG_*_HOME` via `xdg-basedir`.
- The `.kilo-dev/` directory is gitignored and created automatically on first run.
- The implementation lives in `KiloBackendCliManager.buildEnv()` / `devStorageEnv()`. Tests: `KiloBackendCliManagerEnvTest`.
@@ -194,9 +194,9 @@ For blocking I/O in coroutines, move the dispatcher switch inside the callee usi
- **Gradle only**: `./gradlew buildPlugin` from `packages/kilo-jetbrains/` (requires CLI binaries already present in `backend/build/generated/cli/`; run `bun run build --prepare-cli` first).
- **Java checks**: Do not run `java -version` as a routine preflight. Gradle commands already fail clearly when Java is missing or incompatible; check Java only when diagnosing that failure mode.
- **Via Turbo**: `bun turbo build --filter=@kilocode/kilo-jetbrains` from repo root.
-- **Run in sandbox**: `./gradlew runIde` — launches sandboxed IntelliJ with the plugin. Does NOT build CLI binaries.
-- **Run split backend**: `./gradlew runIdeBackend` — if it exits shortly after startup, check for an orphaned Java process from a previous backend run and kill it before restarting.
-- **Test split mode**: `./gradlew generateSplitModeRunConfigurations` creates a "Run IDE (Split Mode)" config that starts both frontend and backend processes locally. Emulate latency via the Split Mode widget (requires internal mode: `-Didea.is.internal=true`).
+- **Run split mode**: `./gradlew --no-configuration-cache runIdeSplitMode` or the checked-in `Run IDE (Split Mode)` configuration — launches backend and frontend locally and prepares the local-platform CLI binary automatically. Emulate latency via the Split Mode widget (requires internal mode: `-Didea.is.internal=true`).
+- **Run split backend**: `./gradlew --no-configuration-cache runIdeBackend` — prepares the local-platform CLI binary automatically; if it exits shortly after startup, check for an orphaned Java process from a previous backend run and kill it before restarting.
+- **Run in monolithic sandbox**: `./gradlew runIde` — launches sandboxed IntelliJ with the plugin. Does NOT build CLI binaries.
### CLI/SDK Change Awareness
diff --git a/packages/kilo-jetbrains/README.md b/packages/kilo-jetbrains/README.md
index 2d704f9fee5..78978d66337 100644
--- a/packages/kilo-jetbrains/README.md
+++ b/packages/kilo-jetbrains/README.md
@@ -84,31 +84,34 @@ See [RELEASING.md](RELEASING.md) for the full release process, including how to
## Run the plugin
-Use the `runIde` Gradle task (available in the Gradle tool window or via `./gradlew runIde` from `packages/kilo-jetbrains/`) to launch a sandboxed IntelliJ instance with the plugin installed.
+Use the checked-in `Run IDE (Split Mode)` run configuration (or `./gradlew --no-configuration-cache runIdeSplitMode` from `packages/kilo-jetbrains/`) to launch the backend and frontend halves of a local split-mode sandbox. The task prepares the local-platform CLI binary automatically when `backend/build/generated/cli/cli/` does not contain the expected binary.
-`runIde` does not prepare the CLI binary automatically. Run `bun run build --prepare-cli` from `packages/kilo-jetbrains/` first to copy the local-platform binary into `backend/build/generated/cli/cli/`.
+Use `runIde` only when you need a monolithic sandboxed IntelliJ instance. `runIde` does not prepare the CLI binary automatically, so run `bun run build --prepare-cli` from `packages/kilo-jetbrains/` first to copy the local-platform binary into `backend/build/generated/cli/cli/`.
Production packaging still requires running `bun run build:production` so all platform binaries are present.
### Run the split backend
-Use the checked-in `Run IDE (Backend)` run configuration (or `./gradlew runIdeBackend`) to launch just the backend half of a split-mode session. It prepares the local-platform CLI binary automatically when `backend/build/generated/cli/cli/` does not contain the expected binary.
+Use the checked-in `Run IDE (Backend)` run configuration (or `./gradlew --no-configuration-cache runIdeBackend`) to launch just the backend half of a split-mode session. It prepares the local-platform CLI binary automatically when `backend/build/generated/cli/cli/` does not contain the expected binary.
If `Run IDE (Backend)` exits shortly after startup, check for an orphaned Java process from a previous backend run and kill it before restarting the backend.
-Use `Run IDE (Split Mode)` to launch both halves at once (composes `Run IDE (Backend)` + `Run IDE (Frontend)`).
+Use `Run IDE (Frontend)` (or `./gradlew --no-configuration-cache runIdeFrontend`) with a running backend when you need frontend JVM debugging; `Run IDE (Split Mode)` launches the frontend itself and does not attach frontend debugging.
-### Backend Gradle properties
+### Development Gradle properties
All properties below are passed with `-P` on the Gradle command line or in the run configuration's script parameters field.
| Property | Default | Description |
|---|---|---|
-| `kilo.splitModeServerPort` | random high port | Backend split-mode server port. `0` or omitted picks a random port from 49152-65535. |
-| `kilo.dev.storage.isolated` | `false` | When `true`, CLI runs with `XDG_*_HOME` pointing to `.kilo-dev/` in the worktree root, fully isolating dev storage from your real Kilo installation. Enabled by default in `Run IDE (Backend)`. |
+| `kilo.splitModeServerPort` | `0` | Backend split-mode server port. `0` or omitted lets the IntelliJ Platform Gradle Plugin pick a free port when the task runs. |
+| `kilo.dev.storage.isolated` | `false` | When `true`, CLI runs with `XDG_*_HOME` pointing to `.kilo-dev/` in the worktree root, fully isolating dev storage from your real Kilo installation. Enabled by default in the checked-in split-mode run configurations. |
| `kilo.dev.worktree.root` | monorepo root | Worktree root used to resolve `.kilo-dev/`. Auto-detected from the Gradle project directory; override only when the auto-detection is wrong. |
| `kilo.bun.path` | `bun` on `$PATH` | Absolute path to Bun. Set this when IntelliJ-launched Gradle cannot find Bun automatically. |
+The checked-in IDE run configurations pass `--no-configuration-cache` because the IntelliJ Platform Gradle Plugin run-IDE tasks are not configuration-cache compatible in this setup.
+They also pass `--purge-old-log-directories` so stale sandbox logs do not hide the current backend and frontend `kilo-dev.log` files.
+
Example with a fixed split-mode port:
```text
@@ -129,7 +132,7 @@ When `kilo.dev.storage.isolated=true`, the CLI subprocess receives standard `XDG
This keeps all development data isolated from your real Kilo installation. The `.kilo-dev/` directory is gitignored and created automatically on first run.
-The `Run IDE (Backend)` run configuration enables this by default. To disable it:
+The checked-in `Run IDE (Backend)`, `Run IDE (Frontend)`, and `Run IDE (Split Mode)` run configurations enable this by default. To disable it:
```text
-Pkilo.dev.storage.isolated=false
@@ -139,7 +142,7 @@ The `Run IDE (Backend)` run configuration enables this by default. To disable it
### Debug logging properties
-The plugin supports a few JVM system properties for local debugging. These are most useful with `runIde` in sandbox mode because the logs are mirrored to `kilo-dev.log` files for frontend and backend.
+The plugin supports a few JVM system properties for local debugging. These are most useful with sandbox runs because the logs are mirrored to `kilo-dev.log` files for frontend and backend.
`kilo.dev.log.level`
@@ -164,7 +167,7 @@ The plugin supports a few JVM system properties for local debugging. These are m
Where to find the log files:
-- In sandbox `runIde` runs, Kilo writes separate dev log files for each side under the IDE sandbox log directory reported by `PathManager.getLogDir()`.
+- In sandbox runs, Kilo writes separate dev log files for each side under the IDE sandbox log directory reported by `PathManager.getLogDir()`.
- Frontend log file: `/kilo-frontend/kilo-dev.log`
- Backend log file: `/kilo-backend/kilo-dev.log`
- In practice these sit under the current `log_run*` sandbox logs for the active run.
diff --git a/packages/kilo-jetbrains/build.gradle.kts b/packages/kilo-jetbrains/build.gradle.kts
index 890853a9c22..50c07ca0044 100644
--- a/packages/kilo-jetbrains/build.gradle.kts
+++ b/packages/kilo-jetbrains/build.gradle.kts
@@ -3,26 +3,21 @@ import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType
import org.jetbrains.intellij.platform.gradle.TestFrameworkType
import org.jetbrains.intellij.platform.gradle.tasks.InstrumentCodeTask
import org.jetbrains.intellij.platform.gradle.tasks.RunIdeTask
-import org.jetbrains.intellij.platform.gradle.tasks.aware.SplitModeAware.SplitModeTarget
+import org.jetbrains.intellij.platform.gradle.tasks.aware.SplitModeAware.PluginInstallationTarget
import java.time.LocalDate
group = "ai.kilocode.jetbrains"
-val ports = 49152..65535
-
-fun fallback(): Int {
- return ports.random()
-}
-
fun port(value: String): Int {
val text = value.trim()
- if (text.isEmpty()) return fallback()
+ require(text.isNotEmpty()) {
+ "kilo.splitModeServerPort must be an integer from 0 to 65535; use 0 or omit it for a random port"
+ }
val n = text.toIntOrNull()
- ?: error("kilo.splitModeServerPort must be an integer from 0 to 65535; use 0 or omit it for a random high port")
+ ?: error("kilo.splitModeServerPort must be an integer from 0 to 65535; use 0 or omit it for a random port")
require(n in 0..65535) {
- "kilo.splitModeServerPort must be an integer from 0 to 65535; use 0 or omit it for a random high port"
+ "kilo.splitModeServerPort must be an integer from 0 to 65535; use 0 or omit it for a random port"
}
- if (n == 0) return fallback()
return n
}
@@ -95,7 +90,7 @@ val ver = override?.let(::checked) ?: prop?.let(::checked) ?: if (release) check
) else checked(tag ?: "0.0.0-dev")
val channel = providers.gradleProperty("kilo.channel").map { it.trim() }.orElse("default")
-val splitPort = providers.gradleProperty("kilo.splitModeServerPort").orNull?.let(::port) ?: fallback()
+val splitPort = providers.gradleProperty("kilo.splitModeServerPort").map(::port).orElse(0)
val isolated = providers.gradleProperty("kilo.dev.storage.isolated").map { it.toBoolean() }.orElse(false)
val worktreeRoot = providers.gradleProperty("kilo.dev.worktree.root").orElse(
providers.provider { rootProject.layout.projectDirectory.asFile.parentFile.parentFile.canonicalPath }
@@ -180,7 +175,7 @@ dependencies {
intellijPlatform {
splitMode = true
- splitModeTarget = SplitModeTarget.BOTH
+ pluginInstallationTarget = PluginInstallationTarget.BOTH
pluginConfiguration {
id = "ai.kilocode.jetbrains"
@@ -229,6 +224,16 @@ tasks {
dependsOn(":backend:prepareLocalCli")
dependsOn(":backend:processResources")
}
+
+ runIdeFrontend {
+ splitModeServerPort.set(splitPort)
+ }
+
+ runIdeSplitMode {
+ splitModeServerPort.set(splitPort)
+ dependsOn(":backend:prepareLocalCli")
+ dependsOn(":backend:processResources")
+ }
}
project(":backend").tasks.named("processResources") {
diff --git a/packages/kilo-jetbrains/gradle/libs.versions.toml b/packages/kilo-jetbrains/gradle/libs.versions.toml
index dca51580893..2cfb8872e11 100644
--- a/packages/kilo-jetbrains/gradle/libs.versions.toml
+++ b/packages/kilo-jetbrains/gradle/libs.versions.toml
@@ -1,6 +1,6 @@
[versions]
intellij-platform = "2026.1"
-intellij-gradle-plugin = "2.16.1-20260623.221413-11"
+intellij-gradle-plugin = "2.17.0"
intellij-rpc-plugin = "2.3.20-RC2-0.1"
kotlin-jvm-plugin = "2.3.20"
kotlin-serialization-plugin = "2.3.20"
diff --git a/packages/kilo-jetbrains/settings.gradle.kts b/packages/kilo-jetbrains/settings.gradle.kts
index d18a5006659..c9b17f77c25 100644
--- a/packages/kilo-jetbrains/settings.gradle.kts
+++ b/packages/kilo-jetbrains/settings.gradle.kts
@@ -6,19 +6,7 @@ include("backend")
pluginManagement {
includeBuild("build-tasks")
- resolutionStrategy {
- eachPlugin {
- if (requested.id.id == "org.jetbrains.intellij.platform") {
- useModule("org.jetbrains.intellij.platform:intellij-platform-gradle-plugin:${requested.version}")
- }
- }
- }
repositories {
- maven("https://central.sonatype.com/repository/maven-snapshots/") {
- content {
- includeGroup("org.jetbrains.intellij.platform")
- }
- }
mavenCentral()
gradlePluginPortal()
maven("https://packages.jetbrains.team/maven/p/ij/intellij-dependencies/")