agentleFS
nowledge-conowledge-co/con-terminal/skills/gpui-cache-aware/SKILL.md

gpui-cache-aware

Skill651 starsChanged 7 days agoMITView on GitHub

Use this skill when reviewing or changing Con UI performance, especially when a view feels janky, expensive, or unexpectedly re-renders during unrelated updates. Keep Con visually rich without paying repeated GPUI layout/render cost for work that could be cached or isolated. Cache at the cheapest correct layer first. Order of preference: Do not jump straight to view caching. For any slow UI path, inspect these in order: Preferred fix: Preferred fix: Preferred fix: Use AnyView::cached(...) only if all of these…

The file

Show its rules and text

We split this skill into the rules it gives an agent

25 rules. About 0 are common, 18 are distinctive, and 7 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈18

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 7

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Use this skill when reviewing or changing Con UI performance, especially when a view feels janky, expensive, or unexpectedly re-renders …

    line 3
  2. Distinctive:

    Keep Con visually rich without paying repeated GPUI layout/render cost for work that could be cached or isolated.

    line 7
  3. Very specific:

    Use GPUI AnyView::cached(...) only when the subtree has a stable size contract.

    line 18
  4. Distinctive:

    Do not jump straight to view caching.

    line 20
  5. Very specific:

    add data-layer caches on parsed document/block/cell/message structs

    line 34
  6. Distinctive:

    keep decorative element composition for UI chrome and short content only

    line 45
  7. Very specific:

    keep mutation paths explicit so only that entity gets notify()

    line 55
  8. Very specific:

    Use AnyView::cached(...) only if all of these are true:

    line 59
  9. Distinctive:

    If a cached view causes overlap, clipping, or stale layout, the cache boundary is wrong.

    line 76
  10. Distinctive:

    If there are many repeated items, consider virtualization before micro-optimizing item chrome.

    line 80
  11. Distinctive:

    If the item count is small but each item is expensive, focus on item-level caches instead.

    line 81
  12. Distinctive:

    Prefer parsed markdown caches on the message/document model.

    line 87
  13. Distinctive:

    Avoid per-token flex trees for long replies.

    line 90
  14. Distinctive:

    Do not hide/fold long replies as the primary performance fix.

    line 95
  15. Distinctive:

    Keep terminal surfaces and heavy side panels isolated.

    line 100
  16. Distinctive:

    Avoid reading terminal runtime state during ordinary render unless already cached.

    line 101
  17. Distinctive:

    Check GPU composition bounds as well as CPU caches.

    line 103
  18. Very specific:

    Do not return a child's layout ID from a presentation wrapper and then call prepaint_as_root on that same child.

    line 114
  19. Distinctive:

    Test hitbox positions against visible geometry, not merely whether a click at the hitbox's reported (possibly wrong) position invokes its …

    line 118
  20. Very specific:

    When observing scroll endpoints after layout, request a follow-up frame only when visibility changes.

    line 127
  21. Very specific:

    If a view needs .on_hover(...), call .id(stable_id) first.

    line 150
  22. Distinctive:

    After a cache-related change:

    line 159
  23. Distinctive:

    run targeted tests if the subsystem has them

    line 162
  24. Distinctive:

    if touching Windows/Linux-only view code from macOS, note that local checks are partial unless the target toolchain is installed

    line 166
  25. Distinctive:

    If the only way a change feels fast is by degrading rendering fidelity, treat that as an incomplete fix and keep going.

    line 180

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

GPUI Cache-Aware Review

Use this skill when reviewing or changing Con UI performance, especially when a view feels janky, expensive, or unexpectedly re-renders during unrelated updates.

Goal

Keep Con visually rich without paying repeated GPUI layout/render cost for work that could be cached or isolated.

Core Rule

Cache at the cheapest correct layer first.

Order of preference:

  1. Cache parsed / normalized data.
  2. Cache expensive text-run or highlight transforms.
  3. Isolate expensive subtrees behind stable entity boundaries.
  4. Use GPUI AnyView::cached(...) only when the subtree has a stable size contract.

Do not jump straight to view caching.

Review Checklist

For any slow UI path, inspect these in order:

1. Parse / transform churn

  • Is the code reparsing markdown / JSON / syntax / layout input on every render?
  • Is the code rebuilding SharedString, Vec<TextRun>, highlighted runs, or table cell text on every render?
  • Can the expensive transform be retained on the model object and invalidated only on real content change?

Preferred fix:

  • add data-layer caches on parsed document/block/cell/message structs
  • invalidate only when source text or theme-dependent key changes

2. Render-tree cardinality

  • Is the renderer producing many tiny div() children for content that could be one StyledText?
  • Are inline chips, per-token wrappers, nested flex rows, or deep container stacks used for long-form content?

Preferred fix:

  • collapse long-form prose to text-first rendering
  • keep decorative element composition for UI chrome and short content only

3. Entity boundaries

  • Is a very large subtree being rebuilt because the parent panel rerendered for unrelated state?
  • Can the subtree live in its own Entity<V> with a narrower invalidation surface?

Preferred fix:

  • split large stable regions into their own render entities
  • keep mutation paths explicit so only that entity gets notify()

4. GPUI cached view suitability

Use AnyView::cached(...) only if all of these are true:

  • the subtree size is externally constrained or stable
  • the cached style can describe the layout contract correctly
  • reusing previous layout/paint is actually valid for the subtree

Good fits:

  • panes that fill known bounds
  • fixed-size or externally-sized tool panels
  • stable canvases / editors / native-host surfaces

Bad fits:

  • intrinsic-height rich text documents
  • content whose height depends on wrapping and dynamic width unless that width/height contract is explicitly handled

If a cached view causes overlap, clipping, or stale layout, the cache boundary is wrong.

5. Lists and scrolling surfaces

  • If there are many repeated items, consider virtualization before micro-optimizing item chrome.
  • If the item count is small but each item is expensive, focus on item-level caches instead.

Con-Specific Guidance

Markdown and chat surfaces

  • Prefer parsed markdown caches on the message/document model.
  • Cache inline text-run generation for paragraphs, headings, and table cells.
  • Cache syntax-highlight runs for code blocks.
  • Avoid per-token flex trees for long replies.
  • For long assistant replies, isolate each markdown block behind a stable Entity and reuse that entity across parent renders. Keep per-block UI state such as table scroll handles on that entity, not inside parsed markdown data that is produced off the UI thread.
  • Do not hide/fold long replies as the primary performance fix. Folding can be a UX affordance, but the expanded state must remain responsive.

Terminal-adjacent UI

  • Keep terminal surfaces and heavy side panels isolated.
  • Avoid reading terminal runtime state during ordinary render unless already cached.
  • Be cautious with transparency, animation, and resize interactions; measure before adding visual layers.
  • Check GPU composition bounds as well as CPU caches. In the pinned Metal renderer, paths are copied from an intermediate texture over their bounds. A viewport-sized path with a hole can still require a large blit. For canvas gutters, use narrow quads and separately cached, corner-sized paths; test that they never paint over terminal pixels and keep their bounds small.
  • For hover affordances that only need cursor feedback, prefer a tiny overlay / hitbox and cursor_pointer() over repainting terminal text. Keep the overlay state bounded to the hovered link/range.

GPUI interaction gotchas

  • Do not return a child's layout ID from a presentation wrapper and then call prepaint_as_root on that same child. The node is still parented in Taffy; GPUI's absolute-origin lookup can count the parent offset again. Give the wrapper its own layout node and lay out the child as an independent root. Test hitbox positions against visible geometry, not merely whether a click at the hitbox's reported (possibly wrong) position invokes its callback.
  • Caption .occlude() targets can block an ancestor's wheel listener. Forward wheel events from the real occluded target to its shared scroll handle, and include occlusion in the interaction test fixture. A plain layout fixture can pass while the native caption cannot scroll.
  • Component popover triggers need mouse-down to reach their wrapper. Apply native-caption occlusion outside the whole popover, not to its inner button; retain mouse-down consumption on ordinary caption buttons.
  • When observing scroll endpoints after layout, request a follow-up frame only when visibility changes. An unconditional on_next_frame from prepaint creates idle frame demand even when no animation is running.
  • Recheck the pinned view-cache key before animating an ancestor's opacity. The current key includes bounds, content mask and text style, but not inherited opacity. Keep such a subtree uncached while its opacity changes, and restore caching at the fully opaque endpoint. A changing clip can invalidate the cache, but rounded pixel bounds are not a reliable opacity invalidation mechanism.
  • Native-surface overlays cannot rely on an opaque GPUI fill hiding a drop shadow's interior. If elevation is needed, paint only exterior content-mask strips, never a shadow-only full-surface div over terminal glass. The pinned Metal shadow vertex stage uses clip distances for these masks. Verify both the content's unchanged appearance and the masked geometry; do not infer a frame-rate improvement from a smaller painted region alone.
  • A pane's undecorated/single-pane path must still run native clip prepaint. A native scroll host also needs its own backing layer before a layer mask can work; a Metal-backed descendant does not imply parent backing. Reusing its terminal after closing a sibling can otherwise retain a split mask even though its view frame has expanded. Test the real rendering path, not just the native mask setter in isolation.
  • .hover(|style| ...) is a style hook on Div; .on_hover(...) is an enter/exit listener and requires a Stateful<Div>.
  • If a view needs .on_hover(...), call .id(stable_id) first. Use a stable id such as the pane's FocusHandle, not a changing row/index.
  • For platform-selected files (ghostty_view.rs, windows_view.rs, linux_view.rs), a macOS cargo check -p con only checks the macOS path. Validate the touched platform path on its target or wait for portable CI before treating the fix as closed.

Validation

After a cache-related change:

  • verify cargo check -p con
  • run targeted tests if the subsystem has them
  • confirm there is no layout regression
  • confirm the cache invalidates on real content/theme changes
  • confirm the cache does not hide stale data
  • if touching Windows/Linux-only view code from macOS, note that local checks are partial unless the target toolchain is installed

Anti-Patterns

  • caching a view because it "seems expensive" without proving its size contract is stable
  • keeping old cached output after source text changed
  • using collapsed/default-hidden UI as the main performance strategy
  • replacing high-fidelity rendering with degraded output when a correct cache boundary exists

Deliverable Standard

The final fix should preserve UX quality first, then reduce repeated work structurally.

If the only way a change feels fast is by degrading rendering fidelity, treat that as an incomplete fix and keep going.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.