← All articlesBlog · EngineeringPublished 26 September 20265 min read

Two days to rebuild the site, twenty years to know what to ask for

We rebuilt the Jupiter and the Giraffe site in two days with Claude: a new design system, an AI assistant and our SEO intact. Here is what made it possible.

On Friday morning the new Jupiter and the Giraffe site didn't exist in code. By Saturday afternoon it was merged. New design, an AI assistant that answers questions about our work, a rebuilt SEO setup, and 31 commits touching 270 files. Claude wrote most of the code. Claude Design did most of the visual exploration.

That's the headline, and it's true. It also leaves out the part that made it possible. I knew exactly what I wanted before I opened a single session.

What got built

The site runs on Next.js and Payload CMS, with Postgres and Blob storage on Vercel. None of that changed. What changed was everything on top of it.

The redesign started in Claude Design. I explored layouts there, exported the ones I liked as HTML, then had Claude rebuild them inside the existing codebase as a proper design system. We called it Run of Show. It's one stylesheet, a set of shared components, colour tokens that handle dark mode, and Archivo as the display face squeezed to 62% width.

Three homepage concepts side by side in Claude Design: Orbit, Programme and Run of Show

Three homepage directions in Claude Design: Orbit, Programme and Run of Show.

The Run of Show homepage in three colourways: dark, light and orange

Run of Show in the site's own colours: dark, light and orange flood.

The styleguide colour section: the fixed tokens, the palette and the semantic tokens split into light and dark

The Run of Show colours: fixed tokens, the palette, and every semantic token in light and dark.

The small things are what make it feel finished. There's film grain over the hero, a stepped 8-bit loading bar between pages, and a consultation button that slides in once the header scrolls out of view. For the font and the page transitions, Claude built throwaway test pages so I could compare options side by side before picking one. That's a habit I'd keep.

Font test page with the headline set in Orbitron

The throwaway font test page, first with Orbitron, the old display face…

Font test page with the headline set in Archivo at 62% width

…then with Archivo squeezed to 62% width.

AI search that only knows what's on the site

The part people ask about is the assistant. There's a bar at the bottom of every page, and Cmd+K opens a full-screen version. Ask it what we built for a client, or what Built To Fit costs, and it answers from the site's own content with links to the pages it used.

The site assistant answering "How much does Built To Fit cost?" with a link to the offer page

Asking the assistant what Built To Fit costs. It answers from the offer page and links to it.

Here's how it works.

  • OpenRouter for every model call. One API key covers the chat model (Gemini 2.5 Flash-Lite) and the embedding model (Voyage 4 Lite). Swapping the chat model is one environment variable, so I'm not tied to any provider.
  • Vectors in the same Postgres database. pgvector adds a vector column to the database the CMS already uses. There's no separate vector service to pay for or keep in sync.
  • Chunks that know where they came from. Content is split into pieces of about 1,500 characters with a small overlap. Each piece gets its page title and section stamped on before it's embedded.
  • Only changed content gets re-embedded. Each chunk is hashed along with the model name. A reindex skips anything unchanged, and switching embedding models forces a full rebuild on its own.
  • The index stays current. Publishing a case study or article reindexes it on save. Hardcoded pages get picked up by a GitHub Action that runs after every production deploy.
  • Visitors' questions stay private. Chat requests only go to providers that keep no data and don't train on prompts. A Turnstile check and a signed cookie keep bots from running up the bill, and each session is capped at 30 messages.

The retrieval itself is simple. Embed the question, pull the six closest chunks, and give them to the model with strict rules to answer only from that content. One detail I like: a short follow-up such as "and pricing?" gets embedded with the previous question, so it keeps its topic.

There's also a private notes field in the CMS. The assistant reads it for background but never cites or links to it.

SEO I wasn't willing to lose

The old site was WordPress, and some of those URLs still bring in traffic. A redesign is the easiest way to throw that away without noticing. So SEO was a day-one job, not something to tidy up after launch.

  • One validated site config, so every canonical URL uses the www domain
  • Canonical, Open Graph and Twitter tags on every page from a single helper
  • A native sitemap and robots file, replacing the old plugin
  • Structured data for the organisation, the website, articles, case studies and breadcrumbs
  • Permanent redirects from every old WordPress URL pattern
  • Real 404s instead of soft ones, no trailing slashes on internal links, and search results kept out of the index
  • An llms.txt file for AI crawlers
  • Playwright tests that check all of the above, so it can't quietly break later

After launch I submitted the new sitemap in Google Search Console and kept an eye on the old URLs as they moved over to their new homes.

Where I still had to look

Claude is very good at building what you describe. It doesn't look at the page the way a visitor does, and some problems only show up when you do.

Spacing was the obvious one. The header links started as fixed-width boxes, so short words had big gaps around them and long ones were cramped. I had them sized to their text with an even gap between. On wide screens the cookie banner and the floating Book button sat at different heights. Nobody would say why it looked off, but it did, so both now sit 16px from the bottom.

Some catches weren't visual at all. Next renders 404 pages differently, so the cookie consent defaults never loaded there and Google Tag Manager ran without them. The first row of case study images loaded lazily, which slowed the biggest image on the page. None of these were hard to fix. You just have to know to look.

The guardrails that let me go fast

Moving this quickly on a live site only works if mistakes can't reach production easily.

  • Database migrations only run on production builds, so a preview branch can't change the live schema
  • The script that pushes content to production makes me type the database host before it writes anything
  • Contact and careers form input is validated and escaped before it goes into an email
  • Every feature shipped with tests, and a review pass on the AI work caught a dozen edge cases before merge, from oversized requests to half-published drafts

I also kept an AGENTS.md file in the repo that records the decisions as they're made. Which colour tokens to use, where the SEO helpers live, how the assistant gets indexed. Every new Claude session starts by reading it, so day two didn't undo day one.

So, two days?

Yes. But only because the brief was already in my head.

I knew I wanted the vectors in Postgres rather than another service. I knew I wanted every model behind OpenRouter so I could change my mind later. I knew the old WordPress URLs had to redirect on day one, and that consent had to default to off. I knew the spacing was wrong before I could say exactly where.

Claude made the typing fast. Knowing what to type took twenty years. If you want to build like this, that's the part worth investing in first.

Keep reading
More articles

Up next

Cue 99 — Get in touch

What’s slowing your team down?