Skip to content

perf(jetbrains): speed up transcript tab switching and list painting - #14520

Merged
kirillk merged 3 commits into
mainfrom
perf/jetbrains-transcript-tab-switch
Sep 24, 2026
Merged

kirillk merged 3 commits into
mainfrom
perf/jetbrains-transcript-tab-switch

Conversation

@kirillk

@kirillk kirillk commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

Issue

No linked issue. Found via a user-provided JetBrains CPU profile (.jfr) of switching between worktree session editor tabs.

Context

A CPU profile of switching between JetBrains worktree editor tabs showed most of the cost came from Swing rebuilding the private HTML document of every <html>-text JLabel in the session transcript. Detaching or re-attaching a tab resets a component's graphics configuration, and the JDK's label code (BasicLabelUI.propertyChange → SwingUtilities2.isScaleChanged) treats that as a screen-scale change and reparses the label's HTML. Tool card headers, file links, to-do rows, and attachment chips all used <html> text just for single-line clipping and underline/strikethrough, so this was paid twice per switch and scaled with the number of tool calls in both the outgoing and incoming session.

Two smaller contributors from the same profile:

  • The Agent Manager list reuses one renderer component for every row and invalidates it wholesale before each paint, so nested Stack/Align layouts recomputed their sizes for every ancestor container on every row paint, row-height measurement, and hit test.
  • The list's running-session spinner repainted the entire list on every animation frame, regardless of how many rows were actually animating.

Implementation

  • Added PlainLabel (ui/PlainLabel.kt), a JBLabel that always renders its text literally — even text starting with <html> — and paints underline/strikethrough via font attributes instead of markup. Replaced every single-line transcript label that used <html> text (tool card title/subtitle/state, file links, to-do rows, attachment chips, task child rows, the approval footer, the edit card's files tag) with it. Removed the now-unused FileLinkText.kt and its HTML-wrapping helpers.
    • Trade-off: a plain label shortens overflowing text with "…" instead of the previous hard character cut.
  • Trimmed what every transcript card keeps attached, since every tab switch walks the whole tree:
    • The collapse/expand arrow now attaches to the header row only while the card can actually expand, instead of staying attached and hidden.
    • toolParts() takes a link flag; only Read/Edit cards build the file-link wrapper slot. Other tool cards (Tool, Shell, Board, Task, search) no longer carry a hidden FileLinkLabel + wrapper panel they never show.
    • TextView's copy-toolbar placeholder is added/removed from the layout instead of toggling isVisible, so only the one text part per assistant message that has a copy button carries it.
    • Each to-do row collapsed from three components (row panel + check label + text label) to one PlainLabel using the check mark as its icon.
  • Added LayoutPass (ui/layout/LayoutPass.kt): a scoped memo that Stack and Align consult so each container answers each kind of size (min/preferred/max) once per layout pass, keyed by the container's current size, and dropped as soon as Swing invalidates it. Wrapped the Agent Manager renderer's paint validate(), row-height measurement, and activeListLayout (hit-testing) in it. On a small test row this cut preferred-size reads from 132 to 26 for a full measure+layout pass.
  • Set AnimatedIcon.REFRESH_DELEGATE on the Agent Manager list so a spinner frame repaints only the visible rows that actually paint an animated glyph (including badges wearing a live-run dot), instead of the whole list. This relies on an experimental IntelliJ Platform API (@ApiStatus.Experimental), flagged per the repo's Platform API guidance.
  • Documented the new PlainLabel/LayoutPass patterns and the "don't keep rarely-shown header parts attached" rule in packages/kilo-jetbrains/AGENTS.md.

Screenshots / Video

N/A — no visible layout change other than long single-line labels ending in "…" instead of a hard cut when they overflow (pre-existing clipping behavior, same effective outcome).

How to Test

Manual/local verification

  • ./gradlew typecheck from packages/kilo-jetbrains/ — passes.
  • ./gradlew :frontend:test from packages/kilo-jetbrains/ — full suite (4,272 tests) passes.
  • bun run script/check-md-table-padding.ts — no padded tables.
  • Re-profiling the fix in a live IDE session was not performed by the agent; the performance analysis and expected improvement are derived from the original .jfr profile plus targeted before/after measurement tests (LayoutPassTest, ActiveListPaintCostTest) added in this PR, not a second live capture.

Reviewer test steps

  1. Open the JetBrains plugin against a worktree session with a long transcript (many tool calls, a to-do list, some file links).
  2. Confirm tool card headers, file links, and to-do items render identically to before (same text, same underline/strikethrough), just with "…" instead of a hard cut for long overflowing text.
  3. Switch between two worktree session editor tabs and confirm behavior is unchanged (collapse/expand still works, file links still open, copy button still appears on the latest assistant response).
  4. In the Agent Manager list, start a session so a row shows the running spinner; confirm only that row (and any other animating row) appears to repaint/animate, and the rest of the list is not repainted needlessly (e.g. via a CPU profile of ActiveListRenderer/RepaintManager).

Blocked checks and substitute verification

  • Live IDE CPU re-profiling of the tab-switch fix was not performed; substituted with the unit tests above (PlainLabelTest, LayoutPassTest, ActiveListPaintCostTest, plus the existing session-view suites updated for the PlainLabel/attachment changes) run via ./gradlew :frontend:test.

Checklist

  • Issue linked above, or exception explained
  • Tests/verification described
  • Screenshots/video included for visual changes, or marked N/A
  • Changeset considered for user-facing changes
  • I personally reviewed the diff and can explain the changes, including any AI-assisted work.

Get in Touch

A CPU profile of switching between JetBrains worktree editor tabs showed
most of the cost came from Swing rebuilding the private HTML document of
every `<html>` JLabel in the transcript. Detaching or re-attaching a tab
resets a component's graphics configuration, which the JDK label code
treats as a screen-scale change and reparses. Tool card headers, file
links, to-do rows, and attachment chips all used `<html>` text for
single-line clipping and underline/strikethrough, so this cost was paid
twice per switch and scaled with the number of tool calls in both
sessions.

- Add `PlainLabel`, a `JBLabel` that always renders text literally and
  paints underline/strikethrough via font attributes instead of markup,
  and use it for every single-line transcript label that previously used
  `<html>` text.
- Detach the collapse/expand arrow and the file link header slot from
  cards that never show them (most tool cards never show a link), rather
  than keeping them attached and hidden. Every tab switch walks the whole
  transcript tree, so idle-but-attached components still cost something.
- Attach the copy-toolbar placeholder in `TextView` only while the
  toolbar is shown, instead of hiding it under every text part.
- Collapse each to-do row from three components to one label using the
  check as its icon.

The Agent Manager list reuses one renderer component for every row and
invalidates it wholesale on each paint, so nested `Stack`/`Align` layouts
recomputed their sizes for every ancestor on every row. Add
`LayoutPass`, which memoizes each container's size per layout pass, and
wrap the renderer's paint validation, row-height measurement and
hit-testing in it. Also set `AnimatedIcon.REFRESH_DELEGATE` so a spinner
frame repaints only the rows actually showing an animated glyph instead
of the whole list.
@kilo-code-bot

kilo-code-bot Bot commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Reviewed the follow-up commit 8481a19d3d, which resolves the prior warning: the AnimatedIcon.REFRESH_DELEGATE install moved out of init into a new addNotify() override that is symmetric with the existing removeNotify() clear, reusing a single Runnable across attach/detach cycles. The added ActiveListPaintCostTest case asserts the delegate returns after a detach/re-attach. No new issues found on the changed lines.

Files Reviewed (2 files)
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/list/ActiveListView.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/ui/list/ActiveListPaintCostTest.kt
Previous Review Summaries (2 snapshots, latest commit 8e83b74)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 8e83b74)

Status: 1 Issue Found | Recommendation: Address before merge

Reviewed follow-up commit 8e83b74e40, which addresses the four prior suggestions. Three are correctly fixed: the PlainLabel decoration cache is now keyed on the resolved font size/style, LayoutPass.size/forget carry @RequiresEdt, and the activeListAnimated hot path no longer allocates a wrapper list per row. The ActiveListView delegate cleanup is incomplete — it clears the delegate on detach but never restores it (see finding).

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/list/ActiveListView.kt 252 REFRESH_DELEGATE is cleared on detach but never restored in an addNotify override, so a detach/re-attach (e.g. a worktree tab switch) drops the per-row animation repaint optimization for the rest of the view's life.
Files Reviewed (5 files)
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/PlainLabel.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/layout/LayoutPass.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/list/ActiveListModel.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/list/ActiveListView.kt - 1 issue
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/ui/PlainLabelTest.kt

Fix these issues in Kilo Cloud

Previous review (commit ceb83ea)

Status: 4 Issues Found | Recommendation: Address before merge

Reviewed the JetBrains perf change (34 files: PlainLabel, LayoutPass, ActiveList*, tool/todo/text views, tests, changeset). The design is sound and matches the repo's Swing guidelines; no correctness or blocking issues were confirmed. Findings are low-severity suggestions.

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 4
Issue Details (click to expand)

SUGGESTION

File Line Issue
packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/PlainLabel.kt 57 Decoration cache keyed by Font identity can go stale when a JBFont's size changes in place (IDE zoom), affecting strike/underline labels such as completed to-do rows.
packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/layout/LayoutPass.kt 29 Shared static memo is not thread-confined; size/forget lack @RequiresEdt. Latent, EDT-bound layout makes it unlikely.
packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/list/ActiveListView.kt 136 REFRESH_DELEGATE Runnable captures the view and is never cleared; no removeNotify/Disposable cleanup.
packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/list/ActiveListModel.kt 214 listOf(...) allocation runs per visible row on every animation frame — the hot path this PR targets.
Files Reviewed (34 files)
  • .changeset/jetbrains-faster-tab-switching.md
  • packages/kilo-jetbrains/AGENTS.md
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/ui/FileLinkText.kt (deleted)
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/ui/attachment/AttachmentCard.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/TextView.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/base/AbstractSessionPartView.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/todo/TodoListPanel.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/tool/BaseSearchToolView.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/tool/EditToolView.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/tool/ReadToolView.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/tool/ShellToolView.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/tool/TaskToolView.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/tool/ToolApprovalFooter.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/tool/ToolSupport.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/PlainLabel.kt - 1 issue
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/layout/Align.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/layout/LayoutPass.kt - 1 issue
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/layout/Stack.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/list/ActiveListModel.kt - 1 issue
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/list/ActiveListRenderer.kt
  • packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/list/ActiveListView.kt - 1 issue
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/ui/ModifiedFilesViewTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/ui/SessionUiUpdateTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/views/EditToolViewTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/views/PromptAttachmentViewTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/views/ReadToolViewTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/views/ShellToolViewTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/views/TextViewTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/views/ToolViewTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/views/base/AbstractSessionPartViewTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/session/views/todo/TodoWriteViewTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/ui/PlainLabelTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/ui/layout/LayoutPassTest.kt
  • packages/kilo-jetbrains/frontend/src/test/kotlin/ai/kilocode/client/ui/list/ActiveListPaintCostTest.kt

Fix these issues in Kilo Cloud


Reviewed by deepseek-v4.1-flash · Input: 0 · Output: 0 · Cached: 0

Review guidance: REVIEW.md from base branch main

- PlainLabel: key the underline/strikethrough decoration cache on the
  font's resolved size and style, not just object identity. JBFont is
  one instance whose getSize()/getStyle() resolve dynamically off the
  current IDE zoom (JBFont.refreshScaledFont mutates its own size/
  pointSize fields in place), so identity alone would keep painting a
  to-do row's strikethrough at its pre-zoom size forever.
- LayoutPass: annotate the internal size()/forget() helpers with
  @RequiresEdt. They mutate a shared IdentityHashMap reached from
  Swing's LayoutManager2 callbacks, which are EDT-bound; the annotation
  makes an off-EDT caller fail loud instead of racing the map.
- ActiveListView: clear the AnimatedIcon.REFRESH_DELEGATE client
  property on removeNotify() so the delegate (which closes over the
  view's model/renderer/items) doesn't outlive the view if the
  platform's animation registry retains it longer than expected.
- ActiveListModel: rewrite activeListAnimated() as direct any() checks
  instead of wrapping the three badge lists in a listOf(...) first,
  avoiding a per-row allocation on every animation frame.

Addresses the 4 suggestions from the automated review on PR #14520.
removeNotify() cleared AnimatedIcon.REFRESH_DELEGATE but nothing ever
put it back on the next addNotify(). A worktree session editor tab
switch detaches and re-attaches this exact view, so after the first
switch the delegate stayed null for the rest of the view's life and
the per-row animation repaint this PR introduced silently reverted to
repainting the whole list on every spinner frame.

Move the client property installation from init into a new addNotify()
override, symmetric with the existing removeNotify() clear, and reuse
one Runnable instance across attach/detach cycles instead of
allocating a fresh one each time.

Addresses the follow-up review finding on PR #14520 (commit 8e83b74).
@marius-kilocode

Copy link
Copy Markdown
Collaborator

Can we add before after time tables of real reproductions?

|---|---|
| Rich HTML with modern CSS, icons, shortcuts | `JBHtmlPane` (`com.intellij.ui.components.JBHtmlPane`) |
| Simple multi-line label with HTML | `JBLabel` + `XmlStringUtil.wrapInHtml()` |
| Single-line transcript text (tool headers, file links, to-do rows) | `PlainLabel` (`ai.kilocode.client.ui.PlainLabel`) with `underline`/`strike`; never `<html>` text, because Swing re-parses every HTML label each time an editor tab is detached or re-attached |

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This AGENTS.md file is getting too long. At this size you will greatly degrade model output quality with that. Would it make sense to extract certain parts to skills instead?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I's been working better and better for me in time but I think it makes sense to re-iterate on that. I planned to make a clean up day this week that would include checking for bad smells, code duplication, memory leaks and running the profiler. I think I will add this to the plan too, that makes sense.

@kirillk
kirillk merged commit cb4dafa into main Sep 24, 2026
24 of 25 checks passed
@kirillk
kirillk deleted the perf/jetbrains-transcript-tab-switch branch September 24, 2026 14:03
iscekic pushed a commit that referenced this pull request Sep 26, 2026
…4554)

## Automated docs sync — 2026-09-25

This PR keeps kilo.ai/docs in sync with features merged to [Kilo-Org/cloud](https://github.com/Kilo-Org/cloud) and [Kilo-Org/kilocode](https://github.com/Kilo-Org/kilocode). Every change below links to the merged PR it documents.

- Window: `2026-09-24T07:08:33.639Z` → `2026-09-25T07:05:29.302Z`
- Verification (docs build + tests): **passing**

### Surface: `cloud-mobile`

- Assignees / requested reviewers: @iscekic and @eshurakov
- Derivation: Derived from the repository layout. A product surface is a package under packages/ that ships a distinct client, plugin, backend, or hosted service: cli = packages/opencode/ + packages/tui/ + packages/server/ + packages/sdk/ + packages/plugin/; vscode = packages/kilo-vscode/ + packages/kilo-web-ui/ + packages/kilo-ui/; jetbrains = packages/kilo-jetbrains/; gateway = packages/kilo-gateway/; web = packages/kilo-console/ + packages/kilo-indexing/ + packages/kilo-memory/ + packages/kilo-sandbox/. Docs route from the IA tree packages/kilo-docs/pages/ plus docs/jetbrains-vscode-settings-parity.md: each surface lists the pages sections that document it, and the per-platform pages under packages/kilo-docs/pages/code-with-ai/platforms/ map to the matching extension surface (the vscode/ directory to vscode, jetbrains.md to jetbrains). A doc path belongs to the surface with the longest matching prefix; a path that matches none of those prefixes falls to `other` (the explicit other prefixes are listed under other.docs). The cloud surfaces are derived the same way from the Kilo-Org/cloud layout: cloud-mobile = apps/mobile/, cloud-web = apps/web/, cloud-extension = apps/extension/, and cloud-agent = the cloud-agent packages under packages/ (packages/cloud-agent-sdk/ + packages/cloud-agent-profile/). A cloud source names its repository while a bare string still means this repository. The pages under packages/kilo-docs/pages/collaborate/ document the cloud web app (app.kilo.ai: teams dashboard, billing, SSO, adoption dashboard), so they route to cloud-web. No page under packages/kilo-docs/pages/ documents the browser side-panel extension yet, so cloud-extension lists no docs prefix.
- Map: `.github/docs-sync/surfaces.json`
- Surface map: `cli`, `vscode`, `jetbrains`, `gateway`, `web`, `cloud-mobile`, `cloud-web`, `cloud-extension`, `cloud-agent`, `other`
- Source prefixes: `apps/mobile/` (Kilo-Org/cloud)
- Doc prefixes: `packages/kilo-docs/pages/code-with-ai/platforms/mobile.md`
- Paths that fall to `other`: `packages/kilo-docs/pages/community/`, `packages/kilo-docs/pages/kiloclaw/`, `packages/kilo-docs/pages/contributing/`, `packages/kilo-docs/LEARNINGS.md`, `docs/`
- Reviewers are ranked from `Kilo-Org/cloud`; the workflow needs a token with `contents: read` on that repository (repository secret `CROSS_REPO_ACCESS_TOKEN`, exposed to the upsert step as `CLOUD_REPO_TOKEN`).
- How the two were computed: Reviewers for `cloud-mobile` are ranked from `Kilo-Org/cloud` git history over `apps/mobile/` (a commit 180 days old counts half as much, half-life 180 days). Bots (author type "Bot" or a login matching /\[bot\]$/i) and people without admin, write, or maintain permission are excluded.

### Changes

<!-- docs-sync:changes:start -->
| Docs change | Source |
| --- | --- |
| updated pages/code-with-ai/platforms/mobile.md | [Kilo-Org/cloud#6386](Kilo-Org/cloud#6386) |
| updated pages/ai-providers/openai-chatgpt-plus-pro.md | [Kilo-Org/cloud#6702](Kilo-Org/cloud#6702) |
| updated pages/code-with-ai/platforms/cloud-agent.md | [Kilo-Org/cloud#6683](Kilo-Org/cloud#6683) |
| updated pages/getting-started/byok.md | [Kilo-Org/cloud#6692](Kilo-Org/cloud#6692) |
<!-- docs-sync:changes:end -->

### Pending — will retry

<!-- docs-sync:pending:start -->
_None._
<!-- docs-sync:pending:end -->

### Considered, no docs change needed

<!-- docs-sync:skipped:start -->
| PR | Reason |
| --- | --- |
| [Kilo-Org/cloud#6658](Kilo-Org/cloud#6658) | Internal sandbox lifecycle fix with no user-visible workflow or setting. |
| [Kilo-Org/cloud#6673](Kilo-Org/cloud#6673) | Internal container CA trust plumbing, no user-facing behavior. |
| [Kilo-Org/cloud#6672](Kilo-Org/cloud#6672) | Internal sandbox launch/recovery fix with no documented workflow change. |
| [Kilo-Org/cloud#6660](Kilo-Org/cloud#6660) | Internal cloud-agent queue delivery fix; no new command, setting, or workflow for users. |
| [Kilo-Org/cloud#6226](Kilo-Org/cloud#6226) | Internal gateway alias-routing change, not user-visible. |
| [#14490](#14490) | Tool-call animation and streaming UI polish; users do not need to learn a new workflow. |
| [#14530](#14530) | Bug fix restoring intended worktree-pool behavior, no doc change needed. |
| [#14529](#14529) | Bug fix restoring tab/panel state across project switches. |
| [#14531](#14531) | Reconnect recovery bug fix, restores already-documented behavior. |
| [#14532](#14532) | Bug fix keeping session tab title in sync on rename. |
| [Kilo-Org/cloud#6088](Kilo-Org/cloud#6088) | Removes internal/admin model-experiment surfaces, not public product docs. |
| [Kilo-Org/cloud#6682](Kilo-Org/cloud#6682) | Internal control-socket reconnect race fix, no user-facing change. |
| [#14534](#14534) | Transcript re-render performance bug fix. |
| [#14535](#14535) | Bug fix preserving the loaded browser page across context switches. |
| [Kilo-Org/cloud#6684](Kilo-Org/cloud#6684) | Reverted by Kilo-Org/cloud#6685. |
| [Kilo-Org/cloud#6678](Kilo-Org/cloud#6678) | Dead-code constant removal, no user-visible effect. |
| [Kilo-Org/cloud#6687](Kilo-Org/cloud#6687) | Removes internal model-experiment maintenance and retains tables, no user-facing change. |
| [#14515](#14515) | JetBrains plugin unload crash fix, no documented behavior change. |
| [#14520](#14520) | JetBrains transcript/list rendering performance work. |
| [Kilo-Org/cloud#6614](Kilo-Org/cloud#6614) | Mobile PR Review header and session title bug fix, no doc change needed. |
| [Kilo-Org/cloud#6625](Kilo-Org/cloud#6625) | Internal mobile secure-store error-handling refactor. |
| [Kilo-Org/cloud#6624](Kilo-Org/cloud#6624) | Mobile auth bug fix that stops a retry loop; restores expected sign-in behavior with no new setting or workflow. |
| [#14310](#14310) | Contributor/CI fix making the kilo-v2 checkout installable; not user-visible product behavior. |
| [Kilo-Org/cloud#6611](Kilo-Org/cloud#6611) | Mobile notification-tap fix that selects the session's organization; restores correct behavior rather than adding a learnable feature. |
| [Kilo-Org/cloud#6644](Kilo-Org/cloud#6644) | Mobile sign-in layout/alignment polish; no change to what a user must do. |
| [Kilo-Org/cloud#6601](Kilo-Org/cloud#6601) | Mobile layout fix keeping empty states clear of the tab bar; purely visual. |
| [#14543](#14543) | CI/release infrastructure adding Windows binary code signing; no public docs impact. |
| [Kilo-Org/cloud#6616](Kilo-Org/cloud#6616) | Mobile visual defect fixes and a session-title fallback; no new user workflow or setting. |
| [Kilo-Org/cloud#6630](Kilo-Org/cloud#6630) | Reports an edge-case partial worktree restore; failure-path plumbing with no new user-facing workflow, target setting, or config. |
| [Kilo-Org/cloud#6699](Kilo-Org/cloud#6699) | Cloud Agent e2e stabilization plus internal idle-sandbox capacity handling; not user-visible. |
| [#14545](#14545) | Automated JetBrains release/changelog PR; underlying user-facing changes are triaged from their own PRs. |
| [Kilo-Org/cloud#6708](Kilo-Org/cloud#6708) | Internal AI-gateway request-logging policy change in the admin panel; no existing public docs surface and no change to how users run Kilo Code. |
| [#14533](#14533) | Documentation already shipped with the merged PR. The experimental.task_model_selection flag is gone from the current source, and pages/code-with-ai/agents/model-selection.md, pages/code-with-ai/agents/context-mentions.md, and pages/getting-started/settings/index.md already describe per-task selection as default-on with no stale experiment references. |
| [#14510](#14510) | Documentation already shipped with the merged PR. Marketplace companion-skill support is present in the current source (packages/opencode/src/kilocode/marketplace/companions.ts and installer), and pages/customize/marketplace.md already documents installing, publishing, and removing MCP servers with companion skills. |
<!-- docs-sync:skipped:end -->

---

(bot) Generated by the docs-sync workflow. Humans review and merge; while this PR stays open, the next daily run appends new changes here. Branch: `docs/auto-sync-2026-09-25`.
<!-- docs-sync: processed-through 2026-09-25T07:05:29.302Z -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants