Cognition Rebuilds Devin's Chat to Load 70% Faster for Huge Sessions

Cognition rebuilt the Devin webapp's chat renderer with skeleton outlines and scroll anchoring, cutting load times 70% for massive sessions.

·
·
  • Cognition rebuilt Devin's chat renderer, cutting large session load times by 70%.
  • Layout shift dropped 86%, and Interaction to Next Paint improved 36% across the app.
  • Skeleton outlines let users scroll instantly through sessions with hundreds of thousands of messages.
  • Island loading hydrates events near the viewport with a buffer, avoiding scroll-then-wait cycles.
  • A single anchor row keeps viewport stable when skeletons swap for real messages mid-scroll.
  • Webapp facelift adds compact sidebar, ⌘K palette, nested subagent management, and filtering.

Cognition shipped a substantial overhaul of the Devin webapp, and the headline number is one every frontend engineer working on long-lived agent UIs will recognize as painful: the largest sessions used to take more than 20 seconds to load, then stutter and drop frames afterward. The team rewrote the chat renderer from scratch, and along the way redesigned the sidebar, command palette, and the way nested subagents surface in the UI.

The rebuild targets a specific failure mode. Users run Devin for days at a time, producing sessions with hundreds of thousands of messages, and the browser simply cannot render that much DOM. The canonical fix is straightforward: don't fetch everything, and don't render everything. But the first pass at virtualization produced its own problems, and fixing them is where the interesting engineering lives.

Why the first virtualizer wasn't good enough

The engineering post is candid about the initial implementation. As events loaded in or new rows rendered, the height of elements on screen would change, moving the content the user was reading. Streaming made it worse, because the chat would shift under the cursor even when nobody was scrolling. And jumping to older parts of a session meant scrolling, hitting a spinner, waiting, and repeating, sometimes for minutes to reach the first message.

The goal they landed on is worth stating clearly: make it feel like the entire session is already on the machine, without actually loading it.

Skeleton outlines and island loading

The core trick is a two-stage fetch. Instead of pulling full event payloads, the app first queries only the type of each event in the session. This query stays fast even with huge sessions because it only scans an index and returns very little data, just an array of types. From that array, the renderer paints a skeleton that approximates the real chat's height and shape.

When the user scrolls to an unloaded region, the app hydrates an island of real events around that position, including a buffer above and below so content is usually ready before it enters the viewport. The skeletons then swap out for real messages.

Anchoring the viewport so nothing jumps

Swapping skeletons for real messages changes row heights, which normally shoves everything on screen around. Their solution is a small set of rules for picking an anchor row whose on-screen position must not change:

  • If there are visible loaded messages, the topmost loaded message becomes the anchor.
  • If only skeletons are visible, the topmost skeleton becomes the anchor.
  • After new rows render, measure the height delta and apply it as a scroll offset before the browser paints.

One edge case remains: skeletons mixed with loaded rows on the same screen, where any row could be the one the user is reading. Rather than compromise, they prevent these situations from arising entirely by extending any load that would create a small islet to cover the whole islet.

The numbers

Chats load 70% faster, and layout shift decreased by 86%. The improvement scales with session size, so p99 sessions see a 70% reduction in load time while p50 sees around 23%. Cognition's own summary of the release also cites a 55% faster open time for long chats and a 36% drop in Interaction to Next Paint, the Core Web Vitals metric for input responsiveness.

Devin fixing Devin

One of the more interesting parts of the write-up is the workflow. Rather than debug virtualization issues by hand, the team built a virtualization debugger that logs every relevant action and visualizes chat state, then handed failing session logs to Devin in overnight batches. Devin would come up with several fixes in parallel and test them with the debugger to validate that the issue would not reproduce.

The team's takeaway is that computer-use agents are still not great at intuiting UI bugs the way humans do, so giving them purpose-built inspection tools matters more than expecting them to squint at screenshots. Agents tend to stick to their existing tools rather than build new ones, so it's on the engineers running them to push in an ambition-maximizing direction.

What else shipped with the facelift

The renderer is the headline, but the webapp update bundles several workflow changes:

  • A customizable sidebar with new grouping and filtering to surface sessions that need attention.
  • A compact view that condenses each session row down to the most important information.
  • An expanded ⌘K command menu that can find, start, pin, and navigate sessions from the keyboard.
  • Nested subagent management, so parent sessions that spin up child sessions with their own VMs are now visible and controllable from the sidebar.
  • An auto-hiding sidebar that peeks out when the cursor hits the left edge of the screen.

For anyone building agent frontends where sessions can grow without bound, the pattern here is worth borrowing: fetch a cheap type-only outline first, hydrate islands on demand, and pick a single anchor row to keep the viewport stable through every reflow. It is the kind of infrastructure work that does not usually get a blog post, and the reason it did is that agent sessions are starting to look less like chats and more like long-running project timelines.

Comments

avatar