diff --git a/assets/css/case-studies.scss b/assets/css/case-studies.scss index 31b64f27..a3e4d987 100644 --- a/assets/css/case-studies.scss +++ b/assets/css/case-studies.scss @@ -1210,6 +1210,14 @@ $cs-mint-faint: rgba(42, 217, 194, 0.06); text-transform: uppercase; font-size: 0.78rem; } + // two-line name/role attribution (name defaults to white for the dark + // card — restate it in pine so it reads on the light face) + .cs-pullquote__name { + color: $pine; + } + .cs-pullquote__role { + color: #0b7d72; // $csi-link is defined further down (immersive scope) + } } } @@ -1534,10 +1542,10 @@ html:has(.cs-sticky-nav) { strong { color: #fff; } - ul > li::before { + ul:not(.csi-scale) > li::before { @include csi-grad-solid; } - ol > li::before { + ol:not(.csi-phases):not(.csi-editor__lines) > li::before { color: $cs-pine-dark; background: $cs-mint; } @@ -1767,16 +1775,18 @@ html:has(.cs-sticky-nav) { color: $csi-ink; font-weight: 800; } - // `:not(.csi-list):not(.csi-compare__rows)` — those uls carry their own - // grid/ledger layout; keep the prose bullet/spacing treatment off them - ul:not(.csi-list):not(.csi-compare__rows), - ol { + // `:not(.csi-list):not(.csi-compare__rows):not(.csi-scale)` (and the ol + // equivalents) — those lists carry their own grid/ledger layout; keep the + // prose bullet/spacing treatment off them. Any NEW ul/ol-based shortcode + // must join these chains or it inherits gradient bullets. + ul:not(.csi-list):not(.csi-compare__rows):not(.csi-scale), + ol:not(.csi-phases):not(.csi-editor__lines) { margin: 0 0 1.3rem; padding: 0; list-style: none; } - ul:not(.csi-list):not(.csi-compare__rows) > li, - ol > li { + ul:not(.csi-list):not(.csi-compare__rows):not(.csi-scale) > li, + ol:not(.csi-phases):not(.csi-editor__lines) > li { position: relative; padding-left: 1.75rem; margin-bottom: 0.7rem; @@ -1785,7 +1795,7 @@ html:has(.cs-sticky-nav) { content: none; } } - ul:not(.csi-list):not(.csi-compare__rows) > li::before { + ul:not(.csi-list):not(.csi-compare__rows):not(.csi-scale) > li::before { content: ""; position: absolute; left: 0; @@ -1795,10 +1805,10 @@ html:has(.cs-sticky-nav) { border-radius: 2px; @include csi-grad-solid; } - ol { + ol:not(.csi-phases):not(.csi-editor__lines) { counter-reset: csi-ol; } - ol > li::before { + ol:not(.csi-phases):not(.csi-editor__lines) > li::before { counter-increment: csi-ol; content: counter(csi-ol); position: absolute; @@ -2980,6 +2990,528 @@ html:has(.cs-sticky-nav) { .button { margin: 0; } + // custom CTA bullet list (e.g. Cursor's "Terraform ceilings" callout) — + // centred band, left-aligned list, gradient square bullets (the pseudo bg + // is dropped in print; the list still reads) + ul { + list-style: none; + display: inline-block; + margin: 1.1rem auto 1.2rem; + padding: 0; + text-align: left; + li { + position: relative; + padding-left: 1.35rem; + margin: 0.5rem 0; + font-size: 1.05rem; + line-height: 1.55; + color: #d3e2e1; + &::before { + content: ""; + position: absolute; + left: 0; + top: 0.5em; + width: 9px; + height: 9px; + border-radius: 3px; + @include csi-grad-solid; + } + } + } + } + + // --------------------------------------------------------------------------- + // ARTICLE SECTIONS — csi-section article="true": a merged, multi-topic card + // where one band holds what would otherwise be several sections. The whole + // column (head + prose) is CENTRED by capping the section's container to the + // content width — without that cap the 1320px container leaves a huge empty + // gutter on the right of wide screens. Prose text stays a readable 760px; + // components (rail, ledgers, editor, scale, inline charts/figures) breathe + // at the full 980px. In-card topics are `### h3` sub-heads, optionally led + // by a `.csi-prose-kicker` span (the sub-block's eyebrow). Keep the :not() + // chains in sync with the prose list rules above. + // --------------------------------------------------------------------------- + .csi-section--article .csi-container { + max-width: calc(980px + 5.2rem); // content + the container's 2.6rem pads + } + .csi-section--article .csi-prose { + max-width: 980px; + > p, + > h3, + > ul:not(.csi-list):not(.csi-compare__rows):not(.csi-scale), + > ol:not(.csi-phases):not(.csi-editor__lines) { + max-width: 760px; + } + } + .csi-prose h3 { + font-family: $header-font; + font-size: 1.45rem; + font-weight: 800; + line-height: 1.3; + color: $csi-ink; + margin: 3.2rem 0 1.1rem; + // small gradient dash above each sub-head (decorative pseudo — print drops + // it; the heading still reads) + &::before { + content: ""; + display: block; + width: 34px; + height: 3px; + border-radius: 2px; + @include csi-grad-solid; + margin-bottom: 0.85rem; + } + &:first-child { + margin-top: 0; + } + } + // markdown headings in prose are wrapped in anchor links by the heading + // render hook — keep them heading-coloured, and swap the hover underline + + // # symbol to mint. The `.csi-section` prefix is load-bearing: the + // pine-face link override (`.csi-section--pine .csi-prose a:not(.button)`) + // carries four classes, so this must too or headings render mint on dark. + .csi-section .csi-prose h3 a:not(.button) { + color: inherit; + font-weight: inherit; + background-image: none; + } + .csi-prose h3 .heading-text::after { + background-color: $cs-mint; + } + .csi-prose h3 .heading-anchor-symbol { + color: $cs-mint; + } + // sub-block eyebrow inside an h3 (``) + .csi-prose-kicker { + display: block; + font-size: 0.68rem; + font-weight: 800; + letter-spacing: 0.16em; + text-transform: uppercase; + color: $csi-link; + margin-bottom: 0.5rem; + } + // inline chart images in prose (markdown `![alt](src)`) — block, rounded, + // full column width + .csi-prose img { + display: block; + width: 100%; + height: auto; + border-radius: 14px; + margin: 0.4rem 0 1.5rem; + } + .csi-section--pine, + .csi-section--pine-deep, + .csi-section--gradient { + .csi-prose h3 { + color: #fff; + } + .csi-prose-kicker { + color: $cs-mint; + } + // charts carried into a dark band need the same frame as csi-media images + .csi-prose img { + box-shadow: + 0 26px 54px -30px rgba(0, 0, 0, 0.6), + 0 0 0 1px rgba(42, 217, 194, 0.18); + } + } + // csi-figure — CSS-drawn figure embedded mid-prose instead of in a split's + // media column + .csi-inline-figure { + max-width: var(--csi-fig-max, 640px); + margin: 2.1rem auto; + } + + // --------------------------------------------------------------------------- + // PHASES — engagement roadmap rail (csi-phases): the month-by-month arc of + // an engagement as numbered stops along a gradient rail. The numeral is real + // text with `.csi-grad` (auto face recolour + print fallback) and the rail + // segment is a REAL element (not a pseudo background) so it prints. + // 4-up on desktop, single column ≤900px. + // --------------------------------------------------------------------------- + .csi-phases { + list-style: none; + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 0 1.2rem; + max-width: 1120px; + margin: 2.5rem auto 0; + padding: 0; + text-align: left; + @media (max-width: 900px) { + grid-template-columns: 1fr; + gap: 1.6rem 0; + max-width: 480px; + } + } + .csi-phase { + &__marker { + display: flex; + align-items: center; + gap: 0.65rem; + margin-bottom: 0.9rem; + } + &__num { + font-family: $header-font; + font-size: 0.82rem; + font-weight: 800; + letter-spacing: 0.08em; + } + &__line { + flex: 1 1 auto; + height: 2px; + border-radius: 1px; + @include csi-grad-solid; + opacity: 0.45; + } + &__date { + display: block; + font-size: 0.66rem; + font-weight: 800; + letter-spacing: 0.14em; + text-transform: uppercase; + color: $csi-link; + margin-bottom: 0.35rem; + } + &__name { + display: block; + font-family: $header-font; + font-size: 1rem; + font-weight: 700; + line-height: 1.4; + color: $csi-ink; + } + } + .csi-section--pine, + .csi-section--pine-deep, + .csi-section--gradient { + .csi-phase__date { + color: $cs-mint; + } + .csi-phase__name { + color: #fff; + } + .csi-phase__line { + opacity: 0.6; + } + } + + // --------------------------------------------------------------------------- + // SCALE — order-of-magnitude inventory strip (csi-scale): gradient magnitude + // word on the left, what it counts on the right. The qualitative sibling of + // the csi-compare ledger — compare owns exact before/after figures, this + // owns "how big is the estate today". Recolours per face. + // --------------------------------------------------------------------------- + .csi-scale { + list-style: none; + max-width: 860px; + margin: 2rem auto 0; + padding: 0; + } + .csi-scale__item { + display: grid; + grid-template-columns: minmax(0, 0.44fr) minmax(0, 1fr); + align-items: baseline; + column-gap: 1.5rem; + padding: 0.9rem 0; + text-align: left; + @media (max-width: 640px) { + grid-template-columns: 1fr; + row-gap: 0.15rem; + padding: 0.8rem 0; + } + } + .csi-scale__item + .csi-scale__item { + border-top: 1px solid $csi-line; + } + .csi-scale__value { + font-family: $header-font; + font-size: 1.85rem; + font-weight: 900; + line-height: 1.08; + letter-spacing: -0.01em; + text-align: right; + @include csi-grad-light; + @media (max-width: 640px) { + text-align: left; + font-size: 1.55rem; + } + } + .csi-scale__label { + font-size: 1.02rem; + line-height: 1.55; + color: $csi-ink-soft; + } + .csi-section--pine, + .csi-section--pine-deep, + .csi-section--gradient { + .csi-scale__value { + @include csi-grad-bright; + } + .csi-scale__label { + color: #c4d4d3; + } + } + .csi-section--pine .csi-scale__item + .csi-scale__item, + .csi-section--pine-deep .csi-scale__item + .csi-scale__item, + .csi-section--gradient .csi-scale__item + .csi-scale__item { + border-top-color: rgba(255, 255, 255, 0.1); + } + + // --------------------------------------------------------------------------- + // CALLOUT — inset spotlight panel (csi-callout): tinted card, gradient left + // bar, optional uppercase chip. For load-bearing asides that aren't quotes + // (cs-pullquote stays reserved for quotes). The left bar is a pseudo + // (decorative — print drops it); the border + tint keep the panel legible + // in the PDF. + // --------------------------------------------------------------------------- + .csi-callout { + position: relative; + max-width: 860px; + margin: 1.9rem auto; + padding: 1.35rem 1.7rem 1.35rem 1.95rem; + background: linear-gradient(135deg, rgba(42, 217, 194, 0.09), rgba(209, 145, 191, 0.08)); + border: 1px solid rgba(42, 217, 194, 0.28); + border-radius: 14px; + overflow: hidden; + text-align: left; + &::before { + content: ""; + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 4px; + @include csi-grad-solid; + } + &__chip { + display: inline-block; + font-size: 0.62rem; + font-weight: 800; + letter-spacing: 0.16em; + text-transform: uppercase; + padding: 0.28rem 0.65rem; + border-radius: 999px; + @include csi-grad-solid; + color: #06201f; + margin-bottom: 0.7rem; + } + } + .csi-callout__body p { + margin: 0; + font-size: 1.02rem; + line-height: 1.65; + } + .csi-callout__body p + p { + margin-top: 0.7rem; + } + .csi-section--pine, + .csi-section--pine-deep, + .csi-section--gradient { + .csi-callout__body p { + color: #d3e2e1; + strong { + color: #fff; + } + } + } + + // --------------------------------------------------------------------------- + // EDITOR — csi-editor rules panel: stylized editor window (chrome dots + + // filename tab + CSS-counter line numbers). Deliberately a DARK panel on + // every face — it reads as a code window, not a card, so no face overrides. + // Line numbers are ::before *content* (text survives print; only pseudo + // background-image is dropped). + // --------------------------------------------------------------------------- + .csi-editor { + max-width: 860px; + margin: 2rem auto 0; + background: $cs-pine-dark; + border: 1px solid rgba(42, 217, 194, 0.24); + border-radius: 14px; + overflow: hidden; + text-align: left; + box-shadow: 0 26px 54px -34px rgba(0, 0, 0, 0.55); + &__chrome { + display: flex; + align-items: center; + gap: 0.42rem; + padding: 0.7rem 1rem; + background: rgba(255, 255, 255, 0.04); + border-bottom: 1px solid rgba(255, 255, 255, 0.08); + } + &__light { + width: 10px; + height: 10px; + border-radius: 50%; + background: rgba(255, 255, 255, 0.16); + } + &__tab { + margin-left: 0.7rem; + font-family: "SF Mono", "Cascadia Code", Menlo, Consolas, monospace; + font-size: 0.72rem; + letter-spacing: 0.03em; + color: #8fd9cd; + padding: 0.26rem 0.7rem; + background: rgba(42, 217, 194, 0.1); + border: 1px solid rgba(42, 217, 194, 0.25); + border-radius: 7px; + } + &__lines { + list-style: none; + margin: 0; + padding: 0.85rem 0; + counter-reset: csi-editor-line; + } + &__line { + counter-increment: csi-editor-line; + position: relative; + padding: 0.42rem 1.4rem 0.42rem 3.6rem; + font-size: 0.95rem; + line-height: 1.55; + color: #c9dad9; + &:nth-child(odd) { + background: rgba(255, 255, 255, 0.025); + } + &::before { + content: counter(csi-editor-line, decimal-leading-zero); + position: absolute; + left: 1.1rem; + top: 0.56rem; + font-family: "SF Mono", "Cascadia Code", Menlo, Consolas, monospace; + font-size: 0.7rem; + letter-spacing: 0.04em; + color: rgba(143, 217, 205, 0.55); + } + a:not(.button) { + color: $cs-mint; + } + strong { + color: #fff; + } + } + } + + // --------------------------------------------------------------------------- + // FIGURE — CURSOR TERRALITH (csi-split figure="cursor/terralith"). The + // monolithic production workspace drawn as an over-stuffed editor-style + // state-file window (nod to the Cursor IDE) with drift noise in the cell + // grid and friction tags beneath. Drawn with REAL elements; styled for the + // PINE face it lives on (the challenge split) — no light-face variant. + // --------------------------------------------------------------------------- + .csi-fig--cursor-terralith { + display: flex; + flex-direction: column; + gap: 0.9rem; + width: 100%; + } + .csi-fig-cterra__window { + background: $cs-pine-dark; + border: 1px solid rgba(42, 217, 194, 0.24); + border-radius: 14px; + overflow: hidden; + box-shadow: 0 26px 54px -30px rgba(0, 0, 0, 0.6); + } + .csi-fig-cterra__bar { + display: flex; + align-items: center; + gap: 0.4rem; + padding: 0.65rem 0.95rem; + background: rgba(255, 255, 255, 0.05); + border-bottom: 1px solid rgba(255, 255, 255, 0.08); + } + .csi-fig-cterra__dot { + width: 9px; + height: 9px; + border-radius: 50%; + background: rgba(255, 255, 255, 0.16); + } + .csi-fig-cterra__file { + margin-left: 0.55rem; + font-family: "SF Mono", "Cascadia Code", Menlo, Consolas, monospace; + font-size: 0.7rem; + letter-spacing: 0.03em; + color: #8fd9cd; + } + .csi-fig-cterra__cells { + display: grid; + grid-template-columns: repeat(12, 1fr); + gap: 4px; + padding: 1rem; + i { + display: block; + aspect-ratio: 1; + border-radius: 2.5px; + background: rgba(42, 217, 194, 0.14); + &:nth-child(4n) { + background: rgba(42, 217, 194, 0.24); + } + // drift noise — scattered off-pattern pink cells + &:nth-child(7n) { + background: rgba(209, 145, 191, 0.42); + } + &:nth-child(23n) { + background: rgba(209, 145, 191, 0.75); + } + } + } + .csi-fig-cterra__status { + padding: 0.8rem 1rem 0.95rem; + border-top: 1px solid rgba(255, 255, 255, 0.08); + strong { + display: block; + font-family: $header-font; + font-size: 0.95rem; + color: #fff; + } + span { + font-size: 0.78rem; + line-height: 1.5; + color: #9fb6b5; + } + } + .csi-fig-cterra__tags { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + justify-content: center; + } + .csi-fig-cterra__tag { + font-size: 0.68rem; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; + padding: 0.35rem 0.75rem; + border-radius: 999px; + border: 1px solid rgba(209, 145, 191, 0.45); + color: #e8c9de; + background: rgba(209, 145, 191, 0.12); + } + + // --------------------------------------------------------------------------- + // COMPARE — delta pill (`delta:` inner field): the "Change" column of a + // source table as a gradient chip after the new-world value. The pill resets + // the clip that csi-compare__after puts on its text (the gradient there is + // background-clipped) so the chip keeps solid dark text on a gradient bg — + // element backgrounds (not pseudo) survive print. + // --------------------------------------------------------------------------- + .csi-compare__delta { + display: inline-block; + margin: 0.28rem 0 0 0.4rem; + padding: 0.16rem 0.6rem; + border-radius: 999px; + font-size: 0.68rem; + font-weight: 800; + letter-spacing: 0.05em; + text-transform: uppercase; + line-height: 1.35; + vertical-align: middle; + @include csi-grad-solid; + -webkit-background-clip: border-box; + background-clip: border-box; + color: #06201f; + -webkit-text-fill-color: #06201f; } } @@ -3075,6 +3607,7 @@ html:has(.cs-sticky-nav) { .csi-questions__outro-main strong, .csi-compare__col--after, .csi-compare__after, + .csi-scale__value, .cs-hero__title .text-gradient { background: none !important; -webkit-background-clip: border-box !important; @@ -3120,8 +3653,23 @@ html:has(.cs-sticky-nav) { .csi-fig-terralith__mono, .csi-fig-terralith__stack, .csi-timeline, - .csi-question { + .csi-question, + .csi-phase, + .csi-scale__item, + .csi-callout, + .csi-editor, + .csi-fig-cterra__window, + .csi-list__item, + .csi-prose img, + .csi-inline-figure { break-inside: avoid; } + + // the compare delta pill keeps solid dark text on its gradient chip (it is + // NOT clipped text) — undo the __after solid-teal fallback it would inherit + .csi-compare__delta { + -webkit-text-fill-color: #06201f !important; + color: #06201f !important; + } } } diff --git a/content/case-studies/cursor.md b/content/case-studies/cursor.md new file mode 100644 index 00000000..5ad82753 --- /dev/null +++ b/content/case-studies/cursor.md @@ -0,0 +1,348 @@ +--- +title: "75% Faster Plans, 2x Daily Applies: How Cursor Rebuilt Its Terraform Workflow with Masterpoint" +weight: 1 +description: "At Masterpoint, we focused on Terraform and IaC improvements so our client Cursor could focus on making their users extraordinarily productive. Plan time dropped from 10+ minutes to roughly 2, weekly infrastructure PRs grew from 194 to 500+, and the median blast radius shrank 91%." + +layout: immersive + +# Hero +eyebrow: "CASE STUDY SUCCESS STORY" +client: "Cursor" +client_logo: /img/case-studies/cursor/cursor-logo-white.svg +client_logo_height: 30px +hero_title: "75% Faster Plans, 2x Daily Applies: How Cursor Rebuilt Its Terraform Workflow with Masterpoint" + +# At-a-glance stat strip (appears under hero) +stat_bar: + - value: "~8 → ~2 min" + label: "median plan time (production)" + - value: "194 → 500+" + label: "deployment PRs / week — a 157% increase" + - value: "54 → 5" + label: "median resources affected — a 91% smaller blast radius" + - value: "40k+" + label: "Terraform resources are managed using the new platform" + +# Preview / OG +preview_image: /img/case-studies/cursor/deployment-frequency-stat.png +og_img: /img/case-studies/cursor/deployment-frequency-stat.png + +sitemap: + priority: 0 + +callout: >- +

If your team is hitting Terraform ceilings like:

+ +

Masterpoint can help. We've done this work at + scale, for engineering organizations that can't afford to slow down. + Get in touch →

+--- + +{{< csi-testimonial tldr="true" variant="pine" >}} +At Masterpoint, we focused on **Terraform and IaC improvements** so our client Cursor could focus on making their users **extraordinarily productive**. +{{< /csi-testimonial >}} + +{{< csi-section title="Key Value Delivered" variant="light" align="center" accent="true" >}} +{{< csi-impact cols="2" >}} +icon: fa-gauge-high +title: Dramatically faster plans +body: Plan time dropped significantly. Originally plan time had spikes of 10+ minutes; after our work, plan time was roughly 2 minutes. +--- +icon: fa-code-pull-request +title: Improved delivery speed +body: Engineers shipped 157% more PRs per week after the engagement, and have increased shipping cadence since. +--- +icon: fa-calendar-check +title: More frequent, safer deploys +body: Weekly infrastructure PRs grew from 194 to 500+, and fewer plans were abandoned as the apply-to-plan ratio improved from 55% to 64%. +--- +icon: fa-bullseye +title: Safer, more contained changes +body: The median Terraform run now touches 5 resources instead of 54 — a 91% smaller blast radius, so engineers can reason about exactly what a change will affect before applying it. +{{< /csi-impact >}} +{{< /csi-section >}} + +{{< csi-section id="the-challenge" eyebrow="The Problem" title="Infrastructure That Couldn't Keep Up" variant="pine" article="true" >}} +By late 2025, Cursor's Terraform setup had become one of the biggest friction points in the engineering org. The company behind the Cursor IDE experienced issues familiar to fast-growing startups: infrastructure code written quickly, then scaled by copy-pasta rather than through careful design. + +Those early Terraform patterns were replicated at machine speed as engineers dogfooded Cursor. They were copied and instantiated hundreds of times without the architectural guardrails needed to keep the system manageable. The result was a classic [terralith](/blog/terralith-monolithic-terraform-architecture/): critical infrastructure was managed as a **single monolithic production workspace with over 7,000 resources in one state file**. + +{{< csi-figure name="cursor/terralith" >}} + +And because that workspace was so large, it was too slow. + +{{< cs-pullquote name="Travis McPeak" title="Security Lead" company="Cursor" variant="light" >}} +We had one giant workspace that took way too long to plan. It was killing us. +{{< /cs-pullquote >}} + +### But the problem wasn't just the lack of speed. It was a lack of engineering confidence in the IaC system. + +Issues included: + +- The AWS console was used to make changes during incidents and these fixes were never rolled into TF, and so were later inadvertently reverted. +- Managing ECS deployments through Terraform caused constant drift in the production terralith, flooding PR diffs with hundreds of unrelated changes. + +Over time, the team **stopped trusting the system**, let alone reading the diffs. + +{{< cs-pullquote name="Travis McPeak" title="Security Lead" company="Cursor" variant="light" >}} +We would have engineers click apply on prod workspaces that had 120 ECS service changes. The ECS services would change all the time because of drift, so the team became desensitized to large Terraform plan changes. +{{< /cs-pullquote >}} + +This confusion caused downtime, such as a network firewall change that caused a 10 minute outage. + +The existing platform, Terraform Cloud, introduced some friction too: + +- Workspace management relied on manual ClickOps configuration for each new workspace. +- The SSO experience was inconsistent. +- TFC's resource-under-management (RUM) pricing model made it daunting to scale. +{{< /csi-section >}} + +{{< csi-section id="the-work" eyebrow="The Engagement" title="What Masterpoint Did" variant="light" article="true" >}} +Masterpoint came in for a systematic overhaul, working across **the architecture, the platform, and the developer workflow**. + +{{< csi-phases >}} +date: November 2025 +title: Audit and High Leverage Fixes +--- +date: December 2025 +title: Spacelift Migration Begins +--- +date: January to February 2026 +title: Bulk Migration +--- +date: February to May 2026 +title: AI Agent Guardrails And Additional Improvements +{{< /csi-phases >}} + +### Phase 01 · November 2025 Audit and High Leverage Fixes + +The engagement opened with an audit of Cursor's infrastructure: + +{{< csi-list >}} +icon: fa-cloud +title: cloud environments +--- +icon: fa-code +title: IaC setup +--- +icon: fa-arrows-rotate +title: CI/CD pipelines +--- +icon: fa-network-wired +title: networking +--- +icon: fa-chart-line +title: observability +{{< /csi-list >}} + +Within a week, Masterpoint delivered an audit report, a best practices checklist, and a security scan. The findings included **IAM duplication accounted for 70% of the production TF state** and noisy plan diffs caused engineer fatigue. + +The audit phase targeted the highest-leverage fixes first: IAM resource deduplication, workspace trigger and path filter corrections so plans only ran when relevant code changed, and initial provider alias splits to begin isolating staging and ML infrastructure from the main production workspace. + +By November 25th, the IAM deduplication fixes had landed. + +The number of production resources dropped from 8,480 to 4,593, a **46% reduction**. Mean plan time fell from 8.1 minutes to 4.9 minutes, a **39% improvement**. The P95 plan time improved even more. + +{{< csi-compare before_label="Before (Nov 20–24)" after_label="After (Nov 25–Dec 8)" >}} +label: Resource Count +before: 8,480 +after: 4,593 +delta: 45.8% reduction (3,887 resources removed) +--- +label: Mean +before: 488.8s (8.1 min) +after: 296.6s (4.9 min) +delta: 39.3% faster +--- +label: P50 (Median) +before: 423s (7.1 min) +after: 272s (4.5 min) +delta: 35.7% faster +--- +label: P95 +before: 749s (12.5 min) +after: 414s (6.9 min) +delta: 44.7% faster +--- +label: Sample Size +before: 38 runs +after: 184 runs +{{< /csi-compare >}} + +This was accomplished without touching the workspace structure, but the systems could still be improved. + +### Phase 02 · December 2025 Spacelift Migration Begins + +With the first phase complete, Masterpoint turned to the platform. + +As mentioned above, TFC's ClickOps workspace management, SSO troubles, and resource-under-management pricing were all inhibiting Cursor's velocity and growth. + +Masterpoint recommended a move to [Spacelift](https://spacelift.io/) to address these issues. + +The team kicked off the Spacelift migration in mid-December, starting with the groundwork: + +- naming and tagging standards +- AWS multi-account IAM role architecture +- Okta SSO configuration + +{{< csi-callout label="The Pilot" >}} +Rather than migrating everything at once, a **low-risk pilot Spacelift stack** (the equivalent of a TFC workspace) was used to validate the approach. The end-to-end fully automated pilot project was **completed within days**. +{{< /csi-callout >}} + +Masterpoint also began evaluating a full migration from the Terraform runtime to [OpenTofu](https://opentofu.org/). + +### Phase 03 · January to February 2026 Bulk Migration + +With a plan covering a migration of dozens of TFC workspaces across four phases, the team worked systematically. By late January, the bulk of workspaces had been migrated to Spacelift stacks with **no operational downtime** for the Cursor engineering organization. + +By February, the migration was done. All workspaces had been moved from TFC to Spacelift and the runtime was converted from Terraform to OpenTofu. Migrating to OpenTofu freed Cursor from licensing constraints and unlocked capabilities unavailable or paywalled in Terraform, such as **state encryption, OpenTelemetry support, and provider iteration**. + +As part of the final migration work, the production workspace was reduced by splitting out various provider-aliased resources into dedicated stacks, continuing the decomposition work that had started with IAM deduplication in November. + +### Phase 04 · February to May 2026 AI Agent Guardrails And Additional Improvements + +After the migration was completed, Masterpoint continued to improved system usability and speed by: + +- restructuring Route53 DNS API requests into optimized, dedicated TF modules to address AWS's strict 5 requests/second limit +- continuing to break up large state files into narrower root modules, allowing for faster plans (further reducing critical infrastructure plans from roughly 5 minutes to under 2 minutes) and decreased blast radius +- implementing child module versioning with OCI registries to enable staged rollouts and safer change control of critical TF resources +- resolving the ECS drift issue by using the ["Task Definition Template Pattern"](https://newsletter.masterpoint.io/p/deploying-your-apps-into-ecs) +- implementing OpenTofu's [OTel tracing](https://opentofu.org/docs/internals/tracing/) to set up the Cursor team for longterm visibility into their IaC throughput + +Because Cursor's engineering team **uses Cursor to write Terraform**, Masterpoint embedded architectural knowledge directly into the codebase as AI agent skills and rules. + +This AI context encodes the decisions that AI models cannot anticipate on their own: + +{{< csi-editor filename=".cursor/rules" >}} +when to create a new root module vs. extend an existing one +how to scope blast radius in a root module +how to break up a high blast radius monolithic root module +data source patterns and optimizations +how to use OCI-sourced child modules +security practices, such as TF module SHA pinning +debugging performance bottlenecks, through methods such as logging and OpenTelemetry traces +{{< /csi-editor >}} + +Every IaC optimization Masterpoint delivered was paired with instructions to **prevent anti-patterns from being reintroduced**. + +{{< cs-pullquote name="Ravi Rahman" title="Software Engineer" company="Cursor" >}} +The AI agent skills and rules help us build our IaC correctly while at the same time moving faster. +{{< /cs-pullquote >}} +{{< /csi-section >}} + +{{< csi-section id="the-results" title="The Results" variant="pine" accent="true" article="true" >}} +### What Cursor's Infrastructure as Code Manages + +The Cursor infrastructure today includes: + +{{< csi-scale >}} +value: hundreds +label: of ECS services with tens of thousands of live running tasks +--- +value: thousands +label: of EC2 instances +--- +value: dozens +label: of Redis clusters +--- +value: a few dozen +label: databases +--- +value: in the triple digits +label: of ALB and NLB load balancers +{{< /csi-scale >}} + +In all **40k+ Terraform resources** are managed using the new platform. All of this exists in **100+ narrow, independent root modules**, with OpenTofu, on Spacelift, using Okta SSO, stored in S3-backed state, and paired with AI agent rules to keep the architecture clean as the codebase grows. + +### Numbers That Matter + +{{< csi-compare before_label="Before" after_label="After" >}} +label: Median plan time (production) +before: ~8 min +after: ~2 min +--- +label: Deployment PRs / week +before: ~194 +after: 500+ +delta: +157% +--- +label: Median resources affected +before: 54 +after: 5 +delta: 91% reduction in blast radius +{{< /csi-compare >}} + +### Plan time went from 10+ minutes to 2 minutes + +The production workspace plan time dropped from over 10+ minutes, with spikes to 15 minutes, during the November baseline to around 2 minutes by mid 2026. + +This is an improvement of roughly **75% from where the engagement started**, and more than **80% from the pre-engagement peak**. + +![Deploy time before and after: average plan + apply took 10+ minutes before, 2 minutes now — 80% less time per Terraform run](/img/case-studies/cursor/plan-time-column-compare.png) + +### Deployment frequency increased + +Weekly merged PRs against infrastructure as code went from approximately 194 per week to over 500 a week, a **157% increase**. They've only accelerated since then. + +![2.6x more PRs shipped: from 194 changes per week in October 2025 to 500+ in May 2026, a 157% jump in deployment frequency](/img/case-studies/cursor/deployment-frequency-stat.png) + +### The productivity lift was significant + +This gain wasn't from growing the engineering organization: a controlled same-cohort analysis of **34 engineers** active both before and after the Masterpoint engagement found that PR throughput grew by **121%**. + +{{< csi-compare before_label="Pre-engagement" after_label="End of Engagement" >}} +label: Cohort throughput +before: 63 PRs/wk +after: 140 PRs/wk +delta: +121% +--- +label: Per-active-week cadence +before: 5.37 PRs/author/wk +after: 9.19 PRs/author/wk +delta: +71% +{{< /csi-compare >}} + +### Infrastructure became democratized + +Looking beyond the controlled same-cohort set of engineers, **89% of all engineers who work with infrastructure now ship Terraform PRs each month**. + +Previously, workspace creation required manual ClickOps and admin access. Today, engineers create and manage their own stacks. The number of separately managed modules went from **26 to 100+**. Engineers are now creating their own product/domain scoped infrastructure instead of jumbling it in the primary monolithic workspace. + +![Terraform root module workspaces grew from 21 in October 2025 to 141 in May 2026 — up 571% — as self-service workspaces replaced monolithic antipatterns](/img/case-studies/cursor/tf-workspaces.png) +{{< /csi-section >}} + +{{< csi-section eyebrow="The Results" title="What Changed for the Team" variant="light" article="true" >}} +### Engineers know what an IaC Terraform change will touch + +Before the engagement, engineers couldn't predict what a change would actually touch in a workspace. A database might live in a workspace named for networking infrastructure, so even finding where something was managed required tribal knowledge. Dependencies between workspaces were just as opaque: touching one piece of infrastructure could ripple into systems that had nothing to do with the change — or surface long-standing drift that did. Plans intended for one system would silently queue in unrelated workspaces, waiting for the next person to find them with no context on where they came from or whether they were safe to apply. + +With smaller, focused stacks, plans are scoped to the change at hand. The median Terraform run now touches just **5 resources instead of 54** — a 91% smaller blast radius — so engineers know precisely what a plan will affect before they run it. + +![91% reduction in blast radius: a median Terraform run once touched 54 resources, now it averages just 5](/img/case-studies/cursor/dependency-graph.png) + +{{< cs-pullquote name="Ravi Rahman" title="Software Engineer" company="Cursor" >}} +The Terraform experience has gotten way better. For the first time since I've been here, we just merge and apply. If something's wrong, the system lets us know. It's fast and moves at the speed we need. +{{< /cs-pullquote >}} + +### Architectural flexibility enables the business and product delivery + +Before the engagement, the terralith made architectural changes expensive and risky. Touching one piece of infrastructure meant disrupting unconnected components. + +With narrow stacks owning a focused piece of infrastructure, the Cursor engineering team can more easily modify their architecture. + +New services, providers, and cloud targets can be added as their own stacks, which is a foundation that **directly enables expansion into multi-cloud infrastructure** as Cursor continues to scale. + +### Cursor's agents are set up for future success + +Since Cursor's engineers rely on Cursor to write their own Terraform, Masterpoint embedded the new architecture into AI agent rules and skills that sit directly within the codebase. + +These rules capture the patterns and decisions that LLMs can't figure out on their own, setting the team up to **consistently ship high-quality infrastructure code**, now and as the system evolves. +{{< /csi-section >}} + +{{< csi-testimonial name="Travis McPeak" title="Security Lead" company="Cursor" variant="pine" image="/img/bg_our_word.jpg" >}} +Masterpoint didn't just fix our IaC. They gave our entire engineering org the **confidence to move fast**. We went from a system people were afraid to touch Terraform to where nearly every engineer is quickly and assuredly shipping infrastructure changes every week. +{{< /csi-testimonial >}} diff --git a/docs/case-studies.md b/docs/case-studies.md index 54402cc6..e495d70b 100644 --- a/docs/case-studies.md +++ b/docs/case-studies.md @@ -24,11 +24,11 @@ July 2026 once Power Digital, its last user, was rebuilt on immersive.) | Layout | Template | Used by | Body class | Style prefix | | ------------- | ------------------------------------- | ------------------------------------------------------- | ----------------------------------- | ----------------------- | | **Modern** | `layouts/case-studies/single.html` | Default for any case study without a `layout:` override | `case-study-modern` | `.case-study-modern` | -| **Immersive** | `layouts/case-studies/immersive.html` | MarketSpark, Power Digital (opt-in via `layout: immersive`) | `case-study-modern case-study-immersive` | `.case-study-immersive` | +| **Immersive** | `layouts/case-studies/immersive.html` | MarketSpark, Power Digital, Cursor (opt-in via `layout: immersive`) | `case-study-modern case-study-immersive` | `.case-study-immersive` | Routing is via Hugo's `layout:` front matter param. A case study that does -**not** specify `layout:` uses `single.html` (the modern layout). MarketSpark -and Power Digital opt into immersive with `layout: immersive`. +**not** specify `layout:` uses `single.html` (the modern layout). MarketSpark, +Power Digital, and Cursor opt into immersive with `layout: immersive`. The **modern** layout was designed from scratch and is the default for new case studies. The @@ -153,12 +153,38 @@ All shortcodes are in `layouts/shortcodes/cs-*.html` and styled under - **New shortcode files in `layouts/shortcodes/` are not picked up by a running `hugo serve`.** Restart serve after creating a new shortcode template. Modifying an existing one hot-reloads fine. -- **`