Files
nexus/sreweekly/articles/494/08-how-we-sped-up-code-search-for-graphite-chat.html
2026-09-12 17:23:01 +08:00

40 lines
207 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html><html class="has-data-[in-page-nav=true]:scroll-p-34 lg:has-data-[in-page-nav=true]:scroll-p-20 has-[ol]:scroll-smooth" lang="en"><head><style type="text/css" data-next-head="">
:root {
--font-matter: 'matterFont', 'matterFont Fallback';
--font-dm-mono: 'dmMono', 'dmMono Fallback';
--font-jet-brains-mono: 'JetBrains Mono', 'JetBrains Mono Fallback';
--font-inter: 'Inter', 'Inter Fallback';
}
</style><meta charSet="utf-8" data-next-head=""/><meta name="viewport" content="width=device-width, height=device-height, initial-scale=1, shrink-to-fit=no" data-next-head=""/><meta name="theme-color" content="#fffcf8" data-next-head=""/><link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png" data-next-head=""/><link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png" data-next-head=""/><link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png" data-next-head=""/><link rel="manifest" href="/favicon/site.webmanifest" data-next-head=""/><link rel="mask-icon" href="/favicon/safari-pinned-tab.svg" color="#000000" data-next-head=""/><title data-next-head="">How we sped up code search for Graphite Chat </title><meta name="description" content="How we built fast, low-latency code search at any commit—going beyond default-branch-only tools like GitHub and Sourcegraph." data-next-head=""/><meta name="twitter:card" content="summary_large_image" data-next-head=""/><meta name="twitter:site" content="@graphite" data-next-head=""/><meta name="twitter:creator" content="@graphite" data-next-head=""/><meta name="twitter:title" content="How we sped up code search for Graphite Chat " data-next-head=""/><meta name="twitter:description" content="How we built fast, low-latency code search at any commit—going beyond default-branch-only tools like GitHub and Sourcegraph." data-next-head=""/><meta name="twitter:image" content="https://www.datocms-assets.com/85246/1757535905-082025_code-search_v1_0057.jpg?fm=jpg&amp;q=75&amp;w=1200&amp;h=630&amp;fit=crop" data-next-head=""/><meta property="og:title" content="How we sped up code search for Graphite Chat " data-next-head=""/><meta property="og:description" content="How we built fast, low-latency code search at any commit—going beyond default-branch-only tools like GitHub and Sourcegraph." data-next-head=""/><meta property="og:site_name" content="Graphite" data-next-head=""/><meta property="og:url" content="https://staging-graphite-splash.vercel.app/blog/how-we-sped-up-code-search-graphite-chat" data-next-head=""/><meta property="og:image" content="https://www.datocms-assets.com/85246/1757535905-082025_code-search_v1_0057.jpg?fm=jpg&amp;q=75&amp;w=1200&amp;h=630&amp;fit=crop" data-next-head=""/><meta property="og:image:alt" content="How we sped up code search for Graphite Chat " data-next-head=""/><meta property="og:image:width" content="1200" data-next-head=""/><meta property="og:image:height" content="630" data-next-head=""/><link rel="canonical" href="https://staging-graphite-splash.vercel.app/blog/how-we-sped-up-code-search-graphite-chat" data-next-head=""/><link rel="alternate" type="application/rss+xml" title="RSS Feed for petefreitag.com" href="/feed.xml"/><script>
(function() {
function getCookie(name) {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
if (cookie.indexOf(name + '=') === 0) {
return cookie.substring(name.length + 1);
}
}
return null;
}
var cookie = getCookie("loggedIn");
if (window.location.pathname === "/" && cookie) {
var url = new URL("https://app.graphite.com");
url.search = window.location.search;
url.searchParams.set("redirected", "true");
window.location.href = url;
}
})();
</script><link rel="preload" href="/_next/static/media/MatterRegular-s.p.a1dc570b.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><link rel="preload" href="/_next/static/media/MatterRegularItalic-s.p.7094561a.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><link rel="preload" href="/_next/static/media/MatterMedium-s.p.9d516e3b.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><link rel="preload" href="/_next/static/media/MatterMediumItalic-s.p.21558a2a.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><link rel="preload" href="/_next/static/media/MatterSemiBold-s.p.8a088781.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><link rel="preload" href="/_next/static/media/MatterSemiBoldItalic-s.p.d51d9f3c.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><link rel="preload" href="/_next/static/media/DMMono_light-s.p.fdd3dd50.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><link rel="preload" href="/_next/static/media/DMMono_light_italic-s.p.701be9e8.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><link rel="preload" href="/_next/static/media/DMMono_regular-s.p.2e6dc724.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><link rel="preload" href="/_next/static/media/DMMono_italic-s.p.4eee889a.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><link rel="preload" href="/_next/static/media/DMMono_medium-s.p.fa7f462f.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><link rel="preload" href="/_next/static/media/DMMono_medium_italic-s.p.30950d31.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><link rel="preload" href="/_next/static/media/19087af2bdec32b5-s.p.ec718a33.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><link rel="preload" href="/_next/static/media/83afe278b6a6bb3c-s.p.3a6ba036.woff2" as="font" type="font/woff2" crossorigin="anonymous" data-next-font="size-adjust"/><script id="set-stage" data-nscript="beforeInteractive">window.STAGE = "undefined";</script><link rel="preload" href="/_next/static/chunks/d0e98280d773cdc7.css?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" as="style"/><link rel="stylesheet" href="/_next/static/chunks/d0e98280d773cdc7.css?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" data-n-g=""/><link rel="preload" href="/_next/static/chunks/143a91cba7c5a1c4.css?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" as="style"/><link rel="stylesheet" href="/_next/static/chunks/143a91cba7c5a1c4.css?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" data-n-g=""/><link rel="preload" href="/_next/static/chunks/1c0dd04c40bb88b9.css?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" as="style"/><link rel="stylesheet" href="/_next/static/chunks/1c0dd04c40bb88b9.css?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" data-n-p=""/><link rel="preload" href="/_next/static/chunks/4e87d6a824171741.css?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" as="style"/><link rel="stylesheet" href="/_next/static/chunks/4e87d6a824171741.css?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv"/><noscript data-n-css=""></noscript><script defer="" src="/_next/static/chunks/2d25b8a8ab069056.js?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv"></script><script defer="" src="/_next/static/chunks/fb0c3a5e6963d689.js?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv"></script><script src="/_next/static/chunks/884d29612cfe3bdb.js?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" defer=""></script><script src="/_next/static/chunks/24a66d6e4b525e14.js?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" defer=""></script><script src="/_next/static/chunks/6b8e8ea77ca1ffe5.js?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" defer=""></script><script src="/_next/static/chunks/e02bade43e3faae3.js?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" defer=""></script><script src="/_next/static/chunks/ceeaf640e4c16e66.js?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" defer=""></script><script src="/_next/static/chunks/278a7917e4346bce.js?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" defer=""></script><script src="/_next/static/chunks/84de96a25d47ea1d.js?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" defer=""></script><script src="/_next/static/chunks/b00e80b39eaccc22.js?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" defer=""></script><script src="/_next/static/chunks/turbopack-3d623e61d368e120.js?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" defer=""></script><script src="/_next/static/chunks/1cbfc46d207591d6.js?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" defer=""></script><script src="/_next/static/chunks/c4d6ac274e0c5520.js?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" defer=""></script><script src="/_next/static/chunks/318de0601bf93f2b.js?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" defer=""></script><script src="/_next/static/chunks/f2e32afd1ba9f9a6.js?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" defer=""></script><script src="/_next/static/chunks/114f5f9bb359a7a4.js?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" defer=""></script><script src="/_next/static/chunks/bef1cf00dff67378.js?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" defer=""></script><script src="/_next/static/chunks/d1dde5b51132732e.js?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" defer=""></script><script src="/_next/static/chunks/f9cd939ebd5bc405.js?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" defer=""></script><script src="/_next/static/chunks/turbopack-58bdd8120aeb4169.js?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" defer=""></script><script src="/_next/static/0Ku2uBfu23Pa9kZxkrE8D/_ssgManifest.js?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" defer=""></script><script src="/_next/static/0Ku2uBfu23Pa9kZxkrE8D/_buildManifest.js?dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv" defer=""></script></head><body><div id="__next"><noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-WKH3LF8H" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript><script>((e,i,s,u,m,a,l,h)=>{let d=document.documentElement,w=["light","dark"];function p(n){(Array.isArray(e)?e:[e]).forEach(y=>{let k=y==="class",S=k&&a?m.map(f=>a[f]||f):m;k?(d.classList.remove(...S),d.classList.add(a&&a[n]?a[n]:n)):d.setAttribute(y,n)}),R(n)}function R(n){h&&w.includes(n)&&(d.style.colorScheme=n)}function c(){return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}if(u)p(u);else try{let n=localStorage.getItem(i)||s,y=l&&n==="system"?c():n;p(y)}catch(n){}})("data-theme","theme","system","dark",["light","dark"],null,true,true)</script><a href="#main-content" class="absolute top-0 left-0 bg-white text-sm text-black p-2 z-50 opacity-0 pointer-events-none focus:opacity-100 focus:pointer-events-auto">Skip to content</a><a class="flex relative z-20 py-3 px-8 bg-popover sm:text-center text-balance items-center justify-center flex-nowrap gap-2 text-xs sm:text-sm font-medium transition-all duration-200 ease-out border-b-neutral-200 dark:border-neutral-800 border-b leading-tight group" role="region" aria-label="Announcement" href="/blog/cursor-cloud-agents"><div class="dots absolute inset-0 w-full h-full pointer-events-none opacity-25 dark:[--dot-color:white] [--dot-color:black]" aria-hidden="true" style="--dot-size:4px;--dot-inset:1.5;--dot-image:radial-gradient(var(--dot-color) 50%, transparent 50%)"></div><p class="font-semibold">Cursor Cloud Agents are now in Graphite. Create, review, and ship without leaving your PR.</p><div class="flex items-center gap-1.5 rounded-full transition-all duration-200 ease-out font-medium whitespace-nowrap text-foreground/50 group-hover:text-foreground">Read more<svg width="12" height="10" viewBox="0 0 12 10" fill="currentColor" xmlns="http://www.w3.org/2000/svg" class="group-hover:translate-x-0.25 transition-transform duration-200 ease-out size-3"><path d="M5.8965 1.208L8.9525 4.248H0.9205V5.432H8.9525L5.9125 8.488L6.6805 9.256L11.0805 4.84L6.6645 0.424L5.8965 1.208Z" fill="currentColor"></path></svg></div></a><header class="sticky top-0 z-40 container scheme-dark"><div aria-hidden="true" class="fixed top-0 left-0 w-full h-16 bg-background backdrop-blur-sm mask-(--gradient-ease-in-out-sine) pointer-events-none opacity-0 transition-opacity duration-300"></div><div class="py-2 lg:px-0 transition-[padding] flex justify-center duration-300"><div class="bg-transparent p-2 flex gap-2 w-full text-sm text-subtle rounded-xl items-center justify-between duration-300 transition-all relative"><div aria-hidden="true" class="absolute inset-0 pointer-events-none transition-opacity border rounded-xl border-transparent"><svg class="absolute -inset-px" width="100%" height="100%" preserveAspectRatio="none" aria-hidden="true"><mask id="header-mask"><rect class="size-full" fill="white" rx="12" ry="12"></rect></mask></svg><div class="absolute inset-0 h-[200%] rounded-xl box-decoration-clone mask-[url(#header-mask)] mask-subtract bg-linear-to-b from-background via-background/33 to-background/0 backdrop-blur-lg"></div></div><div class="relative"><a class="text-primary flex items-center gap-2 text-lg tracking-tighter pointer-events-auto sm:mask-wipe sm:hover:animate-mask-wipe ml-2 w-28 sm:w-32 sm:hover:[animation-duration:2s]" href="/"><svg viewBox="0 0 966 189" fill="none" aria-label="Graphite Logo"><path fill-rule="evenodd" clip-rule="evenodd" d="M662.11 153.252V22.178H680.724V72.1495H681.662C689.326 61.3067 697.774 57.6931 708.722 57.6931C731.084 57.6931 745.95 72.4646 745.95 96.9761V153.252H727.332V96.9775C727.364 94.0188 726.806 91.0842 725.692 88.3454C724.578 85.6066 722.93 83.1188 720.85 81.0261C718.762 78.9343 716.288 77.2796 713.558 76.1602C710.834 75.0408 707.914 74.4786 704.97 74.5061C691.05 74.5061 680.726 84.8773 680.726 96.9777V153.252L662.11 153.252Z" fill="currentColor"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M820.817 133.595V76.3939H804.395V59.5792H820.817V39.1986L839.435 28.3811V59.5792H866.961V76.3939H839.435V130.767C839.435 134.538 841.311 136.423 845.061 136.423H866.961L857.125 153.253H841.311C828.013 153.253 820.817 145.695 820.817 133.595Z" fill="currentColor"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M629.3 106.01C629.3 86.5236 617.258 74.1096 602.242 74.1096C587.384 74.1096 575.341 86.5236 575.341 106.01C575.341 125.497 587.384 137.756 602.242 137.756C617.258 137.756 629.3 125.497 629.3 106.01ZM556.729 188.672V59.571H573.464L575.341 73.6379H576.279C579.409 66.8807 587.073 57.2949 605.059 57.2949C629.461 57.2949 647.912 75.9969 647.912 106.01C647.912 136.023 629.457 154.725 605.059 154.725C587.227 154.725 579.095 145.296 576.279 138.382H575.341V188.671L556.729 188.672Z" fill="currentColor"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M757.026 76.4245H773.446V153.252H792.056V59.5781H757.026V76.4245Z" fill="currentColor"></path><path d="M792.059 22.178H771.573V41.8209H792.059V22.178Z" fill="currentColor"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M399.474 153.252V59.5781H415.272L417.148 71.2107H418.086C422.622 61.9387 427.158 59.5781 440.452 59.5781H450.4V76.4245H437.638C423.874 76.4245 418.086 81.7358 418.086 94.3072V153.252L399.474 153.252Z" fill="currentColor"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M893.427 98.4669H948.323C946.289 83.5388 936.275 73.1662 921.259 73.1662C905.467 73.1662 896.237 83.5388 893.427 98.4669ZM946.015 126.378L961.157 135.16C953.157 145.718 939.979 154.725 921.267 154.725C894.361 154.725 874.817 135.082 874.817 106.01C874.817 76.9387 894.361 57.2949 921.267 57.2949C946.447 57.2949 965.999 76.9379 965.999 103.182C965.959 105.441 965.803 107.696 965.529 109.938L965.057 112.609H893.427C895.459 128.482 906.401 138.697 921.259 138.697C932.523 138.697 940.889 133.986 946.015 126.378Z" fill="currentColor"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M516.027 112.967V109.195H493.817C479.585 109.195 473.327 115.638 473.327 124.124C473.327 132.61 478.801 138.11 490.063 138.11C506.955 138.11 516.027 128.837 516.027 112.967ZM533.075 153.252C520.093 153.252 517.591 143.799 516.965 139.244H516.027C510.395 150.558 498.353 154.645 488.185 154.645C467.701 154.645 454.559 142.544 454.559 125.572C454.559 106.87 466.761 94.6108 492.879 94.6108H516.027V92.883C516.027 80.6238 508.673 73.266 496.475 73.0819C492.141 73.0889 487.891 74.2948 484.193 76.5683C480.495 78.8408 477.491 82.093 475.511 85.9676L459.671 76.7931C466.061 65.1408 478.195 57.2146 496.479 57.2146C520.881 57.2146 534.797 71.0428 534.797 92.8868V132.9C534.797 133.834 535.167 134.73 535.825 135.392C536.483 136.052 537.375 136.423 538.303 136.423H545.747V153.252H533.075Z" fill="currentColor"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M378.171 84.4829V153.253H362.371L360.501 132.884H359.557C350.491 147.183 335.787 154.726 318.579 154.726C284.327 154.726 256.175 127.541 256.175 87.3104C256.175 47.0793 284.327 19.8938 318.579 19.8938C346.287 19.8938 364.563 36.5553 374.225 54.8996L358.167 64.233C349.145 48.6895 335.475 38.5959 318.579 38.5959C294.177 38.5959 275.723 57.2979 275.723 87.3104C275.723 117.17 294.177 136.025 318.579 136.025C340.943 136.025 358.621 118.423 358.621 101.297V100.356H324.111L315.017 84.4827L378.171 84.4829Z" fill="currentColor"></path><path d="M111.052 0L23.468 23.5035L0 111.22L64.1158 175.433L151.7 151.93L175.168 64.2131L111.052 0ZM125.364 153.254H49.8032L12.0226 87.7166L49.8032 22.1794H125.364L163.145 87.7166L125.364 153.254Z" fill="currentColor"></path><path d="M131.431 43.8006L71.5321 27.7263L27.6829 71.6419L43.7329 131.632L103.632 147.706L147.481 103.79L131.431 43.8006Z" fill="currentColor"></path></svg></a></div><div class="justify-center lg:flex hidden dark"><nav aria-label="Main" data-orientation="horizontal" dir="ltr" data-slot="navigation-menu" data-viewport="false" class="group/navigation-menu relative flex max-w-max flex-1 items-center w-full justify-center"><div style="position:relative"><ul data-orientation="horizontal" data-slot="navigation-menu-list" class="group flex-1 list-none justify-center flex flex-row items-start" dir="ltr"><li data-slot="navigation-menu-item" class="relative group/trigger hover:bg-accent rounded-md transition-all"><button id="radix-:R1qak6:-trigger-radix-:R6dqak6:" data-state="closed" aria-expanded="false" aria-controls="radix-:R1qak6:-content-radix-:R6dqak6:" data-slot="navigation-menu-trigger" class="group group group inline-flex w-full h-9 items-center justify-center rounded-md bg-transparent px-4 py-2 text-sm font-medium text-accent-foreground/60 hover:text-accent-foreground dark:hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1" data-radix-collection-item=""><div class="w-fit gap-2 transition-all">Features</div><div aria-hidden="true" class="origin-bottom scale-0 opacity-0 group-data-[state=open]:opacity-100 group-data-[state=open]:scale-100 transition-opacity duration-300 group-data-[state=closed]:duration-0 z-10 pointer-events-none size-1.5 absolute top-full left-1/2 -translate-x-1/2 translate-y-1 bg-popover rotate-45 border-accent-foreground/10 border-t-1 border-r-0 border-b-0 border-l-1"></div> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevron-down relative top-[1px] ml-1 size-5 lg:size-3 transition lg:group-data-[state=open]:-rotate-180 -rotate-90 lg:rotate-0" aria-hidden="true"><path d="m6 9 6 6 6-6"></path></svg></button></li><li data-slot="navigation-menu-item" class="relative group/trigger hover:bg-accent rounded-md transition-all"><button id="radix-:R1qak6:-trigger-radix-:Radqak6:" data-state="closed" aria-expanded="false" aria-controls="radix-:R1qak6:-content-radix-:Radqak6:" data-slot="navigation-menu-trigger" class="group group group inline-flex w-full h-9 items-center justify-center rounded-md bg-transparent px-4 py-2 text-sm font-medium text-accent-foreground/60 hover:text-accent-foreground dark:hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1" data-radix-collection-item=""><div class="w-fit gap-2 transition-all">Resources</div><div aria-hidden="true" class="origin-bottom scale-0 opacity-0 group-data-[state=open]:opacity-100 group-data-[state=open]:scale-100 transition-opacity duration-300 group-data-[state=closed]:duration-0 z-10 pointer-events-none size-1.5 absolute top-full left-1/2 -translate-x-1/2 translate-y-1 bg-popover rotate-45 border-accent-foreground/10 border-t-1 border-r-0 border-b-0 border-l-1"></div> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevron-down relative top-[1px] ml-1 size-5 lg:size-3 transition lg:group-data-[state=open]:-rotate-180 -rotate-90 lg:rotate-0" aria-hidden="true"><path d="m6 9 6 6 6-6"></path></svg></button></li><li data-slot="navigation-menu-item" class="relative group/trigger hover:bg-accent rounded-md transition-all"><a data-slot="navigation-menu-link" class="data-[active=true]:focus:bg-accent data-[active=true]:bg-accent/50 data-[active=true]:text-accent-foreground [&amp;_svg:not([class*=&#x27;text-&#x27;])]:text-muted-foreground flex-col gap-1 p-2 [&amp;_svg:not([class*=&#x27;size-&#x27;])]:size-4 group inline-flex w-full h-9 items-center justify-center rounded-md bg-transparent px-4 py-2 text-sm font-medium text-accent-foreground/60 hover:text-accent-foreground dark:hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1" href="/customers" data-radix-collection-item="">Customers</a></li><li data-slot="navigation-menu-item" class="relative group/trigger hover:bg-accent rounded-md transition-all"><a data-slot="navigation-menu-link" class="data-[active=true]:focus:bg-accent data-[active=true]:bg-accent/50 data-[active=true]:text-accent-foreground [&amp;_svg:not([class*=&#x27;text-&#x27;])]:text-muted-foreground flex-col gap-1 p-2 [&amp;_svg:not([class*=&#x27;size-&#x27;])]:size-4 group inline-flex w-full h-9 items-center justify-center rounded-md bg-transparent px-4 py-2 text-sm font-medium text-accent-foreground/60 hover:text-accent-foreground dark:hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1" href="/docs" data-radix-collection-item="">Docs</a></li><li data-slot="navigation-menu-item" class="relative group/trigger hover:bg-accent rounded-md transition-all"><a data-slot="navigation-menu-link" class="data-[active=true]:focus:bg-accent data-[active=true]:bg-accent/50 data-[active=true]:text-accent-foreground [&amp;_svg:not([class*=&#x27;text-&#x27;])]:text-muted-foreground flex-col gap-1 p-2 [&amp;_svg:not([class*=&#x27;size-&#x27;])]:size-4 group inline-flex w-full h-9 items-center justify-center rounded-md bg-transparent px-4 py-2 text-sm font-medium text-accent-foreground/60 hover:text-accent-foreground dark:hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1" href="/pricing" data-radix-collection-item="">Pricing</a></li><li data-slot="navigation-menu-item" class="relative group/trigger hover:bg-accent rounded-md transition-all"><a data-slot="navigation-menu-link" class="data-[active=true]:focus:bg-accent data-[active=true]:bg-accent/50 data-[active=true]:text-accent-foreground [&amp;_svg:not([class*=&#x27;text-&#x27;])]:text-muted-foreground flex-col gap-1 p-2 [&amp;_svg:not([class*=&#x27;size-&#x27;])]:size-4 group inline-flex w-full h-9 items-center justify-center rounded-md bg-transparent px-4 py-2 text-sm font-medium text-accent-foreground/60 hover:text-accent-foreground dark:hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1" target="_blank" href="https://cursor.com/contact-sales?product=graphite" data-radix-collection-item="">Contact</a></li></ul></div></nav></div><div class="pointer-events-auto flex flex-row gap-2 justify-end"><div class="flex flex-row gap-2 transition-opacity duration-300 opacity-0 pointer-events-none"><a class="md:pr-2 pr-4 pl-4 py-2 border border-secondary group w-full cursor-pointer inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&amp;_svg]:pointer-events-none [&amp;_svg]:size-4 [&amp;_svg]:shrink-0 relative bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80" aria-label="Log in" accessKey="g" href="https://app.graphite.com">Log in<span aria-hidden="true" class="hidden size-6 ml-2 md:flex items-center justify-center rounded-sm bg-primary/10 text-primary/60">G</span></a><div class="relative [--glow-strength:0]"><div class="absolute inset-0 size-full"><div class="blur-[calc(var(--glow-strength)*4px+12px)] absolute w-2/3 h-full top-0 bg-category-magenta/20 left-0" style="opacity:calc(0.2 * var(--glow-strength) + .8);transform:translate(calc(var(--glow-x) * 10%), calc(var(--glow-y) * -2%))"></div><div class="blur-[calc(var(--glow-strength)*4px+12px)] absolute w-2/3 h-full top-0 bg-category-orange/20 right-0" style="opacity:calc(0.2 * var(--glow-strength) + .8);transform:translate(calc(var(--glow-x) * -10%), calc(var(--glow-y) * -2%))"></div></div><a class="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&amp;_svg]:pointer-events-none [&amp;_svg]:size-4 [&amp;_svg]:shrink-0 relative bg-primary text-primary-foreground shadow hover:bg-primary/90 px-4 py-2 group transition-all w-full cursor-pointer h-full relative" href="https://app.graphite.com/signup">Sign up<div class="size-3 sm:size-4 overflow-hidden relative"><div class="group-hover:translate-x-0 transition-transform -translate-x-1/2 flex items-center duration-500 absolute fit h-full left-0 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:size-3"><svg width="12" height="10" viewBox="0 0 12 10" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M5.8965 1.208L8.9525 4.248H0.9205V5.432H8.9525L5.9125 8.488L6.6805 9.256L11.0805 4.84L6.6645 0.424L5.8965 1.208Z" fill="currentColor"></path></svg><svg width="12" height="10" viewBox="0 0 12 10" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M5.8965 1.208L8.9525 4.248H0.9205V5.432H8.9525L5.9125 8.488L6.6805 9.256L11.0805 4.84L6.6645 0.424L5.8965 1.208Z" fill="currentColor"></path></svg></div></div><div class="rounded-[inherit] absolute inset-0 p-[var(--padding,1px)] pointer-events-none" style="mask:linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);mask-composite:exclude"><div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 aspect-[1/1] min-h-full min-w-full scale-[1.2]"><div class="absolute size-full group-hover:rotate-[360deg] rotate-[0deg] bg-[conic-gradient(from_0deg,#3cb091,#1495c7,#6666c1,#efae0f,#3cb091)] dark:opacity-100 opacity-50 transition-transform duration-700"></div></div></div></a></div></div><div class="lg:hidden flex items-center justify-self-end w-fit"><button type="button" aria-haspopup="dialog" aria-expanded="false" aria-controls="radix-:Raaak6:" data-state="closed" class="flex gap-2 items-center p-2 data-[state=open]:opacity-0 data-[state=open]:pointer-events-none relative"><span class="sr-only">Menu</span><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-menu size-4" aria-hidden="true"><path d="M4 12h16"></path><path d="M4 18h16"></path><path d="M4 6h16"></path></svg></button></div></div></div></div></header><main id="main-content"><section id="hero" class="relative overflow-x-clip mb-2 z-20"><div class="grid-container z-10"><div class="size-0.5 bg-primary absolute bottom-0 left-2"></div><div class="size-0.5 bg-primary absolute bottom-0 right-2"></div><div class="w-full col-span-full flex flex-col space-y-4 body-base pt-18 lg:pt-24 lg:grid-container lg:px-0"><div class="flex lg:flex-col lg:col-span-3 lg:m-0"><a class="w-fit text-primary/50 hover:text-primary transition-colors duration-300" href="/blog">Blog</a><div class="flex lg:gap-1 items-baseline"><svg width="12" height="10" viewBox="0 0 12 10" fill="currentColor" xmlns="http://www.w3.org/2000/svg" class="lg:hidden mx-2 size-3 text-primary/30"><path d="M5.8965 1.208L8.9525 4.248H0.9205V5.432H8.9525L5.9125 8.488L6.6805 9.256L11.0805 4.84L6.6645 0.424L5.8965 1.208Z" fill="currentColor"></path></svg><div aria-hidden="true" class="max-lg:hidden aspect-[2/5] w-2 shrink-0 border-l border-b border-primary/30 rounded-bl-xs"></div><a class="text-primary/50 hover:text-primary transition-colors duration-300" href="/blog?category=engineering">Engineering</a></div></div><h1 class="heading-lg text-left text-balance lg:col-span-8 lg:col-start-5 lg:m-0">How we sped up code search for Graphite Chat </h1><div class="flex justify-between items-end mt-16 border-b pb-2 text-primary/50 gap-8 lg:col-span-full lg:mt-10"><div class="flex flex-col gap-1"><img alt="author" loading="lazy" width="32" height="32" decoding="async" data-nimg="1" class="rounded-xs aspect-[3/4] object-cover lg:w-10 bg-primary" style="color:transparent" sizes="(max-width: 767px) 10, (max-width: 1024px) 10, 10" srcSet="/_next/image?url=https%3A%2F%2Fwww.datocms-assets.com%2F85246%2F1757535817-img_8626.jpg&amp;w=16&amp;q=75 16w, /_next/image?url=https%3A%2F%2Fwww.datocms-assets.com%2F85246%2F1757535817-img_8626.jpg&amp;w=32&amp;q=75 32w, /_next/image?url=https%3A%2F%2Fwww.datocms-assets.com%2F85246%2F1757535817-img_8626.jpg&amp;w=48&amp;q=75 48w, /_next/image?url=https%3A%2F%2Fwww.datocms-assets.com%2F85246%2F1757535817-img_8626.jpg&amp;w=64&amp;q=75 64w, /_next/image?url=https%3A%2F%2Fwww.datocms-assets.com%2F85246%2F1757535817-img_8626.jpg&amp;w=96&amp;q=75 96w, /_next/image?url=https%3A%2F%2Fwww.datocms-assets.com%2F85246%2F1757535817-img_8626.jpg&amp;w=128&amp;q=75 128w, /_next/image?url=https%3A%2F%2Fwww.datocms-assets.com%2F85246%2F1757535817-img_8626.jpg&amp;w=256&amp;q=75 256w, /_next/image?url=https%3A%2F%2Fwww.datocms-assets.com%2F85246%2F1757535817-img_8626.jpg&amp;w=384&amp;q=75 384w, /_next/image?url=https%3A%2F%2Fwww.datocms-assets.com%2F85246%2F1757535817-img_8626.jpg&amp;w=640&amp;q=75 640w, /_next/image?url=https%3A%2F%2Fwww.datocms-assets.com%2F85246%2F1757535817-img_8626.jpg&amp;w=750&amp;q=75 750w, /_next/image?url=https%3A%2F%2Fwww.datocms-assets.com%2F85246%2F1757535817-img_8626.jpg&amp;w=828&amp;q=75 828w, /_next/image?url=https%3A%2F%2Fwww.datocms-assets.com%2F85246%2F1757535817-img_8626.jpg&amp;w=1080&amp;q=75 1080w, /_next/image?url=https%3A%2F%2Fwww.datocms-assets.com%2F85246%2F1757535817-img_8626.jpg&amp;w=1200&amp;q=75 1200w, /_next/image?url=https%3A%2F%2Fwww.datocms-assets.com%2F85246%2F1757535817-img_8626.jpg&amp;w=1920&amp;q=75 1920w, /_next/image?url=https%3A%2F%2Fwww.datocms-assets.com%2F85246%2F1757535817-img_8626.jpg&amp;w=2048&amp;q=75 2048w, /_next/image?url=https%3A%2F%2Fwww.datocms-assets.com%2F85246%2F1757535817-img_8626.jpg&amp;w=3840&amp;q=75 3840w" src="/_next/image?url=https%3A%2F%2Fwww.datocms-assets.com%2F85246%2F1757535817-img_8626.jpg&amp;w=3840&amp;q=75"/><p class="">Brandon Willett</p></div><p class="tabular-nums [word-spacing:-0.25em]">Sep 9, 2025</p></div></div></div></section><section id="content"><div class="grid-container"><aside class="col-span-full max-lg:border-b border-border lg:col-span-3 max-h-[calc(100vh-4.5rem)] sticky top-0 lg:top-18 flex flex-col gap-8 justify-between max-lg:pt-18 max-lg:-mt-18 max-lg:top-0 max-lg:z-10 max-lg:bg-background max-lg:pb-2"><div class="lg:z-10 lg:pt-4 lg:sticky lg:top-18 lg:pb-24"><div data-open="false" data-in-page-nav="true" class="group/in-page-nav relative"><div class="relative z-10"><h2 class="body-base flex items-center gap-2 pointer-events-none z-20 relative w-fit"><div aria-hidden="true" class="absolute -z-10 -inset-x-3 -inset-y-1 rounded-lg group-has-hover/in-page-nav:bg-secondary/50 transition-colors duration-200 ease-(--ease-glide)"></div>In this article <div aria-hidden="true" class="pointer-events-none size-2 relative group-data-[open=true]/in-page-nav:rotate-90 transition-transform duration-600 ease-(--ease-glide)"><div class="w-full h-px bg-primary absolute top-1/2 left-1/2 -translate-1/2 group-data-[open=true]/in-page-nav:opacity-0 transition-opacity duration-300 ease-(--ease-glide)"></div><div class="w-px h-full bg-primary absolute top-1/2 left-1/2 -translate-1/2"></div></div></h2><div class="flex gap-1 items-baseline lg:absolute lg:top-full pointer-events-none"><div class="aspect-[2/5] z-20 w-2 shrink-0 border-l border-b border-primary/30 rounded-bl-xs group-data-[open=true]/in-page-nav:opacity-0 group-data-[open=true]/in-page-nav:rounded-none delay-100 group-data-[open=true]/in-page-nav:delay-0 transition-border-color duration-300 ease-(--ease-glide)"></div><ul class="grid w-full items-start overflow-hidden group-data-[open=true]/in-page-nav:opacity-0 group-data-[open=true]/in-page-nav:translate-y-1 group-data-[open=true]/in-page-nav:delay-0 delay-100 transition-all duration-300 ease-(--ease-glide)"><li class="col-1 row-1 w-full overflow-hidden body-base text-primary/50 opacity-0 data-[active=true]:delay-100 data-[active=true]:opacity-100 transition-opacity duration-0 data-[active=true]:duration-300 ease-(--ease-glide)" data-active="true" aria-hidden="false"><span class="body-base block marker:tabular-nums truncate text-primary/50 hover:text-primary/70 transition-colors duration-300 ease-(--ease-glide)">Default-branch-only search isn’t enough</span></li><li class="col-1 row-1 w-full overflow-hidden body-base text-primary/50 opacity-0 data-[active=true]:delay-100 data-[active=true]:opacity-100 transition-opacity duration-0 data-[active=true]:duration-300 ease-(--ease-glide)" data-active="false" aria-hidden="true"><span class="body-base block marker:tabular-nums truncate text-primary/50 hover:text-primary/70 transition-colors duration-300 ease-(--ease-glide)">What didn’t work</span></li><li class="col-1 row-1 w-full overflow-hidden body-base text-primary/50 opacity-0 data-[active=true]:delay-100 data-[active=true]:opacity-100 transition-opacity duration-0 data-[active=true]:duration-300 ease-(--ease-glide)" data-active="false" aria-hidden="true"><span class="body-base block marker:tabular-nums truncate text-primary/50 hover:text-primary/70 transition-colors duration-300 ease-(--ease-glide)">What somewhat worked</span></li><li class="col-1 row-1 w-full overflow-hidden body-base text-primary/50 opacity-0 data-[active=true]:delay-100 data-[active=true]:opacity-100 transition-opacity duration-0 data-[active=true]:duration-300 ease-(--ease-glide)" data-active="false" aria-hidden="true"><span class="body-base block marker:tabular-nums truncate text-primary/50 hover:text-primary/70 transition-colors duration-300 ease-(--ease-glide)">Back to basics</span></li><li class="col-1 row-1 w-full overflow-hidden body-base text-primary/50 opacity-0 data-[active=true]:delay-100 data-[active=true]:opacity-100 transition-opacity duration-0 data-[active=true]:duration-300 ease-(--ease-glide)" data-active="false" aria-hidden="true"><span class="body-base block marker:tabular-nums truncate text-primary/50 hover:text-primary/70 transition-colors duration-300 ease-(--ease-glide)">The life of a search query</span></li><li class="col-1 row-1 w-full overflow-hidden body-base text-primary/50 opacity-0 data-[active=true]:delay-100 data-[active=true]:opacity-100 transition-opacity duration-0 data-[active=true]:duration-300 ease-(--ease-glide)" data-active="false" aria-hidden="true"><span class="body-base block marker:tabular-nums truncate text-primary/50 hover:text-primary/70 transition-colors duration-300 ease-(--ease-glide)">The future</span></li><li class="col-1 row-1 w-full overflow-hidden body-base text-primary/50 opacity-0 data-[active=true]:delay-100 data-[active=true]:opacity-100 transition-opacity duration-0 data-[active=true]:duration-300 ease-(--ease-glide)" data-active="false" aria-hidden="true"><span class="body-base block marker:tabular-nums truncate text-primary/50 hover:text-primary/70 transition-colors duration-300 ease-(--ease-glide)">The now</span></li></ul></div><button class="absolute -inset-x-3 -inset-y-1 z-10 cursor-pointer"><span class="sr-only">Open</span></button></div><div class="max-lg:absolute max-lg:mt-8 max-lg:pb-4 w-full bg-background top-0 left-0 group-data-[open=true]/in-page-nav:[grid-template-rows:1fr] grid [grid-template-rows:0fr] transition-all duration-300 lg:duration-600 ease-(--ease-glide)"><div class="overflow-hidden"><div class="max-h-[calc(100lvh-20rem)] overflow-scroll max-lg:scale-y-50 origin-top group-data-[open=true]/in-page-nav:scale-y-100 transition-all ease-(--ease-glide)"><div class="w-full h-4 bg-linear-to-b from-background to-transparent sticky top-0 left-0"></div><ol class="lg:mt-2 list-decimal marker:text-primary/50 marker:text-xs marker:font-medium flex flex-col gap-2 transition-all duration-600 ease-(--ease-glide)" style="padding-left:2.25ch"><li class="opacity-0 text-primary/50 data-[active=true]:text-primary group-data-[open=true]/in-page-nav:opacity-100 transition-all duration-300 ease-(--ease-glide)" data-active="true"><a href="#default-branch-only-search-isnt-enough" tabindex="-1" class="body-base block text-inherit text-balance hover:text-primary/70 transition-colors duration-300 ease-(--ease-glide)">Default-branch-only search isn’t enough</a></li><li class="opacity-0 text-primary/50 data-[active=true]:text-primary group-data-[open=true]/in-page-nav:opacity-100 transition-all duration-300 ease-(--ease-glide)" data-active="false"><a href="#what-didnt-work" tabindex="-1" class="body-base block text-inherit text-balance hover:text-primary/70 transition-colors duration-300 ease-(--ease-glide)">What didn’t work</a></li><li class="opacity-0 text-primary/50 data-[active=true]:text-primary group-data-[open=true]/in-page-nav:opacity-100 transition-all duration-300 ease-(--ease-glide)" data-active="false"><a href="#what-somewhat-worked" tabindex="-1" class="body-base block text-inherit text-balance hover:text-primary/70 transition-colors duration-300 ease-(--ease-glide)">What somewhat worked</a></li><li class="opacity-0 text-primary/50 data-[active=true]:text-primary group-data-[open=true]/in-page-nav:opacity-100 transition-all duration-300 ease-(--ease-glide)" data-active="false"><a href="#back-to-basics" tabindex="-1" class="body-base block text-inherit text-balance hover:text-primary/70 transition-colors duration-300 ease-(--ease-glide)">Back to basics</a></li><li class="opacity-0 text-primary/50 data-[active=true]:text-primary group-data-[open=true]/in-page-nav:opacity-100 transition-all duration-300 ease-(--ease-glide)" data-active="false"><a href="#the-life-of-a-search-query" tabindex="-1" class="body-base block text-inherit text-balance hover:text-primary/70 transition-colors duration-300 ease-(--ease-glide)">The life of a search query</a></li><li class="opacity-0 text-primary/50 data-[active=true]:text-primary group-data-[open=true]/in-page-nav:opacity-100 transition-all duration-300 ease-(--ease-glide)" data-active="false"><a href="#the-future" tabindex="-1" class="body-base block text-inherit text-balance hover:text-primary/70 transition-colors duration-300 ease-(--ease-glide)">The future</a></li><li class="opacity-0 text-primary/50 data-[active=true]:text-primary group-data-[open=true]/in-page-nav:opacity-100 transition-all duration-300 ease-(--ease-glide)" data-active="false"><a href="#the-now" tabindex="-1" class="body-base block text-inherit text-balance hover:text-primary/70 transition-colors duration-300 ease-(--ease-glide)">The now</a></li></ol><div class="w-full h-4 bg-linear-to-t from-background to-transparent sticky bottom-0 left-0"></div></div></div></div></div></div><div class="max-lg:fixed max-lg:bottom-0 max-lg:right-0 lg:mt-auto w-full flex max-lg:justify-center max-lg:py-4 z-10 max-lg:bg-linear-to-t max-lg:from-background max-lg:to-background/0"><button class="relative group select-none data-[copied=true]:pointer-events-none data-[error=true]:pointer-events-none p-1 cursor-pointer text-primary/50 hover:text-primary data-[error=true]:text-red-500/70 data-[error=true]:hover:text-red-500 transition-all max-lg:px-4 py-2 lg:py-4 lg:px-0 flex items-center gap-2 max-lg:bg-secondary rounded-lg max-lg:border max-lg:border-border" data-copied="false" data-error="false" aria-label="Copy code">Share<span class="sr-only" aria-hidden="false">Copy to clipboard</span><div class="relative"><div class="group-data-[copied=true]:opacity-0 group-data-[error=true]:opacity-0 py-0.5"><svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg" class="transition-colors size-5"><g clip-path="url(#clip0_224_6247)"><mask id="mask0_224_6247" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="50" height="50"><path d="M50 0H0V50H50V0Z" fill="currentColor"></path></mask><g><path d="M21.3812 35.3144L19.414 37.2816C16.7698 39.9258 12.4828 39.9258 9.83862 37.2816C7.19442 34.6374 7.19442 30.3504 9.83862 27.7062L17.2041 20.3406C19.8483 17.6964 24.1353 17.6964 26.7795 20.3406C27.8911 21.4522 28.5354 22.8543 28.7124 24.3025" stroke="currentColor" stroke-width="3.13" stroke-linecap="round" stroke-linejoin="round"></path><path d="M28.6203 14.8175L30.5875 12.8503C33.2317 10.2061 37.5187 10.2061 40.1629 12.8503C42.8071 15.4945 42.8071 19.7815 40.1629 22.4257L32.7974 29.7913C30.1532 32.4355 25.8662 32.4355 23.222 29.7913C22.1104 28.6797 21.4661 27.2776 21.2891 25.8294" stroke="currentColor" stroke-width="3.13" stroke-linecap="round" stroke-linejoin="round"></path></g></g><defs><clipPath id="clip0_224_6247"><rect width="50" height="50" fill="white"></rect></clipPath></defs></svg></div><span class="text-xs text-primary/50 absolute pointer-events-none top-1/2 -translate-y-1/3 -translate-x-1/2 left-1/2 opacity-0 group-data-[copied=true]:opacity-100 group-data-[copied=true]:-translate-y-1/2 group-data-[copied=true]:-translate-x-1/2 group-data-[copied=true]:delay-200 transition-all" aria-hidden="true"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path id="ICON_FILL" d="M14.7072 4.70712L6.00008 13.4142L1.29297 8.70712L2.70718 7.29291L6.00008 10.5858L13.293 3.29291L14.7072 4.70712Z" fill="currentColor"></path></svg></span><span class="text-xs text-red-500/70 absolute pointer-events-none top-0 right-0 opacity-0 group-data-[error=true]:opacity-100 group-data-[error=true]:delay-100 transition-opacity" aria-hidden="true">Failed</span></div></button><div aria-live="polite" aria-atomic="true" class="sr-only"></div></div></aside><article class="prose lg:prose-lg wrap-break-word prose-a:hover:text-primary prose-a:transition-colors prose-li:[&amp;_p]:my-0 prose-li:mt-0 prose-ul:list-[square] prose-light mt-5 col-span-full md:col-span-4 md:col-start-2 lg:col-span-8 lg:col-start-5 max-w-none"><div class="relative block my-5 [&amp;&gt;picture]:my-0 [&amp;&gt;picture&gt;*]:object-contain [&amp;&gt;picture&gt;*]:rounded-xs [&amp;&gt;img]:my-0" style="overflow:hidden;position:relative;width:100%;max-width:1920px"><img style="display:block;width:100%" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOTIwIiBoZWlnaHQ9IjEwODAiPjwvc3ZnPg==" aria-hidden="true" alt=""/><img aria-hidden="true" alt="" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwgHBgoICAgLDRUXDhUPDQ0NFhENDQ0YFxMZGBYVFhUaHysjGh0oHRUWJDUlKC0vMjIyGSI4PTcwPCsxMi8BCgsLDg0OFQ0QFS8cFhwvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL//AABEIAA4AGAMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAADBQEEBwD/xAAdEAACAwACAwAAAAAAAAAAAAABAwACEQRBEyEx/8QAFQEBAQAAAAAAAAAAAAAAAAAAAgD/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwDLPFQvHuOacNbE/eoiJIvuy+jlXC82EQeWiq74J0E25Yw7Jkn/2Q==" style="transition:opacity 500ms;opacity:1;position:absolute;left:-5%;top:-5%;width:110%;height:110%;max-width:none;max-height:none"/><noscript><picture><source srcSet="https://www.datocms-assets.com/85246/1757535905-082025_code-search_v1_0057.jpg?dpr=0.25&amp;fm=webp 480w,https://www.datocms-assets.com/85246/1757535905-082025_code-search_v1_0057.jpg?dpr=0.5&amp;fm=webp 960w,https://www.datocms-assets.com/85246/1757535905-082025_code-search_v1_0057.jpg?dpr=0.75&amp;fm=webp 1440w,https://www.datocms-assets.com/85246/1757535905-082025_code-search_v1_0057.jpg?fm=webp 1920w" sizes="(max-width: 1920px) 100vw, 1920px" type="image/webp"/><source srcSet="https://www.datocms-assets.com/85246/1757535905-082025_code-search_v1_0057.jpg?dpr=0.25 480w,https://www.datocms-assets.com/85246/1757535905-082025_code-search_v1_0057.jpg?dpr=0.5 960w,https://www.datocms-assets.com/85246/1757535905-082025_code-search_v1_0057.jpg?dpr=0.75 1440w,https://www.datocms-assets.com/85246/1757535905-082025_code-search_v1_0057.jpg 1920w" sizes="(max-width: 1920px) 100vw, 1920px"/><img src="https://www.datocms-assets.com/85246/1757535905-082025_code-search_v1_0057.jpg" alt="hero image" style="position:absolute;left:0;top:0;width:100%;height:100%;max-width:none;max-height:none" loading="lazy"/></picture></noscript></div><p>Searching a codebase is <em>usually</em> a pretty easy problem. You want to know what files use your <code>MAX_EMAILS_TO_SEND</code> constant? One command gets you there in milliseconds:</p><div class="[&amp;&gt;pre]:my-0 [&amp;&gt;pre]:!bg-transparent my-5 bg-secondary/70 rounded-sm border border-primary/2.5"><div class="flex items-start justify-between py-1 px-2"><p class="!m-0 md:text-sm text-primary/50 leading-5">Terminal</p><button class="relative group flex items-center select-none data-[copied=true]:pointer-events-none data-[error=true]:pointer-events-none p-1 cursor-pointer text-primary/50 hover:text-primary data-[error=true]:text-red-500/70 data-[error=true]:hover:text-red-500 transition-all gap-2" data-copied="false" data-error="false" aria-label="Copy code"><span class="sr-only" aria-hidden="false">Copy to clipboard</span><div class="relative"><div class="group-data-[copied=true]:opacity-0 group-data-[error=true]:opacity-0 py-0.5"><svg aria-hidden="true" viewBox="0 0 16 16" class="transition-colors size-4"><path fill="currentColor" d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path fill="currentColor" d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg></div><span class="text-xs text-primary/50 absolute pointer-events-none top-1/2 -translate-y-1/3 -translate-x-1/2 left-1/2 opacity-0 group-data-[copied=true]:opacity-100 group-data-[copied=true]:-translate-y-1/2 group-data-[copied=true]:-translate-x-1/2 group-data-[copied=true]:delay-200 transition-all" aria-hidden="true"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path id="ICON_FILL" d="M14.7072 4.70712L6.00008 13.4142L1.29297 8.70712L2.70718 7.29291L6.00008 10.5858L13.293 3.29291L14.7072 4.70712Z" fill="currentColor"></path></svg></span><span class="text-xs text-red-500/70 absolute pointer-events-none top-0 right-0 opacity-0 group-data-[error=true]:opacity-100 group-data-[error=true]:delay-100 transition-opacity" aria-hidden="true">Failed</span></div></button><div aria-live="polite" aria-atomic="true" class="sr-only"></div></div><pre class="prism-code language-bash text-primary/50" style="color:#FFFFFF;background-color:#171717"><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token function" style="color:#6DCBFF">grep</span><span class="token plain"> -r MAX_EMAILS_TO_SEND </span><span class="token builtin class-name" style="color:#6DCBFF">.</span></span></div></pre></div><p>Modern tools like <a href="https://github.com/BurntSushi/ripgrep"><code>ripgrep</code></a> make it even faster. But this simplicity depends on a couple of things being true:</p><ul><li><p>Your files all reside on a (hopefully) fast disk.</p></li><li><p>There aren&#x27;t too many of them.</p></li></ul><p>When building out a code search tool for the agentic <a target="_blank" href="https://graphite.dev/docs/graphite-chat">Graphite Chat</a>, we immediately ran into both of these limitations. We needed to support searches across hundreds of thousands (or millions) of files, at any commit, without maintaining a whole traditional VM+disk for each one. Could <code>grep</code> even support that kind of use case?</p><p>Let’s find out!</p><h2 id="default-branch-only-search-isnt-enough">Default-branch-only search isn’t enough</h2><p>You might read this and think: What&#x27;s supposed to be novel here? We&#x27;ve had fast code search via API for big repositories for years now. <a target="_blank" href="https://sourcegraph.com/">Sourcegraph</a> made a whole company out of the idea, and GitHub even gives you something similar for free.</p><p>True, but only on the <em>default</em> branch. GitHub’s API docs are explicit:</p><blockquote><p>Only the <em>default branch</em> is considered. In most cases, this will be the <code>main</code> branch.</p></blockquote><p>And Sourcegraph, while it’s closed-source now, still has an archive of their documentation and code as it stood in 2023, which details <a target="_blank" href="https://github.com/sourcegraph/sourcegraph-public-snapshot/blob/main/doc/dev/background-information/architecture/index.md">the same thing</a>:</p><blockquote><p>Sourcegraph also has a fast search path for code that isn&#x27;t indexed yet, or for code that will never be indexed (for example: code that is not on a default branch). Indexing every branch of every repository isn&#x27;t a pragmatic use of resources for most customers, so this decision balances optimizing the common case (searching all default branches) with space savings (not indexing everything).</p><p>…</p><p>Provides on-demand unindexed search for repositories. It scans through a git archive fetched from gitserver to find results, similar in nature to <code>git grep</code>.</p></blockquote><p>The searches our model makes almost never target <code>main</code>; they’re against arbitrary commits. For us, fast search <em>at any commit</em> was the requirement, and that turned out to be a much harder problem.</p><h2 id="what-didnt-work">What didn’t work</h2><p>In the spirit of <a target="_blank" href="https://en.wikipedia.org/wiki/KISS_principle">KISS</a> (or “<a target="_blank" href="https://boringtechnology.club">Choose Boring Technology</a>”, or “<a target="_blank" href="https://grugbrain.dev">The Grug Brained Developer</a>”, feel free to pick your favorite decade’s spin on the idea), we figured our first attempt at a solution should also be the most straightforward: a plain old <code>git grep</code> on the repository. If that worked, then we could save ourselves a lot of time.</p><p>We spent a week running experiments on several block-based storage solutions on AWS:</p><ul><li><p>On-demand AWS Lambdas to execute searches via one shared EFS volume.</p></li><li><p>An ECS cluster where tasks dynamically mount per-repo EFS volumes at query time.</p></li><li><p>Persistent EC2 instances which use (faster) EBS with <a target="_blank" href="https://docs.aws.amazon.com/ebs/latest/userguide/ebs-volumes-multi.html">multi-attach</a> for horizontal scaling.</p></li></ul><p>We saw some interesting results here, for example, we measured the EBS-mounted volumes to consistently perform I/O intensive operations (like searches) about 3x as fast as EFS-mounted ones. From a test we ran searching for a string in the <code>react-native</code> repository:</p><div class="[&amp;&gt;pre]:my-0 [&amp;&gt;pre]:!bg-transparent my-5 bg-secondary/70 rounded-sm border border-primary/2.5"><div class="flex items-start justify-between py-1 px-2"><p class="!m-0 md:text-sm text-primary/50 leading-5">Terminal</p><button class="relative group flex items-center select-none data-[copied=true]:pointer-events-none data-[error=true]:pointer-events-none p-1 cursor-pointer text-primary/50 hover:text-primary data-[error=true]:text-red-500/70 data-[error=true]:hover:text-red-500 transition-all gap-2" data-copied="false" data-error="false" aria-label="Copy code"><span class="sr-only" aria-hidden="false">Copy to clipboard</span><div class="relative"><div class="group-data-[copied=true]:opacity-0 group-data-[error=true]:opacity-0 py-0.5"><svg aria-hidden="true" viewBox="0 0 16 16" class="transition-colors size-4"><path fill="currentColor" d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path fill="currentColor" d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg></div><span class="text-xs text-primary/50 absolute pointer-events-none top-1/2 -translate-y-1/3 -translate-x-1/2 left-1/2 opacity-0 group-data-[copied=true]:opacity-100 group-data-[copied=true]:-translate-y-1/2 group-data-[copied=true]:-translate-x-1/2 group-data-[copied=true]:delay-200 transition-all" aria-hidden="true"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path id="ICON_FILL" d="M14.7072 4.70712L6.00008 13.4142L1.29297 8.70712L2.70718 7.29291L6.00008 10.5858L13.293 3.29291L14.7072 4.70712Z" fill="currentColor"></path></svg></span><span class="text-xs text-red-500/70 absolute pointer-events-none top-0 right-0 opacity-0 group-data-[error=true]:opacity-100 group-data-[error=true]:delay-100 transition-opacity" aria-hidden="true">Failed</span></div></button><div aria-live="polite" aria-atomic="true" class="sr-only"></div></div><pre class="prism-code language-bash text-primary/50" style="color:#FFFFFF;background-color:#171717"><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token comment" style="color:#909090"># EBS</span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain" style="display:inline-block">
</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain">Performance counter stats </span><span class="token keyword" style="color:#6DCBFF">for</span><span class="token plain"> </span><span class="token string" style="color:#FFA882">&#x27;git grep interactionManager 8f1ae53&#x27;</span><span class="token builtin class-name" style="color:#6DCBFF">:</span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain" style="display:inline-block">
</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token number">17,541</span><span class="token plain"> minor-faults </span><span class="token comment" style="color:#909090"># 0.062 M/sec </span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token number">878</span><span class="token plain"> major-faults </span><span class="token comment" style="color:#909090"># 0.003 M/sec </span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token number">282.34</span><span class="token plain"> msec task-clock </span><span class="token comment" style="color:#909090"># 0.184 CPUs utilized </span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain" style="display:inline-block">
</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"></span><span class="token number">1.535785602</span><span class="token plain"> seconds </span><span class="token function" style="color:#6DCBFF">time</span><span class="token plain"> elapsed</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain" style="display:inline-block">
</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"></span><span class="token number">0.208365000</span><span class="token plain"> seconds user</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"></span><span class="token number">0.075011000</span><span class="token plain"> seconds sys</span></span></div></pre></div><div class="[&amp;&gt;pre]:my-0 [&amp;&gt;pre]:!bg-transparent my-5 bg-secondary/70 rounded-sm border border-primary/2.5"><div class="flex items-start justify-between py-1 px-2"><p class="!m-0 md:text-sm text-primary/50 leading-5">Terminal</p><button class="relative group flex items-center select-none data-[copied=true]:pointer-events-none data-[error=true]:pointer-events-none p-1 cursor-pointer text-primary/50 hover:text-primary data-[error=true]:text-red-500/70 data-[error=true]:hover:text-red-500 transition-all gap-2" data-copied="false" data-error="false" aria-label="Copy code"><span class="sr-only" aria-hidden="false">Copy to clipboard</span><div class="relative"><div class="group-data-[copied=true]:opacity-0 group-data-[error=true]:opacity-0 py-0.5"><svg aria-hidden="true" viewBox="0 0 16 16" class="transition-colors size-4"><path fill="currentColor" d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path fill="currentColor" d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg></div><span class="text-xs text-primary/50 absolute pointer-events-none top-1/2 -translate-y-1/3 -translate-x-1/2 left-1/2 opacity-0 group-data-[copied=true]:opacity-100 group-data-[copied=true]:-translate-y-1/2 group-data-[copied=true]:-translate-x-1/2 group-data-[copied=true]:delay-200 transition-all" aria-hidden="true"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path id="ICON_FILL" d="M14.7072 4.70712L6.00008 13.4142L1.29297 8.70712L2.70718 7.29291L6.00008 10.5858L13.293 3.29291L14.7072 4.70712Z" fill="currentColor"></path></svg></span><span class="text-xs text-red-500/70 absolute pointer-events-none top-0 right-0 opacity-0 group-data-[error=true]:opacity-100 group-data-[error=true]:delay-100 transition-opacity" aria-hidden="true">Failed</span></div></button><div aria-live="polite" aria-atomic="true" class="sr-only"></div></div><pre class="prism-code language-bash text-primary/50" style="color:#FFFFFF;background-color:#171717"><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token comment" style="color:#909090"># EFS</span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain" style="display:inline-block">
</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain">Performance counter stats </span><span class="token keyword" style="color:#6DCBFF">for</span><span class="token plain"> </span><span class="token string" style="color:#FFA882">&#x27;git grep interactionManager 8f1ae53&#x27;</span><span class="token builtin class-name" style="color:#6DCBFF">:</span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain" style="display:inline-block">
</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token number">17,620</span><span class="token plain"> minor-faults </span><span class="token comment" style="color:#909090"># 0.050 M/sec </span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token number">53</span><span class="token plain"> major-faults </span><span class="token comment" style="color:#909090"># 0.149 K/sec </span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token number">354.59</span><span class="token plain"> msec task-clock </span><span class="token comment" style="color:#909090"># 0.078 CPUs utilized </span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain" style="display:inline-block">
</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"></span><span class="token number">4.560184652</span><span class="token plain"> seconds </span><span class="token function" style="color:#6DCBFF">time</span><span class="token plain"> elapsed</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain" style="display:inline-block">
</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"></span><span class="token number">0.212312000</span><span class="token plain"> seconds user</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"></span><span class="token number">0.129052000</span><span class="token plain"> seconds sys</span></span></div></pre></div><p>However, in spite of the individual advantages each had over the others, they all buckled in the same place: large repositories.</p><p>While <code>react-native</code> is a decently-sized repo by most measures, it only has a few thousand files:</p><div class="[&amp;&gt;pre]:my-0 [&amp;&gt;pre]:!bg-transparent my-5 bg-secondary/70 rounded-sm border border-primary/2.5"><div class="flex items-start justify-between py-1 px-2"><p class="!m-0 md:text-sm text-primary/50 leading-5">Terminal</p><button class="relative group flex items-center select-none data-[copied=true]:pointer-events-none data-[error=true]:pointer-events-none p-1 cursor-pointer text-primary/50 hover:text-primary data-[error=true]:text-red-500/70 data-[error=true]:hover:text-red-500 transition-all gap-2" data-copied="false" data-error="false" aria-label="Copy code"><span class="sr-only" aria-hidden="false">Copy to clipboard</span><div class="relative"><div class="group-data-[copied=true]:opacity-0 group-data-[error=true]:opacity-0 py-0.5"><svg aria-hidden="true" viewBox="0 0 16 16" class="transition-colors size-4"><path fill="currentColor" d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path fill="currentColor" d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg></div><span class="text-xs text-primary/50 absolute pointer-events-none top-1/2 -translate-y-1/3 -translate-x-1/2 left-1/2 opacity-0 group-data-[copied=true]:opacity-100 group-data-[copied=true]:-translate-y-1/2 group-data-[copied=true]:-translate-x-1/2 group-data-[copied=true]:delay-200 transition-all" aria-hidden="true"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path id="ICON_FILL" d="M14.7072 4.70712L6.00008 13.4142L1.29297 8.70712L2.70718 7.29291L6.00008 10.5858L13.293 3.29291L14.7072 4.70712Z" fill="currentColor"></path></svg></span><span class="text-xs text-red-500/70 absolute pointer-events-none top-0 right-0 opacity-0 group-data-[error=true]:opacity-100 group-data-[error=true]:delay-100 transition-opacity" aria-hidden="true">Failed</span></div></button><div aria-live="polite" aria-atomic="true" class="sr-only"></div></div><pre class="prism-code language-bash text-primary/50" style="color:#FFFFFF;background-color:#171717"><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain">$ </span><span class="token function" style="color:#6DCBFF">git</span><span class="token plain"> ls-files </span><span class="token operator">|</span><span class="token plain"> </span><span class="token function" style="color:#6DCBFF">wc</span><span class="token plain"> -l</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token number">7019</span></span></div></pre></div><p>We need to support repositories hundreds of times this size, and in cases like that, we actually end up at the mercy of the Linux page cache. The <code>major-faults</code> rows in the snippets above represent times the <code>grep</code> process needed to actually reach out to the disk for blocks, and for sample large codebases we tested, searches only returned “fast enough” (under 10 seconds) when <code>major-faults</code> was 0 (for instance, when the same search is run twice in a row). In other words, searches are fast only when the <em>entire repository</em> is already in the page cache.</p><p>At this point, the <code>grep</code> operation becomes mostly CPU bound, and perhaps unsurprisingly, this is also where EFS and EBS see their performance disparity vanish:</p><div class="[&amp;&gt;pre]:my-0 [&amp;&gt;pre]:!bg-transparent my-5 bg-secondary/70 rounded-sm border border-primary/2.5"><div class="flex items-start justify-between py-1 px-2"><p class="!m-0 md:text-sm text-primary/50 leading-5">Terminal</p><button class="relative group flex items-center select-none data-[copied=true]:pointer-events-none data-[error=true]:pointer-events-none p-1 cursor-pointer text-primary/50 hover:text-primary data-[error=true]:text-red-500/70 data-[error=true]:hover:text-red-500 transition-all gap-2" data-copied="false" data-error="false" aria-label="Copy code"><span class="sr-only" aria-hidden="false">Copy to clipboard</span><div class="relative"><div class="group-data-[copied=true]:opacity-0 group-data-[error=true]:opacity-0 py-0.5"><svg aria-hidden="true" viewBox="0 0 16 16" class="transition-colors size-4"><path fill="currentColor" d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path fill="currentColor" d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg></div><span class="text-xs text-primary/50 absolute pointer-events-none top-1/2 -translate-y-1/3 -translate-x-1/2 left-1/2 opacity-0 group-data-[copied=true]:opacity-100 group-data-[copied=true]:-translate-y-1/2 group-data-[copied=true]:-translate-x-1/2 group-data-[copied=true]:delay-200 transition-all" aria-hidden="true"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path id="ICON_FILL" d="M14.7072 4.70712L6.00008 13.4142L1.29297 8.70712L2.70718 7.29291L6.00008 10.5858L13.293 3.29291L14.7072 4.70712Z" fill="currentColor"></path></svg></span><span class="text-xs text-red-500/70 absolute pointer-events-none top-0 right-0 opacity-0 group-data-[error=true]:opacity-100 group-data-[error=true]:delay-100 transition-opacity" aria-hidden="true">Failed</span></div></button><div aria-live="polite" aria-atomic="true" class="sr-only"></div></div><pre class="prism-code language-bash text-primary/50" style="color:#FFFFFF;background-color:#171717"><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain">Performance counter stats </span><span class="token keyword" style="color:#6DCBFF">for</span><span class="token plain"> </span><span class="token string" style="color:#FFA882">&#x27;git grep interactionManager 8f1ae53&#x27;</span><span class="token builtin class-name" style="color:#6DCBFF">:</span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain" style="display:inline-block">
</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token number">17,667</span><span class="token plain"> minor-faults </span><span class="token comment" style="color:#909090"># 0.071 M/sec </span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token number">0</span><span class="token plain"> major-faults </span><span class="token comment" style="color:#909090"># 0.000 K/sec </span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token number">248.55</span><span class="token plain"> msec task-clock </span><span class="token comment" style="color:#909090"># 0.957 CPUs utilized </span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain" style="display:inline-block">
</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"></span><span class="token number">0.259805935</span><span class="token plain"> seconds </span><span class="token function" style="color:#6DCBFF">time</span><span class="token plain"> elapsed</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain" style="display:inline-block">
</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"></span><span class="token number">0.208592000</span><span class="token plain"> seconds user</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"></span><span class="token number">0.040113000</span><span class="token plain"> seconds sys</span></span></div></pre></div><p>Of course, the only way of ensuring that every block needed for a search is already in the page cache when the search comes in, is to have a crystal ball, which we can’t afford.</p><p>So, we have to look into some more earthly solutions!</p><h2 id="what-somewhat-worked">What somewhat worked</h2><p>If we can&#x27;t brute-force our way through a big repository with <code>grep</code>, then it looks like we&#x27;ll need to do some indexing.</p><p>We tested loading the repository’s files into <a target="_blank" href="https://www.elastic.co/">Elasticsearch</a>, which tokenizes documents and executes keyword queries quickly. The results were promising:</p><div class="[&amp;&gt;pre]:my-0 [&amp;&gt;pre]:!bg-transparent my-5 bg-secondary/70 rounded-sm border border-primary/2.5"><div class="flex items-start justify-between py-1 px-2"><p class="!m-0 md:text-sm text-primary/50 leading-5">Terminal</p><button class="relative group flex items-center select-none data-[copied=true]:pointer-events-none data-[error=true]:pointer-events-none p-1 cursor-pointer text-primary/50 hover:text-primary data-[error=true]:text-red-500/70 data-[error=true]:hover:text-red-500 transition-all gap-2" data-copied="false" data-error="false" aria-label="Copy code"><span class="sr-only" aria-hidden="false">Copy to clipboard</span><div class="relative"><div class="group-data-[copied=true]:opacity-0 group-data-[error=true]:opacity-0 py-0.5"><svg aria-hidden="true" viewBox="0 0 16 16" class="transition-colors size-4"><path fill="currentColor" d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 0 1 0 1.5h-1.5a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-1.5a.75.75 0 0 1 1.5 0v1.5A1.75 1.75 0 0 1 9.25 16h-7.5A1.75 1.75 0 0 1 0 14.25Z"></path><path fill="currentColor" d="M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0 1 14.25 11h-7.5A1.75 1.75 0 0 1 5 9.25Zm1.75-.25a.25.25 0 0 0-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 0 0 .25-.25v-7.5a.25.25 0 0 0-.25-.25Z"></path></svg></div><span class="text-xs text-primary/50 absolute pointer-events-none top-1/2 -translate-y-1/3 -translate-x-1/2 left-1/2 opacity-0 group-data-[copied=true]:opacity-100 group-data-[copied=true]:-translate-y-1/2 group-data-[copied=true]:-translate-x-1/2 group-data-[copied=true]:delay-200 transition-all" aria-hidden="true"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"><path id="ICON_FILL" d="M14.7072 4.70712L6.00008 13.4142L1.29297 8.70712L2.70718 7.29291L6.00008 10.5858L13.293 3.29291L14.7072 4.70712Z" fill="currentColor"></path></svg></span><span class="text-xs text-red-500/70 absolute pointer-events-none top-0 right-0 opacity-0 group-data-[error=true]:opacity-100 group-data-[error=true]:delay-100 transition-opacity" aria-hidden="true">Failed</span></div></button><div aria-live="polite" aria-atomic="true" class="sr-only"></div></div><pre class="prism-code language-bash text-primary/50" style="color:#FFFFFF;background-color:#171717"><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain">$ </span><span class="token function" style="color:#6DCBFF">cat</span><span class="token plain"> search.json </span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"></span><span class="token punctuation" style="color:#6DCBFF">{</span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token string" style="color:#FFA882">&quot;query&quot;</span><span class="token builtin class-name" style="color:#6DCBFF">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#6DCBFF">{</span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token string" style="color:#FFA882">&quot;wildcard&quot;</span><span class="token builtin class-name" style="color:#6DCBFF">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#6DCBFF">{</span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token string" style="color:#FFA882">&quot;content&quot;</span><span class="token builtin class-name" style="color:#6DCBFF">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#6DCBFF">{</span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token string" style="color:#FFA882">&quot;value&quot;</span><span class="token builtin class-name" style="color:#6DCBFF">:</span><span class="token plain"> </span><span class="token string" style="color:#FFA882">&quot;*interactionManager*&quot;</span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token punctuation" style="color:#6DCBFF">}</span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token punctuation" style="color:#6DCBFF">}</span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token punctuation" style="color:#6DCBFF">}</span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"></span><span class="token punctuation" style="color:#6DCBFF">}</span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain" style="display:inline-block">
</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain">$ https GET </span><span class="token operator">&lt;</span><span class="token plain">elastic-endpoint</span><span class="token operator">&gt;</span><span class="token plain">/blobs/_search?size</span><span class="token operator">=</span><span class="token number">100</span><span class="token plain"> </span><span class="token operator">&lt;</span><span class="token plain"> search.json </span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"></span><span class="token punctuation" style="color:#6DCBFF">{</span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token string" style="color:#FFA882">&quot;hits&quot;</span><span class="token builtin class-name" style="color:#6DCBFF">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#6DCBFF">{</span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token string" style="color:#FFA882">&quot;hits&quot;</span><span class="token builtin class-name" style="color:#6DCBFF">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#6DCBFF">[</span><span class="token punctuation" style="color:#6DCBFF">..</span><span class="token plain">.</span><span class="token punctuation" style="color:#6DCBFF">]</span><span class="token plain">,</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token string" style="color:#FFA882">&quot;max_score&quot;</span><span class="token builtin class-name" style="color:#6DCBFF">:</span><span class="token plain"> </span><span class="token number">1.0</span><span class="token plain">,</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token string" style="color:#FFA882">&quot;total&quot;</span><span class="token builtin class-name" style="color:#6DCBFF">:</span><span class="token plain"> </span><span class="token punctuation" style="color:#6DCBFF">{</span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token string" style="color:#FFA882">&quot;relation&quot;</span><span class="token builtin class-name" style="color:#6DCBFF">:</span><span class="token plain"> </span><span class="token string" style="color:#FFA882">&quot;eq&quot;</span><span class="token plain">,</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token string" style="color:#FFA882">&quot;value&quot;</span><span class="token builtin class-name" style="color:#6DCBFF">:</span><span class="token plain"> </span><span class="token number">83</span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token punctuation" style="color:#6DCBFF">}</span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token punctuation" style="color:#6DCBFF">}</span><span class="token plain">,</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token string" style="color:#FFA882">&quot;timed_out&quot;</span><span class="token builtin class-name" style="color:#6DCBFF">:</span><span class="token plain"> false,</span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"> </span><span class="token string" style="color:#FFA882">&quot;took&quot;</span><span class="token builtin class-name" style="color:#6DCBFF">:</span><span class="token plain"> </span><span class="token number">79</span><span class="token plain"></span></span></div><div class="token-line console-module-scss-module__Sy3VUW__line" style="color:#FFFFFF"><span class="console-module-scss-module__Sy3VUW__line-content"><span class="token plain"></span><span class="token punctuation" style="color:#6DCBFF">}</span></span></div></pre></div><p>Even using a tiny node type (<a target="_blank" href="https://instances.vantage.sh/aws/opensearch/i4g.large.search"><code>i4g.large.search</code></a>), we saw searches over even huge repositories taking well under 500ms. And that&#x27;s with a cluster of just one node; we could easily split the dataset into shards (ES manages this on its own) such that 10 different nodes handle 1/10 of the files each, and our searches would be even faster.</p><p>Problem solved, right? Not quite. What we just tried with Elasticsearch worked great for <em>one commit</em>, but our requirement was fast search at <em>any commit</em>. The direct approach would be to index the repo’s state at each commit, for easy lookups, but — multiply thousands of repos by thousands of files by thousands of commits, and suddenly you’re managing tens of billions of documents. Running a cluster of that size would be prohibitively complex and expensive.</p><p>So, is the “document database” idea dead-on-arrival?</p><h2 id="back-to-basics">Back to basics</h2><p>When looking at the problem through the above lens (the challenge of efficiently managing thousands of files, each with potentially thousands of versions), there <em>is</em> one database that&#x27;s relevant to the discussion: namely, Git itself!</p><p>A Git repository seems to store an entire copy of the repository at each commit of a <a target="_blank" href="https://github.com/torvalds/linux">potentially-decades-long history</a>, but does so without terabytes of disk space. This led us to wonder, &quot;how does it do that, and can we somehow adapt that approach to work with a document search database instead of a filesystem?&quot;</p><p>For the &quot;how&quot; question, it&#x27;s honestly very clever if you haven&#x27;t <a target="_blank" href="https://git-scm.com/book/en/v2/Git-Internals-Git-Objects">read about it</a> before. The short version is, Git splits the data it stores into several different kinds of objects:</p><ol><li><p><strong>Blobs</strong> → raw file contents, <a target="_blank" href="https://en.wikipedia.org/wiki/Content-addressable_storage">content-addressed</a>.</p></li><li><p><strong>Trees</strong> → lists of blob IDs at a given commit.</p></li></ol><p>And as for the &quot;can we&quot; question, it turns out, yes absolutely!</p><h2 id="the-life-of-a-search-query">The life of a search query</h2><p>The key change was that, like Git, we needed to start storing two kinds of objects instead of just one: the blobs and trees. Then, when it comes time to perform a search, we execute 2 queries:</p><ol><li><p>Get the tree object for the commit SHA specified in the query.</p></li><li><p>Get <em>all</em> blobs that match the search term specified in the query.</p></li></ol><p>And then, in memory, we filter the results from (2) based on the blob IDs in the result of (1), such that we only return files which are actually in-scope for the request. Easy!</p><div class="relative block my-5 [&amp;&gt;picture]:my-0 [&amp;&gt;picture&gt;*]:object-contain [&amp;&gt;picture&gt;*]:rounded-xs [&amp;&gt;img]:my-0" style="overflow:hidden;position:relative;width:100%;max-width:1554px"><img style="display:block;width:100%" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTU0IiBoZWlnaHQ9IjEyMzQiPjwvc3ZnPg==" aria-hidden="true" alt=""/><img aria-hidden="true" alt="" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwYHDQcHBgYGCgYICQ4HDgYGBREJCgcNFx8ZGBYTFhUaHysjGh0oHSEWJDUlKC0vMjIyGSI4PTcwPCsxMi8BCgsLDQ0OFxAOFS8cFhwvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL//AABEIABQAGAMBIgACEQEDEQH/xAAYAAEBAAMAAAAAAAAAAAAAAAAAAQIDB//EABUQAQEAAAAAAAAAAAAAAAAAAAAB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAwEC/8QAFREBAQAAAAAAAAAAAAAAAAAAAAL/2gAMAwEAAhEDEQA/AOtLEixumWQAla4ygGpFUAq//9k=" style="transition:opacity 500ms;opacity:1;position:absolute;left:-5%;top:-5%;width:110%;height:110%;max-width:none;max-height:none"/><noscript><picture><source srcSet="https://www.datocms-assets.com/85246/1757535508-before-drawio-4.png?dpr=0.25&amp;fm=webp 388w,https://www.datocms-assets.com/85246/1757535508-before-drawio-4.png?dpr=0.5&amp;fm=webp 777w,https://www.datocms-assets.com/85246/1757535508-before-drawio-4.png?dpr=0.75&amp;fm=webp 1165w,https://www.datocms-assets.com/85246/1757535508-before-drawio-4.png?fm=webp 1554w" sizes="(max-width: 1554px) 100vw, 1554px" type="image/webp"/><source srcSet="https://www.datocms-assets.com/85246/1757535508-before-drawio-4.png?dpr=0.25 388w,https://www.datocms-assets.com/85246/1757535508-before-drawio-4.png?dpr=0.5 777w,https://www.datocms-assets.com/85246/1757535508-before-drawio-4.png?dpr=0.75 1165w,https://www.datocms-assets.com/85246/1757535508-before-drawio-4.png 1554w" sizes="(max-width: 1554px) 100vw, 1554px"/><img src="https://www.datocms-assets.com/85246/1757535508-before-drawio-4.png" alt="graph" style="position:absolute;left:0;top:0;width:100%;height:100%;max-width:none;max-height:none" loading="lazy"/></picture></noscript></div><p>Both of these queries are fast. The first simply retrieves a single document by its ID. While the second does need to consider every version of every file in the repo (which might sound like a lot), our tests show it’s actually not nearly so bad. Some files in the repository have dozens of unique versions, but the vast majority are rarely—if ever—updated. So the total number of documents is generally a small multiple (think ~3x) of the number of files you see in the working tree.</p><p>Plus, we’ve made a few optimizations to help things move even faster. If you notice, the above 2 queries are totally independent—you don’t need the result from (1) in order to perform (2), so we do them in parallel. And because a commit’s tree (which just specifies a set of blob IDs) is often much smaller than the result set of blobs, we’ve implemented the in-memory filter as a stream transformer, so that we can start responding to the client the moment we receive our first in-scope match.</p><div class="relative block my-5 [&amp;&gt;picture]:my-0 [&amp;&gt;picture&gt;*]:object-contain [&amp;&gt;picture&gt;*]:rounded-xs [&amp;&gt;img]:my-0" style="overflow:hidden;position:relative;width:100%;max-width:2674px"><img style="display:block;width:100%" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNjc0IiBoZWlnaHQ9Ijk1NCI+PC9zdmc+" aria-hidden="true" alt=""/><img aria-hidden="true" alt="" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwgHBgoICAgLCgoWDhUcDg0NDh0dHREVHR8ZGiITJS0aHysjGh0oHRUWJDUlKC0vMjIyGSI4PTcwPCsxMi8BCgsLDg0OHBAQHDsoIig7OzsvOzs7Oy8vOy87Ly8vLzs1Ly87NS8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL//AABEIAAkAGAMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAABAwQHAP/EAB0QAAEEAgMAAAAAAAAAAAAAAAABAgMRITQSFDL/xAAWAQEBAQAAAAAAAAAAAAAAAAACAQD/xAAXEQEAAwAAAAAAAAAAAAAAAAAAAQIR/9oADAMBAAIRAxEAPwDXkfOq+cCGyT9mqLxKbAqpMAr5+WGJQCg4LY//2Q==" style="transition:opacity 500ms;opacity:1;position:absolute;left:-5%;top:-5%;width:110%;height:110%;max-width:none;max-height:none"/><noscript><picture><source srcSet="https://www.datocms-assets.com/85246/1757535590-after-drawio-2.png?dpr=0.25&amp;fm=webp 668w,https://www.datocms-assets.com/85246/1757535590-after-drawio-2.png?dpr=0.5&amp;fm=webp 1337w,https://www.datocms-assets.com/85246/1757535590-after-drawio-2.png?dpr=0.75&amp;fm=webp 2005w,https://www.datocms-assets.com/85246/1757535590-after-drawio-2.png?fm=webp 2674w" sizes="(max-width: 2674px) 100vw, 2674px" type="image/webp"/><source srcSet="https://www.datocms-assets.com/85246/1757535590-after-drawio-2.png?dpr=0.25 668w,https://www.datocms-assets.com/85246/1757535590-after-drawio-2.png?dpr=0.5 1337w,https://www.datocms-assets.com/85246/1757535590-after-drawio-2.png?dpr=0.75 2005w,https://www.datocms-assets.com/85246/1757535590-after-drawio-2.png 2674w" sizes="(max-width: 2674px) 100vw, 2674px"/><img src="https://www.datocms-assets.com/85246/1757535590-after-drawio-2.png" alt="graph" style="position:absolute;left:0;top:0;width:100%;height:100%;max-width:none;max-height:none" loading="lazy"/></picture></noscript></div><h2 id="the-future">The future</h2><p>We have a few other ideas for optimizations, some a bit more experimental. For example, if we only ever use the tree for a set-contains operation, do we even need to fetch the entire tree at all? Maybe we can pre-construct the set of blob IDs, and only fetch that at query time, or even pre-construct something that <a target="_blank" href="https://en.wikipedia.org/wiki/Bloom_filter">acts just like that set, most of the time, but is just 10% the size</a>?</p><p>And since we’re using <a target="_blank" href="https://turbopuffer.com/">Turbopuffer</a> as the document database backing the Graphite code index, adding embeddings is on the table too, which opens the door to semantic search. Maybe we will soon be able to ask PR Chat to check if a pattern you tried is consistent with examples from similar files.</p><h2 id="the-now">The now</h2><p>Today, the system is live, and we’ve already indexed tens of millions of source files across thousands of repositories. For several weeks, Graphite Chat has been using this index to power LLM tool calls, where it’s been a big upgrade from our previous strategy of calling the GitHub API. </p><p>We can now fetch as many files as we need (no arbitrary rate limit), our searches accurately target the PR’s branch (instead of only being able to search <code>main</code>), and best of all — the index has now served thousands of queries with a median latency consistently under 100 milliseconds.</p><p>What started as a “just grep it” idea turned into a deep dive through storage tradeoffs, indexing engines, and Git’s internals. By rethinking search in terms of blobs and trees, we’ve unlocked fast search at any commit—something we couldn’t get off the shelf. And we’ve hardly touched on the ingestion part! It turns out there are ways to have Git shrink a 5GB repo clone down to 20MB, and you&#x27;d be surprised how useful an anemic clone like that can still be.</p><p>Which is to say, check back soon for a part two!</p></article></div><div class="container"><div class="mt-16 col-span-full relative lg:col-start-5 gap-8 lg:gap-2 flex flex-col lg:gap-x-12 max-lg:border-t border-border max-lg:pt-4"><h3 class="body-base mb-12 lg:mb-0">Related articles</h3><div class="max-lg:contents lg:grid lg:grid-cols-3 lg:gap-x-12 lg:relative lg:pt-8 lg:border-t lg:border-border"><div class="hidden lg:block absolute top-0 left-[calc(33.33%-0.5em)] h-full border-l border-border"></div><div class="hidden lg:block absolute top-0 left-[calc(66.66%+0.5em)] h-full border-l border-border"></div><a aria-label="Why AI will never replace human code review" class="body-base flex flex-col gap-2 border-b border-dashed border-border-default pb-8 group/card" href="/blog/ai-wont-replace-human-code-review"><h3 class="text-xl/6 font-semibold text-pretty text-primary group-hover:opacity-60 group-hover/card:opacity-100 transition-opacity">Why AI will never replace human code review</h3><div class="flex items-baseline gap-2.5"><p class="tabular-nums [word-spacing:-0.25em] text-primary/50 group-hover/card:text-primary/70 transition-colors">Mar 17, 2025</p><span aria-hidden="true" class="bg-primary/25 size-1 shrink-0 self-center"></span><p class="text-primary/50 group-hover/card:text-primary/70 transition-colors">Engineering</p></div></a><a aria-label="AI code generation will remain fragmented" class="body-base flex flex-col gap-2 border-b border-dashed border-border-default pb-8 group/card" href="/blog/ai-code-generation-will-remain-fragmented"><h3 class="text-xl/6 font-semibold text-pretty text-primary group-hover:opacity-60 group-hover/card:opacity-100 transition-opacity">AI code generation will remain fragmented</h3><div class="flex items-baseline gap-2.5"><p class="tabular-nums [word-spacing:-0.25em] text-primary/50 group-hover/card:text-primary/70 transition-colors">Nov 25, 2024</p><span aria-hidden="true" class="bg-primary/25 size-1 shrink-0 self-center"></span><p class="text-primary/50 group-hover/card:text-primary/70 transition-colors">Engineering</p></div></a><a aria-label="Introducing frozen branches: A safer way to build on your teammates’ work" class="body-base flex flex-col gap-2 border-b border-dashed border-border-default pb-8 group/card" href="/blog/introducing-frozen-branches"><h3 class="text-xl/6 font-semibold text-pretty text-primary group-hover:opacity-60 group-hover/card:opacity-100 transition-opacity">Introducing frozen branches: A safer way to build on your teammates’ work</h3><div class="flex items-baseline gap-2.5"><p class="tabular-nums [word-spacing:-0.25em] text-primary/50 group-hover/card:text-primary/70 transition-colors">Sep 17, 2025</p><span aria-hidden="true" class="bg-primary/25 size-1 shrink-0 self-center"></span><p class="text-primary/50 group-hover/card:text-primary/70 transition-colors">Engineering</p></div></a></div></div></div></section><section class="container"><div class="pb-8 pt-8 sm:pt-16"><h2 class="gsap-prefooter-split-text heading-lg text-balance text-primary text-center py-8 px-4 mx-auto max-w-2xl">Built for the world’s fastest engineering teams, now available for everyone.</h2><div class="gsap-prefooter-ctas flex gap-3 justify-center"><a class="inline-flex items-center justify-center gap-2 whitespace-nowrap text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&amp;_svg]:pointer-events-none [&amp;_svg]:size-4 [&amp;_svg]:shrink-0 bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80 h-10 rounded-md px-8 cursor-pointer relative border-neutral-700 border w-fit" href="https://cursor.com/contact-sales?product=graphite">Request a demo</a><div class="relative [--glow-strength:0]"><div class="absolute inset-0 size-full"><div class="blur-[calc(var(--glow-strength)*4px+12px)] absolute w-2/3 h-full top-0 bg-category-magenta/20 left-0" style="opacity:calc(0.2 * var(--glow-strength) + .8);transform:translate(calc(var(--glow-x) * 10%), calc(var(--glow-y) * -2%))"></div><div class="blur-[calc(var(--glow-strength)*4px+12px)] absolute w-2/3 h-full top-0 bg-category-orange/20 right-0" style="opacity:calc(0.2 * var(--glow-strength) + .8);transform:translate(calc(var(--glow-x) * -10%), calc(var(--glow-y) * -2%))"></div></div><a class="inline-flex items-center justify-center gap-2 whitespace-nowrap text-sm font-medium focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&amp;_svg]:pointer-events-none [&amp;_svg]:size-4 [&amp;_svg]:shrink-0 relative bg-primary text-primary-foreground shadow hover:bg-primary/90 h-10 rounded-md px-8 group transition-all cursor-pointer w-fit relative" href="https://app.graphite.com/signup">Start free trial<div class="size-3 sm:size-4 overflow-hidden relative"><div class="group-hover:translate-x-0 transition-transform -translate-x-1/2 flex items-center duration-500 absolute fit h-full left-0 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:size-3"><svg width="12" height="10" viewBox="0 0 12 10" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M5.8965 1.208L8.9525 4.248H0.9205V5.432H8.9525L5.9125 8.488L6.6805 9.256L11.0805 4.84L6.6645 0.424L5.8965 1.208Z" fill="currentColor"></path></svg><svg width="12" height="10" viewBox="0 0 12 10" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M5.8965 1.208L8.9525 4.248H0.9205V5.432H8.9525L5.9125 8.488L6.6805 9.256L11.0805 4.84L6.6645 0.424L5.8965 1.208Z" fill="currentColor"></path></svg></div></div><div class="rounded-[inherit] absolute inset-0 p-[var(--padding,1px)] pointer-events-none" style="mask:linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);mask-composite:exclude"><div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 aspect-[1/1] min-h-full min-w-full scale-[1.2]"><div class="absolute size-full group-hover:rotate-[360deg] rotate-[0deg] bg-[conic-gradient(from_0deg,#3cb091,#1495c7,#6666c1,#efae0f,#3cb091)] dark:opacity-100 opacity-50 transition-transform duration-700"></div></div></div></a></div></div></div></section></main><div aria-hidden="true" class="fixed inset-0 size-full pointer-events-none z-10 mix-blend-difference contrast-0 reduced-motion:hidden overflow-hidden"><div class="w-full px-3 grid grid-cols-6 grid-rows-6 lg:grid-cols-12 lg:grid-rows-12"><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div><div class="relative h-0 pb-[100%]"><div class="opacity-0 size-0.5 bg-primary absolute top-0 left-0 gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute top-full gsap-decorative-dot"></div><div class="opacity-0 size-0.5 bg-primary absolute left-full top-full gsap-decorative-dot"></div></div></div></div><footer class="footer-module-scss-module__yUv0PG__footer relative overflow-hidden pt-20 text-xs sm:text-sm text-primary z-10 bg-neutral-950" data-datocms-noindex="true"><div class="!py-8 container"><div class="flex flex-col flex-wrap gap-12 md:grid md:grid-cols-3 md:gap-3 lg:grid-cols-6"><svg viewBox="0 0 33 33" fill="currentColor" xmlns="http://www.w3.org/2000/svg" class="size-8 sm:size-12 text-white"><path d="M14.0973 27.6738L24.8046 24.8048L27.6738 14.0974L19.8354 6.25904L9.128 9.128L6.25888 19.8354L14.0973 27.6738ZM12.3475 8.9664L21.5851 8.9664L26.2038 16.9664L21.5851 24.9664H12.3475L7.7288 16.9664L12.3475 8.9664Z"></path><path d="M11.6058 22.3271L18.9285 24.2893L24.2893 18.9285L22.3271 11.6058L15.0043 9.64354L9.64354 15.0043L11.6058 22.3271Z"></path></svg><nav class="grid grid-cols-2 gap-x-3 gap-y-8 sm:gap-y-12 hover-focus-parent whitespace-nowrap md:col-span-2 lg:col-start-3 lg:col-span-full lg:grid-cols-4"><section aria-labelledby="Features" class="flex flex-col gap-2 sm:gap-4 sm:flex-1 basis-1/2 body-sm"><h3 class="text-primary" id="Features">Features</h3><ul class="flex flex-col gap-1.5 sm:gap-2 group"><li><a aria-label="CLI" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="/features#cli">CLI</a></li><li><a aria-label="Merge queue" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="/features#merge-queue">Merge queue</a></li><li><a aria-label="Insights" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="/features#insights">Insights</a></li><li><a aria-label="PR inbox" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="/features#inbox">PR inbox</a></li><li><a aria-label="AI Reviews" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="/features/ai-reviews">AI Reviews</a></li><li><a aria-label="Agents" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="/features/agents">Agents<div class="font-bold bg-neutral-800 px-1.5 py-0.5 rounded-full uppercase empty:hidden text-xxs tabular-nums">New</div></a></li><li><a target="_blank" aria-label="Graphite Chat" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="/features/chat">Graphite Chat</a></li></ul></section><section aria-labelledby="Company" class="flex flex-col gap-2 sm:gap-4 sm:flex-1 basis-1/2 body-sm"><h3 class="text-primary" id="Company">Company</h3><ul class="flex flex-col gap-1.5 sm:gap-2 group"><li><a aria-label="Blog" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="/blog">Blog</a></li><li><a aria-label="Customers" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="/customers">Customers</a></li><li><a aria-label="Careers" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="/careers">Careers<div class="font-bold bg-neutral-800 px-1.5 py-0.5 rounded-full uppercase empty:hidden text-xxs tabular-nums">0</div></a></li><li><a aria-label="Privacy policy" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="/privacy">Privacy policy</a></li><li><a aria-label="Terms of service" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="/terms-of-service">Terms of service</a></li></ul></section><section aria-labelledby="Resources" class="flex flex-col gap-2 sm:gap-4 sm:flex-1 basis-1/2 body-sm"><h3 class="text-primary" id="Resources">Resources</h3><ul class="flex flex-col gap-1.5 sm:gap-2 group"><li><a aria-label="Docs" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="/docs">Docs</a></li><li><a aria-label="Pricing" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="/pricing">Pricing</a></li><li><a aria-label="Status" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="https://status.graphite.com">Status</a></li><li><a aria-label="Guides" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="/guides">Guides</a></li><li><a aria-label="Stacking workflow" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="/stacking">Stacking workflow</a></li></ul></section><section aria-labelledby="Connect" class="flex flex-col gap-2 sm:gap-4 sm:flex-1 basis-1/2 body-sm"><h3 class="text-primary" id="Connect">Connect</h3><ul class="flex flex-col gap-1.5 sm:gap-2 group"><li><a aria-label="Contact us" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="https://cursor.com/contact-sales?product=graphite"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-mail" aria-hidden="true"><path d="m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7"></path><rect x="2" y="4" width="20" height="16" rx="2"></rect></svg>Contact us</a></li><li><a aria-label="Community Slack" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="https://community.graphite.com"><svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M12.0494 6.16052C12.0494 5.34688 12.707 4.68927 13.5206 4.68927C14.3343 4.68927 14.9919 5.34688 14.9919 6.16052C14.9919 6.97417 14.3343 7.63177 13.5206 7.63177H12.0494V6.16052ZM11.3138 6.16052C11.3138 6.97417 10.6562 7.63177 9.84252 7.63177C9.02887 7.63177 8.37127 6.97417 8.37127 6.16052V2.47125C8.37127 1.6576 9.02887 1 9.84252 1C10.6562 1 11.3138 1.6576 11.3138 2.47125V6.16052ZM4.68341 2.47129C4.68341 3.28493 5.34102 3.94254 6.15466 3.94254H7.62591V2.47129C7.62591 1.65764 6.96831 1.00004 6.15466 1.00004C5.34102 1.00004 4.68341 1.65764 4.68341 2.47129ZM7.62591 6.16056C7.62591 5.34691 6.96831 4.68931 6.15466 4.68931H2.46539C1.65174 4.68931 0.994141 5.34691 0.994141 6.16056C0.994141 6.9742 1.65174 7.63181 2.46539 7.63181H6.15466C6.96831 7.63181 7.62591 6.9742 7.62591 6.16056ZM2.47468 11.3218C3.28833 11.3218 3.94593 10.6642 3.94593 9.85058V8.37933H2.47468C1.66103 8.37933 1.00343 9.03693 1.00343 9.85058C1.00343 10.6642 1.66103 11.3218 2.47468 11.3218ZM6.15281 8.37933C5.33916 8.37933 4.68156 9.03693 4.68156 9.85058V13.5287C4.68156 14.3423 5.33916 15 6.15281 15C6.96645 15 7.62406 14.3423 7.62406 13.5287V9.85058C7.62406 9.03693 6.96645 8.37933 6.15281 8.37933ZM11.3138 13.5287C11.3138 12.7151 10.6562 12.0575 9.84252 12.0575H8.37127V13.5287C8.37127 14.3423 9.02887 15 9.84252 15C10.6562 15 11.3138 14.3423 11.3138 13.5287ZM8.37127 9.85058C8.37127 10.6642 9.02887 11.3218 9.84252 11.3218H13.5318C14.3454 11.3218 15.003 10.6642 15.003 9.85058C15.003 9.03693 14.3454 8.37933 13.5318 8.37933H9.84252C9.02887 8.37933 8.37127 9.03693 8.37127 9.85058Z"></path></svg><span class="sm:inline hidden">Community</span> Slack</a></li><li><a aria-label="GitHub" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="https://github.com/withgraphite/"><svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><path d="M8 1C4.0625 1 1 4.0625 1 8C1 12.5938 5.15625 14.5625 5.8125 14.5625C6.25 14.5625 6.25 14.3438 6.25 14.125V13.0312C4.71875 13.4688 4.0625 12.5938 3.84375 11.9375C3.84375 11.9375 3.84375 11.7188 3.40625 11.2812C3.1875 11.0625 2.3125 10.625 3.1875 10.625C3.84375 10.625 4.28125 11.5 4.28125 11.5C4.9375 12.375 5.8125 12.1562 6.25 11.9375C6.25 11.5 6.6875 11.0625 6.6875 11.0625C4.9375 10.8438 3.625 10.1875 3.625 7.78125C3.625 6.90625 3.84375 6.25 4.28125 5.8125C4.28125 5.8125 3.84375 4.9375 4.28125 3.84375C4.28125 3.84375 5.375 3.84375 6.25 4.71875C6.90625 4.28125 9.09375 4.28125 9.75 4.71875C10.625 3.84375 11.7188 3.84375 11.7188 3.84375C12.1562 5.375 11.7188 5.8125 11.7188 5.8125C12.1562 6.25 12.375 6.90625 12.375 7.78125C12.375 10.1875 10.8438 10.8438 9.3125 11.0625C9.53125 11.2812 9.75 11.7188 9.75 12.375V14.125C9.75 14.3438 9.75 14.5625 10.1875 14.5625C10.8438 14.5625 15 12.5938 15 8C15 4.0625 11.9375 1 8 1Z"></path></svg>GitHub</a></li><li><a aria-label="X (Twitter)" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="https://x.com/graphite/"><svg width="24" height="24" viewBox="0 0 24 24"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" fill="currentColor"></path></svg>X <span class="sm:inline hidden">(Twitter)</span></a></li><li><a aria-label="LinkedIn" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="https://www.linkedin.com/company/withgraphite/"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" data-supported-dps="24x24" fill="currentColor" width="24" height="24" focusable="false"><path d="M20.5 2h-17A1.5 1.5 0 002 3.5v17A1.5 1.5 0 003.5 22h17a1.5 1.5 0 001.5-1.5v-17A1.5 1.5 0 0020.5 2zM8 19H5v-9h3zM6.5 8.25A1.75 1.75 0 118.3 6.5a1.78 1.78 0 01-1.8 1.75zM19 19h-3v-4.74c0-1.42-.6-1.93-1.38-1.93A1.74 1.74 0 0013 14.19a.66.66 0 000 .14V19h-3v-9h2.9v1.3a3.11 3.11 0 012.7-1.4c1.55 0 3.36.86 3.36 3.66z"></path></svg>LinkedIn</a></li><li><a aria-label="YouTube" class="flex items-center gap-1 [&amp;&gt;svg]:size-3 sm:[&amp;&gt;svg]:size-4 [&amp;&gt;svg]:mr-0.5 sm:[&amp;&gt;svg]:mr-1 transition-all hover-focus-child ease duration-500 text-neutral-400" href="https://www.youtube.com/@withgraphite"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-youtube" aria-hidden="true"><path d="M2.5 17a24.12 24.12 0 0 1 0-10 2 2 0 0 1 1.4-1.4 49.56 49.56 0 0 1 16.2 0A2 2 0 0 1 21.5 7a24.12 24.12 0 0 1 0 10 2 2 0 0 1-1.4 1.4 49.55 49.55 0 0 1-16.2 0A2 2 0 0 1 2.5 17"></path><path d="m10 15 5-3-5-3z"></path></svg>YouTube</a></li></ul></section></nav></div></div><div class="container border-t border-neutral-800 text-tertiary py-8"><div class="flex w-full justify-between text-xxs sm:text-xs"><a target="_blank" class="flex items-center flex-row whitespace-nowrap group text-yellow-500" href="https://status.graphite.com"><div class="size-4 rounded-full bg-current/25 flex items-center justify-center"><div class="size-2 relative"><div class="w-full h-full absolute inset-0 bg-current rounded-full blur-[1px] opacity-50 motion-reduce:animate-none"></div><div class="w-full h-full absolute inset-0 bg-current rounded-full "></div></div></div><div class="ml-2 mr-1">Loading</div><svg width="12" height="10" viewBox="0 0 12 10" fill="currentColor" xmlns="http://www.w3.org/2000/svg" class="-rotate-45 group-hover:opacity-100 opacity-0 transition-opacity"><path d="M5.8965 1.208L8.9525 4.248H0.9205V5.432H8.9525L5.9125 8.488L6.6805 9.256L11.0805 4.84L6.6645 0.424L5.8965 1.208Z" fill="currentColor"></path></svg></a><div class="flex">© Graphite <!-- -->2026</div></div><div class="footer-module-scss-module__yUv0PG__wordmark" style="--mask-size:75%" id="wordmark"><img alt="An image of the Graphite logo as a neon sign" loading="lazy" width="1024" height="341" decoding="async" data-nimg="1" class="footer-module-scss-module__yUv0PG__bg footer-module-scss-module__yUv0PG__bg--hidden" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgraphite_logo_neon_sign.fd632602.webp&amp;w=1080&amp;q=75&amp;dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgraphite_logo_neon_sign.fd632602.webp&amp;w=2048&amp;q=75&amp;dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fgraphite_logo_neon_sign.fd632602.webp&amp;w=2048&amp;q=75&amp;dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv"/><div class="footer-module-scss-module__yUv0PG__aberrations"><div class="footer-module-scss-module__yUv0PG__aberration footer-module-scss-module__yUv0PG__bg" style="--offset:8px"><div class="footer-module-scss-module__yUv0PG__bg footer-module-scss-module__yUv0PG__aberration__inner" style="mask-image:image-set(url(/images/footer/wordmark/white.webp) 1x, url(/images/footer/wordmark/white@2x.webp) 2x);background-color:#ff6231"></div></div><div class="footer-module-scss-module__yUv0PG__aberration footer-module-scss-module__yUv0PG__bg" style="--offset:16px"><div class="footer-module-scss-module__yUv0PG__bg footer-module-scss-module__yUv0PG__aberration__inner" style="mask-image:image-set(url(/images/footer/wordmark/white.webp) 1x, url(/images/footer/wordmark/white@2x.webp) 2x);background-color:#ffb931"></div></div><div class="footer-module-scss-module__yUv0PG__aberration footer-module-scss-module__yUv0PG__bg" style="--offset:24px"><div class="footer-module-scss-module__yUv0PG__bg footer-module-scss-module__yUv0PG__aberration__inner" style="mask-image:image-set(url(/images/footer/wordmark/white.webp) 1x, url(/images/footer/wordmark/white@2x.webp) 2x);background-color:#14c7ff"></div></div><div class="footer-module-scss-module__yUv0PG__aberration footer-module-scss-module__yUv0PG__bg" style="--offset:32px"><div class="footer-module-scss-module__yUv0PG__bg footer-module-scss-module__yUv0PG__aberration__inner" style="mask-image:image-set(url(/images/footer/wordmark/white.webp) 1x, url(/images/footer/wordmark/white@2x.webp) 2x);background-color:#1061ff"></div></div></div><img alt="Graphite wordmark" loading="lazy" width="2048" height="683" decoding="async" data-nimg="1" class="footer-module-scss-module__yUv0PG__bg footer-module-scss-module__yUv0PG__bg--hidden" style="color:transparent" srcSet="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fwhite%402x.6327aed5.webp&amp;w=2048&amp;q=75&amp;dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv 1x, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fwhite%402x.6327aed5.webp&amp;w=3840&amp;q=75&amp;dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv 2x" src="/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fwhite%402x.6327aed5.webp&amp;w=3840&amp;q=75&amp;dpl=dpl_ASodJGPkKjhm283buwgKNSKFRnkv"/></div></div></footer></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"data":{"id":"YDse74-uRWCSCvtWVdZEkg","slug":"how-we-sped-up-code-search-graphite-chat","title":"How we sped up code search for Graphite Chat ","metatags":[{"title":"How we sped up code search for Graphite Chat ","description":"How we built fast, low-latency code search at any commit—going beyond default-branch-only tools like GitHub and Sourcegraph.","ogImage":{"url":"https://www.datocms-assets.com/85246/1757535905-082025_code-search_v1_0057.jpg"},"noIndex":false}],"date":"2025-09-10","image":{"blurUpThumb":"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwgHBgoICAgLDRUXDhUPDQ0NFhENDQ0YFxMZGBYVFhUaHysjGh0oHRUWJDUlKC0vMjIyGSI4PTcwPCsxMi8BCgsLDg0OFQ0QFS8cFhwvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL//AABEIAA4AGAMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAADBQEEBwD/xAAdEAACAwACAwAAAAAAAAAAAAABAwACEQRBEyEx/8QAFQEBAQAAAAAAAAAAAAAAAAAAAgD/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwDLPFQvHuOacNbE/eoiJIvuy+jlXC82EQeWiq74J0E25Yw7Jkn/2Q==","url":"https://www.datocms-assets.com/85246/1757535905-082025_code-search_v1_0057.jpg","alt":"hero image"},"author":{"name":"Brandon Willett","headshot":{"blurUpThumb":"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwgHBgoICAgLEhALDhgODQ0VEhgPDQ0NFx8ZGCITFhUaHysjGh0oHSEWJDUlKC0vMjIyGSI4PTcwPCsxMi8BCgsLDg4OHA0NHC8oFhwvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL//AABEIABgAGAMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABQYEAf/EABsQAAIDAQEBAAAAAAAAAAAAAAEEAAIDEQUi/8QAFwEBAQEBAAAAAAAAAAAAAAAAAgQDAf/EABoRAAMAAwEAAAAAAAAAAAAAAAABAhEhMQP/2gAMAwEAAhEDEQA/AL3fUrJHpEW0bN17EWEnfc9hqyvKExah6LlVLG3ZDS2WecDR72NcLECElXn9tLHsI1OhOUU7Cd7YfUz65HJEgCEIX0EMSZI3YsZ2EJsuHG3k/9k=","url":"https://www.datocms-assets.com/85246/1757535817-img_8626.jpg","alt":null},"shortBio":""},"categories":[{"id":"99894518","title":"Engineering"}],"content":{"value":{"schema":"dast","document":{"type":"root","children":[{"item":"HVNZz30kQkOw4cYiKdCC7Q","type":"block"},{"type":"paragraph","children":[{"type":"span","value":"Searching a codebase is "},{"type":"span","marks":["emphasis"],"value":"usually"},{"type":"span","value":" a pretty easy problem. You want to know what files use your "},{"type":"span","marks":["code"],"value":"MAX_EMAILS_TO_SEND"},{"type":"span","value":" constant? One command gets you there in milliseconds:"}]},{"code":"grep -r MAX_EMAILS_TO_SEND .","type":"code"},{"type":"paragraph","children":[{"type":"span","value":"Modern tools like "},{"url":"https://github.com/BurntSushi/ripgrep","type":"link","children":[{"type":"span","marks":["code"],"value":"ripgrep"}]},{"type":"span","value":" make it even faster. But this simplicity depends on a couple of things being true:"}]},{"type":"list","style":"bulleted","children":[{"type":"listItem","children":[{"type":"paragraph","children":[{"type":"span","value":"Your files all reside on a (hopefully) fast disk."}]}]},{"type":"listItem","children":[{"type":"paragraph","children":[{"type":"span","value":"There aren't too many of them."}]}]}]},{"type":"paragraph","children":[{"type":"span","value":"When building out a code search tool for the agentic "},{"url":"https://graphite.dev/docs/graphite-chat","meta":[{"id":"target","value":"_blank"}],"type":"link","children":[{"type":"span","value":"Graphite Chat"}]},{"type":"span","value":", we immediately ran into both of these limitations. We needed to support searches across hundreds of thousands (or millions) of files, at any commit, without maintaining a whole traditional VM+disk for each one. Could "},{"type":"span","marks":["code"],"value":"grep"},{"type":"span","value":" even support that kind of use case?"}]},{"type":"paragraph","children":[{"type":"span","value":"Let’s find out!"}]},{"type":"heading","level":2,"children":[{"type":"span","value":"Default-branch-only search isn’t enough"}]},{"type":"paragraph","children":[{"type":"span","value":"You might read this and think: What's supposed to be novel here? We've had fast code search via API for big repositories for years now. "},{"url":"https://sourcegraph.com/","meta":[{"id":"target","value":"_blank"}],"type":"link","children":[{"type":"span","value":"Sourcegraph"}]},{"type":"span","value":" made a whole company out of the idea, and GitHub even gives you something similar for free."}]},{"type":"paragraph","children":[{"type":"span","value":"True, but only on the "},{"type":"span","marks":["emphasis"],"value":"default"},{"type":"span","value":" branch. GitHub’s API docs are explicit:"}]},{"type":"blockquote","children":[{"type":"paragraph","children":[{"type":"span","value":"Only the "},{"type":"span","marks":["emphasis"],"value":"default branch"},{"type":"span","value":" is considered. In most cases, this will be the "},{"type":"span","marks":["code"],"value":"main"},{"type":"span","value":" branch."}]}]},{"type":"paragraph","children":[{"type":"span","value":"And Sourcegraph, while it’s closed-source now, still has an archive of their documentation and code as it stood in 2023, which details "},{"url":"https://github.com/sourcegraph/sourcegraph-public-snapshot/blob/main/doc/dev/background-information/architecture/index.md","meta":[{"id":"target","value":"_blank"}],"type":"link","children":[{"type":"span","value":"the same thing"}]},{"type":"span","value":":"}]},{"type":"blockquote","children":[{"type":"paragraph","children":[{"type":"span","value":"Sourcegraph also has a fast search path for code that isn't indexed yet, or for code that will never be indexed (for example: code that is not on a default branch). Indexing every branch of every repository isn't a pragmatic use of resources for most customers, so this decision balances optimizing the common case (searching all default branches) with space savings (not indexing everything)."}]},{"type":"paragraph","children":[{"type":"span","value":"…"}]},{"type":"paragraph","children":[{"type":"span","value":"Provides on-demand unindexed search for repositories. It scans through a git archive fetched from gitserver to find results, similar in nature to "},{"type":"span","marks":["code"],"value":"git grep"},{"type":"span","value":"."}]}]},{"type":"paragraph","children":[{"type":"span","value":"The searches our model makes almost never target "},{"type":"span","marks":["code"],"value":"main"},{"type":"span","value":"; they’re against arbitrary commits. For us, fast search "},{"type":"span","marks":["emphasis"],"value":"at any commit"},{"type":"span","value":" was the requirement, and that turned out to be a much harder problem."}]},{"type":"heading","level":2,"children":[{"type":"span","value":"What didn’t work"}]},{"type":"paragraph","children":[{"type":"span","value":"In the spirit of "},{"url":"https://en.wikipedia.org/wiki/KISS_principle","meta":[{"id":"target","value":"_blank"}],"type":"link","children":[{"type":"span","value":"KISS"}]},{"type":"span","value":" (or “"},{"url":"https://boringtechnology.club","meta":[{"id":"target","value":"_blank"}],"type":"link","children":[{"type":"span","value":"Choose Boring Technology"}]},{"type":"span","value":"”, or “"},{"url":"https://grugbrain.dev","meta":[{"id":"target","value":"_blank"}],"type":"link","children":[{"type":"span","value":"The Grug Brained Developer"}]},{"type":"span","value":"”, feel free to pick your favorite decade’s spin on the idea), we figured our first attempt at a solution should also be the most straightforward: a plain old "},{"type":"span","marks":["code"],"value":"git grep"},{"type":"span","value":" on the repository. If that worked, then we could save ourselves a lot of time."}]},{"type":"paragraph","children":[{"type":"span","value":"We spent a week running experiments on several block-based storage solutions on AWS:"}]},{"type":"list","style":"bulleted","children":[{"type":"listItem","children":[{"type":"paragraph","children":[{"type":"span","value":"On-demand AWS Lambdas to execute searches via one shared EFS volume."}]}]},{"type":"listItem","children":[{"type":"paragraph","children":[{"type":"span","value":"An ECS cluster where tasks dynamically mount per-repo EFS volumes at query time."}]}]},{"type":"listItem","children":[{"type":"paragraph","children":[{"type":"span","value":"Persistent EC2 instances which use (faster) EBS with "},{"url":"https://docs.aws.amazon.com/ebs/latest/userguide/ebs-volumes-multi.html","meta":[{"id":"target","value":"_blank"}],"type":"link","children":[{"type":"span","value":"multi-attach"}]},{"type":"span","value":" for horizontal scaling."}]}]}]},{"type":"paragraph","children":[{"type":"span","value":"We saw some interesting results here, for example, we measured the EBS-mounted volumes to consistently perform I/O intensive operations (like searches) about 3x as fast as EFS-mounted ones. From a test we ran searching for a string in the "},{"type":"span","marks":["code"],"value":"react-native"},{"type":"span","value":" repository:"}]},{"code":"# EBS\n\nPerformance counter stats for 'git grep interactionManager 8f1ae53':\n\n 17,541 minor-faults # 0.062 M/sec \n 878 major-faults # 0.003 M/sec \n 282.34 msec task-clock # 0.184 CPUs utilized \n\n1.535785602 seconds time elapsed\n\n0.208365000 seconds user\n0.075011000 seconds sys","type":"code","language":"bash"},{"code":"# EFS\n\nPerformance counter stats for 'git grep interactionManager 8f1ae53':\n\n 17,620 minor-faults # 0.050 M/sec \n 53 major-faults # 0.149 K/sec \n 354.59 msec task-clock # 0.078 CPUs utilized \n\n4.560184652 seconds time elapsed\n\n0.212312000 seconds user\n0.129052000 seconds sys","type":"code","language":"bash"},{"type":"paragraph","children":[{"type":"span","value":"However, in spite of the individual advantages each had over the others, they all buckled in the same place: large repositories."}]},{"type":"paragraph","children":[{"type":"span","value":"While "},{"type":"span","marks":["code"],"value":"react-native"},{"type":"span","value":" is a decently-sized repo by most measures, it only has a few thousand files:"}]},{"code":"$ git ls-files | wc -l\n 7019","type":"code","language":"bash"},{"type":"paragraph","children":[{"type":"span","value":"We need to support repositories hundreds of times this size, and in cases like that, we actually end up at the mercy of the Linux page cache. The "},{"type":"span","marks":["code"],"value":"major-faults"},{"type":"span","value":" rows in the snippets above represent times the "},{"type":"span","marks":["code"],"value":"grep"},{"type":"span","value":" process needed to actually reach out to the disk for blocks, and for sample large codebases we tested, searches only returned “fast enough” (under 10 seconds) when "},{"type":"span","marks":["code"],"value":"major-faults"},{"type":"span","value":" was 0 (for instance, when the same search is run twice in a row). In other words, searches are fast only when the "},{"type":"span","marks":["emphasis"],"value":"entire repository"},{"type":"span","value":" is already in the page cache."}]},{"type":"paragraph","children":[{"type":"span","value":"At this point, the "},{"type":"span","marks":["code"],"value":"grep"},{"type":"span","value":" operation becomes mostly CPU bound, and perhaps unsurprisingly, this is also where EFS and EBS see their performance disparity vanish:"}]},{"code":"Performance counter stats for 'git grep interactionManager 8f1ae53':\n\n 17,667 minor-faults # 0.071 M/sec \n 0 major-faults # 0.000 K/sec \n 248.55 msec task-clock # 0.957 CPUs utilized \n\n0.259805935 seconds time elapsed\n\n0.208592000 seconds user\n0.040113000 seconds sys","type":"code","language":"bash"},{"type":"paragraph","children":[{"type":"span","value":"Of course, the only way of ensuring that every block needed for a search is already in the page cache when the search comes in, is to have a crystal ball, which we can’t afford."}]},{"type":"paragraph","children":[{"type":"span","value":"So, we have to look into some more earthly solutions!"}]},{"type":"heading","level":2,"children":[{"type":"span","value":"What somewhat worked"}]},{"type":"paragraph","children":[{"type":"span","value":"If we can't brute-force our way through a big repository with "},{"type":"span","marks":["code"],"value":"grep"},{"type":"span","value":", then it looks like we'll need to do some indexing."}]},{"type":"paragraph","children":[{"type":"span","value":"We tested loading the repository’s files into "},{"url":"https://www.elastic.co/","meta":[{"id":"target","value":"_blank"}],"type":"link","children":[{"type":"span","value":"Elasticsearch"}]},{"type":"span","value":", which tokenizes documents and executes keyword queries quickly. The results were promising:"}]},{"code":"$ cat search.json \n{\n \"query\": {\n \"wildcard\": {\n \"content\": {\n \"value\": \"*interactionManager*\"\n }\n }\n }\n}\n\n$ https GET \u003celastic-endpoint\u003e/blobs/_search?size=100 \u003c search.json \n{\n \"hits\": {\n \"hits\": [...],\n \"max_score\": 1.0,\n \"total\": {\n \"relation\": \"eq\",\n \"value\": 83\n }\n },\n \"timed_out\": false,\n \"took\": 79\n}","type":"code","language":"bash"},{"type":"paragraph","children":[{"type":"span","value":"Even using a tiny node type ("},{"url":"https://instances.vantage.sh/aws/opensearch/i4g.large.search","meta":[{"id":"target","value":"_blank"}],"type":"link","children":[{"type":"span","marks":["code"],"value":"i4g.large.search"}]},{"type":"span","value":"), we saw searches over even huge repositories taking well under 500ms. And that's with a cluster of just one node; we could easily split the dataset into shards (ES manages this on its own) such that 10 different nodes handle 1/10 of the files each, and our searches would be even faster."}]},{"type":"paragraph","children":[{"type":"span","value":"Problem solved, right? Not quite. What we just tried with Elasticsearch worked great for "},{"type":"span","marks":["emphasis"],"value":"one commit"},{"type":"span","value":", but our requirement was fast search at "},{"type":"span","marks":["emphasis"],"value":"any commit"},{"type":"span","value":". The direct approach would be to index the repo’s state at each commit, for easy lookups, but — multiply thousands of repos by thousands of files by thousands of commits, and suddenly you’re managing tens of billions of documents. Running a cluster of that size would be prohibitively complex and expensive."}]},{"type":"paragraph","children":[{"type":"span","value":"So, is the “document database” idea dead-on-arrival?"}]},{"type":"heading","level":2,"children":[{"type":"span","value":"Back to basics"}]},{"type":"paragraph","children":[{"type":"span","value":"When looking at the problem through the above lens (the challenge of efficiently managing thousands of files, each with potentially thousands of versions), there "},{"type":"span","marks":["emphasis"],"value":"is"},{"type":"span","value":" one database that's relevant to the discussion: namely, Git itself!"}]},{"type":"paragraph","children":[{"type":"span","value":"A Git repository seems to store an entire copy of the repository at each commit of a "},{"url":"https://github.com/torvalds/linux","meta":[{"id":"target","value":"_blank"}],"type":"link","children":[{"type":"span","value":"potentially-decades-long history"}]},{"type":"span","value":", but does so without terabytes of disk space. This led us to wonder, \"how does it do that, and can we somehow adapt that approach to work with a document search database instead of a filesystem?\""}]},{"type":"paragraph","children":[{"type":"span","value":"For the \"how\" question, it's honestly very clever if you haven't "},{"url":"https://git-scm.com/book/en/v2/Git-Internals-Git-Objects","meta":[{"id":"target","value":"_blank"}],"type":"link","children":[{"type":"span","value":"read about it"}]},{"type":"span","value":" before. The short version is, Git splits the data it stores into several different kinds of objects:"}]},{"type":"list","style":"numbered","children":[{"type":"listItem","children":[{"type":"paragraph","children":[{"type":"span","marks":["strong"],"value":"Blobs"},{"type":"span","value":" → raw file contents, "},{"url":"https://en.wikipedia.org/wiki/Content-addressable_storage","meta":[{"id":"target","value":"_blank"}],"type":"link","children":[{"type":"span","value":"content-addressed"}]},{"type":"span","value":"."}]}]},{"type":"listItem","children":[{"type":"paragraph","children":[{"type":"span","marks":["strong"],"value":"Trees"},{"type":"span","value":" → lists of blob IDs at a given commit."}]}]}]},{"type":"paragraph","children":[{"type":"span","value":"And as for the \"can we\" question, it turns out, yes absolutely!"}]},{"type":"heading","level":2,"children":[{"type":"span","value":"The life of a search query"}]},{"type":"paragraph","children":[{"type":"span","value":"The key change was that, like Git, we needed to start storing two kinds of objects instead of just one: the blobs and trees. Then, when it comes time to perform a search, we execute 2 queries:"}]},{"type":"list","style":"numbered","children":[{"type":"listItem","children":[{"type":"paragraph","children":[{"type":"span","value":"Get the tree object for the commit SHA specified in the query."}]}]},{"type":"listItem","children":[{"type":"paragraph","children":[{"type":"span","value":"Get "},{"type":"span","marks":["emphasis"],"value":"all"},{"type":"span","value":" blobs that match the search term specified in the query."}]}]}]},{"type":"paragraph","children":[{"type":"span","value":"And then, in memory, we filter the results from (2) based on the blob IDs in the result of (1), such that we only return files which are actually in-scope for the request. Easy!"}]},{"item":"S905JYNXT9-pSnn3YKJZbA","type":"block"},{"type":"paragraph","children":[{"type":"span","value":"Both of these queries are fast. The first simply retrieves a single document by its ID. While the second does need to consider every version of every file in the repo (which might sound like a lot), our tests show it’s actually not nearly so bad. Some files in the repository have dozens of unique versions, but the vast majority are rarely—if ever—updated. So the total number of documents is generally a small multiple (think ~3x) of the number of files you see in the working tree."}]},{"type":"paragraph","children":[{"type":"span","value":"Plus, we’ve made a few optimizations to help things move even faster. If you notice, the above 2 queries are totally independent—you don’t need the result from (1) in order to perform (2), so we do them in parallel. And because a commit’s tree (which just specifies a set of blob IDs) is often much smaller than the result set of blobs, we’ve implemented the in-memory filter as a stream transformer, so that we can start responding to the client the moment we receive our first in-scope match."}]},{"item":"OtcUYsRrTGClljpAFY9Aeg","type":"block"},{"type":"heading","level":2,"children":[{"type":"span","value":"The future"}]},{"type":"paragraph","children":[{"type":"span","value":"We have a few other ideas for optimizations, some a bit more experimental. For example, if we only ever use the tree for a set-contains operation, do we even need to fetch the entire tree at all? Maybe we can pre-construct the set of blob IDs, and only fetch that at query time, or even pre-construct something that "},{"url":"https://en.wikipedia.org/wiki/Bloom_filter","meta":[{"id":"target","value":"_blank"}],"type":"link","children":[{"type":"span","value":"acts just like that set, most of the time, but is just 10% the size"}]},{"type":"span","value":"?"}]},{"type":"paragraph","children":[{"type":"span","value":"And since we’re using "},{"url":"https://turbopuffer.com/","meta":[{"id":"target","value":"_blank"}],"type":"link","children":[{"type":"span","value":"Turbopuffer"}]},{"type":"span","value":" as the document database backing the Graphite code index, adding embeddings is on the table too, which opens the door to semantic search. Maybe we will soon be able to ask PR Chat to check if a pattern you tried is consistent with examples from similar files."}]},{"type":"heading","level":2,"children":[{"type":"span","value":"The now"}]},{"type":"paragraph","children":[{"type":"span","value":"Today, the system is live, and we’ve already indexed tens of millions of source files across thousands of repositories. For several weeks, Graphite Chat has been using this index to power LLM tool calls, where it’s been a big upgrade from our previous strategy of calling the GitHub API. "}]},{"type":"paragraph","children":[{"type":"span","value":"We can now fetch as many files as we need (no arbitrary rate limit), our searches accurately target the PR’s branch (instead of only being able to search "},{"type":"span","marks":["code"],"value":"main"},{"type":"span","value":"), and best of all — the index has now served thousands of queries with a median latency consistently under 100 milliseconds."}]},{"type":"paragraph","children":[{"type":"span","value":"What started as a “just grep it” idea turned into a deep dive through storage tradeoffs, indexing engines, and Git’s internals. By rethinking search in terms of blobs and trees, we’ve unlocked fast search at any commit—something we couldn’t get off the shelf. And we’ve hardly touched on the ingestion part! It turns out there are ways to have Git shrink a 5GB repo clone down to 20MB, and you'd be surprised how useful an anemic clone like that can still be."}]},{"type":"paragraph","children":[{"type":"span","value":"Which is to say, check back soon for a part two!"}]}]}},"blocks":[{"__typename":"ImageRecord","id":"HVNZz30kQkOw4cYiKdCC7Q","image":{"responsiveImage":{"srcSet":"https://www.datocms-assets.com/85246/1757535905-082025_code-search_v1_0057.jpg?dpr=0.25 480w,https://www.datocms-assets.com/85246/1757535905-082025_code-search_v1_0057.jpg?dpr=0.5 960w,https://www.datocms-assets.com/85246/1757535905-082025_code-search_v1_0057.jpg?dpr=0.75 1440w,https://www.datocms-assets.com/85246/1757535905-082025_code-search_v1_0057.jpg 1920w","webpSrcSet":"https://www.datocms-assets.com/85246/1757535905-082025_code-search_v1_0057.jpg?dpr=0.25\u0026fm=webp 480w,https://www.datocms-assets.com/85246/1757535905-082025_code-search_v1_0057.jpg?dpr=0.5\u0026fm=webp 960w,https://www.datocms-assets.com/85246/1757535905-082025_code-search_v1_0057.jpg?dpr=0.75\u0026fm=webp 1440w,https://www.datocms-assets.com/85246/1757535905-082025_code-search_v1_0057.jpg?fm=webp 1920w","sizes":"(max-width: 1920px) 100vw, 1920px","src":"https://www.datocms-assets.com/85246/1757535905-082025_code-search_v1_0057.jpg","width":1920,"height":1080,"aspectRatio":1.7777777777777777,"alt":"hero image","title":null,"base64":"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwgHBgoICAgLDRUXDhUPDQ0NFhENDQ0YFxMZGBYVFhUaHysjGh0oHRUWJDUlKC0vMjIyGSI4PTcwPCsxMi8BCgsLDg0OFQ0QFS8cFhwvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL//AABEIAA4AGAMBIgACEQEDEQH/xAAZAAACAwEAAAAAAAAAAAAAAAADBQEEBwD/xAAdEAACAwACAwAAAAAAAAAAAAABAwACEQRBEyEx/8QAFQEBAQAAAAAAAAAAAAAAAAAAAgD/xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIRAxEAPwDLPFQvHuOacNbE/eoiJIvuy+jlXC82EQeWiq74J0E25Yw7Jkn/2Q=="}}},{"__typename":"ImageRecord","id":"S905JYNXT9-pSnn3YKJZbA","image":{"responsiveImage":{"srcSet":"https://www.datocms-assets.com/85246/1757535508-before-drawio-4.png?dpr=0.25 388w,https://www.datocms-assets.com/85246/1757535508-before-drawio-4.png?dpr=0.5 777w,https://www.datocms-assets.com/85246/1757535508-before-drawio-4.png?dpr=0.75 1165w,https://www.datocms-assets.com/85246/1757535508-before-drawio-4.png 1554w","webpSrcSet":"https://www.datocms-assets.com/85246/1757535508-before-drawio-4.png?dpr=0.25\u0026fm=webp 388w,https://www.datocms-assets.com/85246/1757535508-before-drawio-4.png?dpr=0.5\u0026fm=webp 777w,https://www.datocms-assets.com/85246/1757535508-before-drawio-4.png?dpr=0.75\u0026fm=webp 1165w,https://www.datocms-assets.com/85246/1757535508-before-drawio-4.png?fm=webp 1554w","sizes":"(max-width: 1554px) 100vw, 1554px","src":"https://www.datocms-assets.com/85246/1757535508-before-drawio-4.png","width":1554,"height":1234,"aspectRatio":1.2593192868719612,"alt":"graph","title":null,"base64":"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwYHDQcHBgYGCgYICQ4HDgYGBREJCgcNFx8ZGBYTFhUaHysjGh0oHSEWJDUlKC0vMjIyGSI4PTcwPCsxMi8BCgsLDQ0OFxAOFS8cFhwvLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL//AABEIABQAGAMBIgACEQEDEQH/xAAYAAEBAAMAAAAAAAAAAAAAAAAAAQIDB//EABUQAQEAAAAAAAAAAAAAAAAAAAAB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAwEC/8QAFREBAQAAAAAAAAAAAAAAAAAAAAL/2gAMAwEAAhEDEQA/AOtLEixumWQAla4ygGpFUAq//9k="}}},{"__typename":"ImageRecord","id":"OtcUYsRrTGClljpAFY9Aeg","image":{"responsiveImage":{"srcSet":"https://www.datocms-assets.com/85246/1757535590-after-drawio-2.png?dpr=0.25 668w,https://www.datocms-assets.com/85246/1757535590-after-drawio-2.png?dpr=0.5 1337w,https://www.datocms-assets.com/85246/1757535590-after-drawio-2.png?dpr=0.75 2005w,https://www.datocms-assets.com/85246/1757535590-after-drawio-2.png 2674w","webpSrcSet":"https://www.datocms-assets.com/85246/1757535590-after-drawio-2.png?dpr=0.25\u0026fm=webp 668w,https://www.datocms-assets.com/85246/1757535590-after-drawio-2.png?dpr=0.5\u0026fm=webp 1337w,https://www.datocms-assets.com/85246/1757535590-after-drawio-2.png?dpr=0.75\u0026fm=webp 2005w,https://www.datocms-assets.com/85246/1757535590-after-drawio-2.png?fm=webp 2674w","sizes":"(max-width: 2674px) 100vw, 2674px","src":"https://www.datocms-assets.com/85246/1757535590-after-drawio-2.png","width":2674,"height":954,"aspectRatio":2.80293501048218,"alt":"graph","title":null,"base64":"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwgHBgoICAgLCgoWDhUcDg0NDh0dHREVHR8ZGiITJS0aHysjGh0oHRUWJDUlKC0vMjIyGSI4PTcwPCsxMi8BCgsLDg0OHBAQHDsoIig7OzsvOzs7Oy8vOy87Ly8vLzs1Ly87NS8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL//AABEIAAkAGAMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAABAwQHAP/EAB0QAAEEAgMAAAAAAAAAAAAAAAABAgMRITQSFDL/xAAWAQEBAQAAAAAAAAAAAAAAAAACAQD/xAAXEQEAAwAAAAAAAAAAAAAAAAAAAQIR/9oADAMBAAIRAxEAPwDXkfOq+cCGyT9mqLxKbAqpMAr5+WGJQCg4LY//2Q=="}}}]}},"relatedPosts":[{"id":"GmOgXyJ9SombL0woLQdbiA","slug":"ai-wont-replace-human-code-review","title":"Why AI will never replace human code review","metatags":[{"title":"Why AI will never replace human code review","description":"It needs to be said: AI can’t fully replace human code review. Not now, and likely not ever. ","ogImage":{"url":"https://www.datocms-assets.com/85246/1742309871-ai_review_is_bad_share_image.png"},"noIndex":false}],"date":"2025-03-18","image":null,"author":{"name":"Greg Foster","headshot":{"blurUpThumb":"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwgHBgoICAgLFQoTFRgQFRMPFRINDw0NGhYZGBYfIiEmHysjJikoHRUiJDUlKC0vMjIyGSI4PTcwPCsxMi8BCgsLDg0OHA0NHC8cFhwvLy8vLy81Ly8vLy8vNS8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL//AABEIABgAGAMBIgACEQEDEQH/xAAYAAEBAQEBAAAAAAAAAAAAAAAAAwUGBP/EAB8QAAEEAgIDAAAAAAAAAAAAAAABAgMEESEFExIiMf/EABgBAAMBAQAAAAAAAAAAAAAAAAMEBQIA/8QAGBEAAwEBAAAAAAAAAAAAAAAAAQIRAAP/2gAMAwEAAhEDEQA/AI3HxPsYQrx7OuwjsGfLiG6nn8OgpWqioiayYdhd3NTNbuZJNhQeSSeNtr1AZSJlmU3LtGGexpCFbjkZaRM6AJzE3WOaibSdRibIiqAA6kzKuou//9k=","url":"https://www.datocms-assets.com/85246/1677776207-greg.png","alt":null},"shortBio":"Cofounder \u0026 CTO of Graphite"},"categories":[{"id":"99894518","title":"Engineering"}]},{"id":"BtqSUmC1QnmUR8PdrdVGSA","slug":"ai-code-generation-will-remain-fragmented","title":"AI code generation will remain fragmented","metatags":[{"title":"AI code generation will remain fragmented","description":"Explore why no single code generation tool will dominate the market. Learn how fragmented context, open interfaces, and accessible LLMs prevent long-term competitive advantages in the code-gen space.","ogImage":null,"noIndex":false}],"date":"2024-11-26","image":null,"author":{"name":"Greg Foster","headshot":{"blurUpThumb":"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwgHBgoICAgLFQoTFRgQFRMPFRINDw0NGhYZGBYfIiEmHysjJikoHRUiJDUlKC0vMjIyGSI4PTcwPCsxMi8BCgsLDg0OHA0NHC8cFhwvLy8vLy81Ly8vLy8vNS8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL//AABEIABgAGAMBIgACEQEDEQH/xAAYAAEBAQEBAAAAAAAAAAAAAAAAAwUGBP/EAB8QAAEEAgIDAAAAAAAAAAAAAAABAgMEESEFExIiMf/EABgBAAMBAQAAAAAAAAAAAAAAAAMEBQIA/8QAGBEAAwEBAAAAAAAAAAAAAAAAAQIRAAP/2gAMAwEAAhEDEQA/AI3HxPsYQrx7OuwjsGfLiG6nn8OgpWqioiayYdhd3NTNbuZJNhQeSSeNtr1AZSJlmU3LtGGexpCFbjkZaRM6AJzE3WOaibSdRibIiqAA6kzKuou//9k=","url":"https://www.datocms-assets.com/85246/1677776207-greg.png","alt":null},"shortBio":"Cofounder \u0026 CTO of Graphite"},"categories":[{"id":"99894518","title":"Engineering"}]},{"id":"CPUbjT_2QxOmaP1TpV5PAw","slug":"introducing-frozen-branches","title":"Introducing frozen branches: A safer way to build on your teammates’ work","metatags":[{"title":"Introducing frozen branches: A safer way to build on your teammates’ work","description":"Protect teammates’ work, prevent accidental edits, and confidently build on shared branches without breaking workflows","ogImage":{"url":"https://www.datocms-assets.com/85246/1758221610-guides-cli-image.png"},"noIndex":false}],"date":"2025-09-18","image":{"blurUpThumb":"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwgHBgoICAgVDQ4XFQ8QDQ4NDRENFhEYFxUZGCITFhUaHysjGh0oHRUWJDUlKC0vMjIyGSI4PTcwPCsxMi8BCgsLDg0OFQ0QHC8oGCgvLy8vLy87Ly8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL//AABEIAA4AGAMBIgACEQEDEQH/xAAZAAABBQAAAAAAAAAAAAAAAAAEAAEDBQf/xAAbEAACAgMBAAAAAAAAAAAAAAAAAQIEBREhA//EABcBAAMBAAAAAAAAAAAAAAAAAAIDBAH/xAAXEQADAQAAAAAAAAAAAAAAAAAAAhIR/9oADAMBAAIRAxEAPwDMqWNlOA1nHOGw7H2GvJ8IbluW3wolROlbCpPYgrw9231CBlTT/9k=","url":"https://www.datocms-assets.com/85246/1758221610-guides-cli-image.png","alt":"pic of CLI"},"author":{"name":"David Bradford","headshot":{"blurUpThumb":"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAoHBwgHBgoICAgLFQ8ODhMQDQ4NDh0PDREYFxolGBYVFiEdHysjHR0oHSEiJDUlKC0vMjIyGSI4PTcwPCsxMi8BCgsLAg0OHA0OHDscFhw7Ly8vLy8vNS8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL//AABEIABgAGAMBIgACEQEDEQH/xAAYAAADAQEAAAAAAAAAAAAAAAAABQYDAf/EAB8QAAICAgIDAQAAAAAAAAAAAAECAAMEBRExBhIyIv/EABYBAQEBAAAAAAAAAAAAAAAAAAQDAf/EABsRAAEFAQEAAAAAAAAAAAAAAAUAAxESMQQC/9oADAMBAAIRAxEAPwBll6spUYqXG/fEsNt6V1HlhJtGqe76HcY4VJyjc40dVapq1sqBMI6qxg2OCrCclfJYlCM4NHWURu/Ib7F4DGTqbbJW0N7HuEIZ1oZOJfO6RrqpsPyLIGOAWMIQm+WhsYiOOkbav//Z","url":"https://www.datocms-assets.com/85246/1676042393-img_1141-1.png","alt":null},"shortBio":""},"categories":[{"id":"99894518","title":"Engineering"}]}]},"__N_SSG":true},"page":"/blog/[slug]","query":{"slug":"how-we-sped-up-code-search-graphite-chat"},"buildId":"0Ku2uBfu23Pa9kZxkrE8D","isFallback":false,"isExperimentalCompile":false,"dynamicIds":[52437],"gsp":true,"scriptLoader":[{"async":true,"src":"https://tag.clearbitscripts.com/v1/pk_09728d68daeca7c8a20727cad15914bc/tags.js","referrerPolicy":"strict-origin-when-cross-origin","strategy":"afterInteractive"}]}</script></body></html>