Back to Kilocode

JetBrains Context Settings Page

.kilo/plans/jetbrains-context-settings-page.md

7.4.1316.0 KB
Original Source

JetBrains Context Settings Page

Implement the Tier 1 Context settings from docs/jetbrains-vscode-settings-parity.md in the JetBrains plugin. This is a pure kilo.json settings UI: no CLI feature work, no SDK regen, and no session-rendering changes.

Goal

Add a new JetBrains settings page under Settings -> Tools -> Kilo Code -> Context for:

SettingConfig keyType
Auto-compactioncompaction.autoboolean
Compaction threshold percentcompaction.threshold_percentnumber or null
Prune on compactioncompaction.pruneboolean
Watcher ignore patternswatcher.ignorestring array

Do not include VS Code Context-tab memory/indexing controls in this first pass. JetBrains does not have the equivalent memory/indexing settings service yet, and the parity doc excludes indexing from easy wins.

Do not put snapshot on this page unless product explicitly decides to combine Context and Checkpoints. The parity doc suggests snapshot belongs on a new Checkpoints page.

Context Verified

  • Source parity doc: docs/jetbrains-vscode-settings-parity.md.
  • JetBrains settings guidance: packages/kilo-jetbrains/AGENTS.md, especially Settings UI.
  • Existing settings pages are registered in packages/kilo-jetbrains/frontend/src/main/resources/kilo.jetbrains.frontend.xml.
  • Existing page pattern to mirror:
    • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/settings/models/ModelsConfigurable.kt
    • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/settings/models/ModelsSettingsUi.kt
    • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/settings/models/ModelsSettingsState.kt
  • Existing global config write path is sufficient once DTO/parser support is added:
    • Frontend: KiloAppService.updateConfigAsync(...)
    • RPC: KiloAppRpcApi.updateConfig(patch: ConfigPatchDto)
    • Backend: KiloBackendAppService.updateConfig(...)
    • HTTP: PATCH /global/config, then GET /global/config
  • Existing backend parser currently only serializes selected string keys from ConfigPatchDto.values; Context needs typed booleans, numbers, explicit null, and string arrays.

Decisions

  • Use global config for the first implementation, matching the existing app-level settings write path.
  • Add typed DTO fields instead of overloading ConfigPatchDto.values for non-string values.
  • Use an explicit clear list for nullable compaction fields, because Double? cannot distinguish absent from explicit null.
  • Reuse BaseSettingsUi, DraftReadyConfigurable, SettingsDraftState, SettingsRows, SettingsRow, and SettingsToggle.
  • Use the shared settings list primitives for watcher.ignore; do not build a bespoke add/remove list if SettingsListPanel or adjacent list primitives fit.
  • Keep all UI strings in KiloBundle.properties. Let other locale bundles fall back unless the repo's resource-bundle checks require duplicated English keys.

Part A - Shared DTOs

File: packages/kilo-jetbrains/shared/src/main/kotlin/ai/kilocode/rpc/dto/KiloAppStateDto.kt

Add config read DTOs:

kotlin
@Serializable
data class WatcherConfigDto(
    val ignore: List<String> = emptyList(),
)

@Serializable
data class CompactionConfigDto(
    val auto: Boolean? = null,
    val threshold_percent: Double? = null,
    val prune: Boolean? = null,
)

Extend ConfigDto:

kotlin
val watcher: WatcherConfigDto? = null,
val compaction: CompactionConfigDto? = null,

Add patch DTOs:

kotlin
@Serializable
data class WatcherPatchDto(
    val ignore: List<String>? = null,
)

@Serializable
data class CompactionPatchDto(
    val clear: List<String> = emptyList(),
    val auto: Boolean? = null,
    val threshold_percent: Double? = null,
    val prune: Boolean? = null,
)

Extend ConfigPatchDto:

kotlin
val watcher: WatcherPatchDto? = null,
val compaction: CompactionPatchDto? = null,

Notes:

  • watcher.ignore = null means no change.
  • watcher.ignore = emptyList() means explicitly save an empty list.
  • compaction.threshold_percent = null alone means no change.
  • compaction.clear = listOf("threshold_percent") means emit JSON "threshold_percent": null.
  • false boolean values must be serialized; do not treat false as absent.

Part B - Backend Config Parser And Serializer

File: packages/kilo-jetbrains/backend/src/main/kotlin/ai/kilocode/backend/cli/KiloCliDataParser.kt

Parse

Extend parseConfig(raw) to read:

  • watcher.ignore
  • compaction.auto
  • compaction.threshold_percent
  • compaction.prune

Add private helpers near parseSkillsConfig / parseMcpConfig:

kotlin
private fun parseWatcherConfig(obj: JsonObject?): WatcherConfigDto?
private fun parseCompactionConfig(obj: JsonObject?): CompactionConfigDto?

Use existing helper style:

  • strings: str(...)
  • booleans: flagOrNull(...)
  • numbers: num(...)
  • arrays: arr()?.mapNotNull { it.jsonPrimitive.contentOrNull }

Serialize

Extend buildConfigPatch(patch) to emit typed context patches:

json
{
  "watcher": {
    "ignore": ["**/node_modules/**"]
  },
  "compaction": {
    "auto": true,
    "threshold_percent": 80,
    "prune": false
  }
}

For explicit threshold clearing:

json
{
  "compaction": {
    "threshold_percent": null
  }
}

Keep the existing values allowlist for string model keys. Do not pass Context values through values.

Part C - Frontend State Model

Add package: packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/settings/context/

New file: ContextSettingsState.kt

Define:

kotlin
internal data class ContextDraft(
    val auto: Boolean? = null,
    val threshold: String = "",
    val prune: Boolean? = null,
    val ignore: List<String> = emptyList(),
)

Use a string for the threshold draft so the UI can represent blank/invalid intermediate input without losing user text. Convert only when building a patch.

Functions to add:

  • contextDraft(config: ConfigDto?): ContextDraft
  • patch(from: ContextDraft, to: ContextDraft): ConfigPatchDto
  • savedMatches(base: ContextDraft, draft: ContextDraft): Boolean
  • threshold(value: String): Double? or equivalent parsing helper
  • validation helper for threshold range if desired

Patch behavior:

  • Only emit changed fields.
  • Emit CompactionPatchDto(auto = false) when the user turns auto-compaction off.
  • Emit CompactionPatchDto(prune = false) when the user turns pruning off.
  • Emit CompactionPatchDto(threshold_percent = 80.0) for a non-blank valid number.
  • Emit CompactionPatchDto(clear = listOf("threshold_percent")) when an existing threshold is cleared.
  • Emit WatcherPatchDto(ignore = emptyList()) when the last ignore pattern is removed.
  • Return no change from the page when all fields match the baseline.

Part D - Frontend UI Page

New file: ContextConfigurable.kt

Mirror ModelsConfigurable:

  • Extend DraftReadyConfigurable<JComponent>.
  • ID = "ai.kilocode.jetbrains.settings.context".
  • getDisplayName() returns KiloBundle.message("settings.context.displayName").
  • create(cs) returns ContextSettingsUi(cs).

New file: ContextSettingsUi.kt

Mirror the simple parts of ModelsSettingsUi:

  • Extend BaseSettingsUi<ContextSettingsContent, ContextDraft, ConfigPatchDto, KiloAppStateDto, Unit>.
  • Initial draft is ContextDraft().
  • save(change, done) calls app.updateConfigAsync(change, done).
  • base(result) and draft(state) call contextDraft(state.config).
  • saved(base, draft) calls savedMatches(base, draft).
  • pendingText() uses settings.context.save.pending.
  • failedText() uses settings.context.save.failed.
  • loadWorkspace(root) returns Unit; applyWorkspace(result) is Unit.
  • models(state) is Unit.
  • syncContent() updates enabled states, field values, save/progress overlay, and validation messaging.

New content class: ContextSettingsContent

Suggested layout:

  • Section settings.context.compaction.title
    • Toggle row settings.context.compaction.auto.title
    • Numeric row settings.context.compaction.threshold.title
    • Toggle row settings.context.compaction.prune.title
  • Section settings.context.watcher.title
    • List editor row/panel for ignore patterns

Controls:

  • Use SettingsToggle for booleans.
  • Use JBTextField or a small reusable numeric field pattern based on AgentEditDialog for threshold.
  • Use shared list primitives (SettingsListPanel / SettingsListView / SettingsListItem / SettingsListCell) for watcher.ignore where practical.
  • Keep the page editable while app status is ready and no save is pending.
  • Disable controls while saving.

Validation:

  • Blank threshold is valid and means clear/reset the config value if it differs from baseline.
  • Non-numeric threshold is invalid and should prevent apply() from sending a patch.
  • Suggested accepted range is 0..100; if existing CLI allows a broader range, follow CLI behavior.
  • Show validation through existing settings messaging rather than custom ad hoc labels.

Part E - Settings Registration And Root Navigation

File: packages/kilo-jetbrains/frontend/src/main/resources/kilo.jetbrains.frontend.xml

Add a child configurable:

xml
<applicationConfigurable
        parentId="ai.kilocode.jetbrains.settings"
        id="ai.kilocode.jetbrains.settings.context"
        groupWeight="3"
        instance="ai.kilocode.client.settings.context.ContextConfigurable"
        bundle="messages.KiloBundle"
        key="settings.context.displayName"/>

Adjust weights so the desired order is stable. Recommended order:

PageWeight
User Profile5
Models4
Context3
Providers2
Agent Behavior1

File: packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/settings/KiloSettingsConfigurable.kt

Add a root-page ActionLink for Context between Models and Providers:

  • Import ContextConfigurable.
  • Link text: settings.context.displayName.
  • Link target: ContextConfigurable.ID.

KiloSettingsSelection.kt probably needs no code changes because child IDs already share the root prefix.

Part F - Strings

File: packages/kilo-jetbrains/frontend/src/main/resources/messages/KiloBundle.properties

Add base strings near the other settings strings:

properties
settings.context.displayName=Context
settings.context.description=Configure compaction and file-watcher context behavior.
settings.context.save.pending=Saving context settings...
settings.context.save.failed=Failed to save context settings
settings.context.compaction.title=Compaction
settings.context.compaction.description=Control when Kilo summarizes long sessions to reduce context usage.
settings.context.compaction.auto.title=Auto-compaction
settings.context.compaction.auto.description=Automatically compact long conversations before they exceed the model context window.
settings.context.compaction.threshold.title=Compaction threshold
settings.context.compaction.threshold.description=Percent of the context window to use before auto-compaction starts. Leave blank to use the default.
settings.context.compaction.threshold.invalid=Enter a number from 0 to 100, or leave the field blank.
settings.context.compaction.prune.title=Prune on compaction
settings.context.compaction.prune.description=Drop older raw conversation details after compaction to keep the session context smaller.
settings.context.watcher.title=Watcher ignore patterns
settings.context.watcher.description=Glob patterns Kilo should ignore when watching repository file changes.
settings.context.watcher.add=Add pattern
settings.context.watcher.empty=No ignore patterns configured.
settings.context.watcher.placeholder=e.g. **/dist/**
settings.context.watcher.remove=Remove {0}

If resource-bundle tests require every key in every locale bundle, copy English values into the localized bundles and leave translation work for a later i18n pass.

Part G - Test Updates

Frontend state tests

Add: packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/settings/context/ContextSettingsStateTest.kt

Cover:

  • Draft reads ConfigDto.watcher and ConfigDto.compaction.
  • Unchanged draft emits no patch.
  • Boolean changes emit false and true correctly.
  • Threshold set emits threshold_percent.
  • Threshold clear emits clear = listOf("threshold_percent").
  • Watcher list add/remove emits the whole new ignore list, including empty list.
  • Invalid threshold is rejected before save if validation lives in state helpers.

Frontend UI tests

Add: packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/settings/context/ContextSettingsUiTest.kt

Use ModelsSettingsUiTest as the main pattern:

  • BasePlatformTestCase.
  • Real EDT.
  • FakeAppRpcApi.
  • KiloAppService.
  • flushUntil helpers.
  • Assert rpc.configPatches after user interaction.
  • Assert controls disable during pending save.
  • Assert failed save leaves page modified and shows settings.context.save.failed.

Update FakeAppRpcApi:

  • File: packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/testing/FakeAppRpcApi.kt
  • Apply patch.watcher and patch.compaction to fake config state.
  • Preserve explicit empty lists.
  • Preserve boolean false.
  • Honor compaction.clear by setting cleared fields to null.

Backend parser tests

Update: packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/cli/KiloCliDataParserTest.kt

Add exact JSON tests for:

  • parseConfig reads watcher and compaction fields.
  • buildConfigPatch emits watcher ignore arrays.
  • buildConfigPatch emits auto=false and prune=false.
  • buildConfigPatch emits numeric threshold_percent.
  • buildConfigPatch emits explicit threshold_percent:null when clear includes the field.

Backend app service tests

Update: packages/kilo-jetbrains/backend/src/test/kotlin/ai/kilocode/backend/app/KiloBackendAppServiceTest.kt

Add a test similar to the existing model config update test:

  • Call updateConfig(ConfigPatchDto(watcher = ..., compaction = ...)).
  • Assert MockCliServer.lastConfigPatchBody exactly matches the expected nested JSON.
  • Assert the returned/reloaded ConfigDto includes the saved Context values.

Root settings tests

Update: packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/settings/KiloSettingsConfigurableTest.kt

Add:

  • ContextConfigurable.ID == "ai.kilocode.jetbrains.settings.context".
  • Root page includes a Context link.
  • Link order matches XML order.

Validation

Run from packages/kilo-jetbrains/:

bash
./gradlew typecheck
./gradlew test

Focused checks while iterating:

bash
./gradlew :shared:test --tests '*ContextSettingsStateTest'
./gradlew :frontend:test --tests '*ContextSettingsUiTest'
./gradlew :backend:test --tests '*KiloCliDataParserTest'
./gradlew :backend:test --tests '*KiloBackendAppServiceTest'

If the exact Gradle module test selectors differ, run the package-level ./gradlew test before marking the implementation ready.

Manual verification:

  1. Run ./gradlew runIde from packages/kilo-jetbrains/.
  2. Open Settings -> Tools -> Kilo Code -> Context.
  3. Toggle auto-compaction and prune.
  4. Set threshold to a number, apply, reopen settings, and verify it persists.
  5. Clear threshold, apply, reopen settings, and verify it resets.
  6. Add and remove watcher ignore patterns, apply, reopen settings, and verify the list persists.
  7. Inspect the global Kilo config file through the existing Open: global ... action if needed.

Risks And Follow-ups

  • Global vs project-local config: this plan uses the existing global config write path. Project-local Context settings would need new workspace config RPC plumbing.
  • Threshold null semantics: implement explicit clear handling; otherwise clearing the field will silently do nothing.
  • String-array UI: reuse list primitives even if it takes a small adapter type; avoid one-off list widgets.
  • VS Code memory/indexing parity: defer because it is not pure config and is excluded by the easy-win criteria.
  • Checkpoints page: implement snapshot separately unless product asks to combine it with Context.
  • Changeset: when implementing this user-facing JetBrains settings feature, add a patch changeset for kilo-code/JetBrains according to repo release guidance.