Building Jigg.AI itself, with Claude Code and Astro
Primary tool: Claude CodeBuilt with: Claude Opus 4.8, ChatGPT 5.6Stack: Astro 7.1, GitHub, Netlify, Cloudflarepricing as of jul 2026last verified jul 2026
That claim is the whole architecture, so here it is as files — one content entry, and the four page files that read it:
site/src/
├─ content.config.ts the schema all four views validate against
├─ content/builds/website.mdx ← the one entry (this post)
└─ pages/
├─ index.astro → home
├─ builds/index.astro → archive
├─ builds/[slug].astro → this build log
└─ tools/index.astro → tools index
Those four pages all read that same collection — none of it is bespoke to this
post, so you could lift this structure wholesale for your own site. (The standalone
pages — About, Privacy, the disclosure — are a separate pages collection; they
don’t touch the build data at all.)
The honest process
The site scaffold and the four page templates were the smooth part. Getting the repository onto GitHub was not — and every snag traced back to my own setup, not to Claude Code or GitHub. Tagged honestly:
Pushed over HTTPS with a passwordMy setup
The first push used HTTPS with a plain account password. GitHub retired that path for Git operations years ago — it needs a token or an SSH key. Dead on arrival.
Registered the SSH key as a read-only deploy keyMy setup
Switching to SSH, I added the key as a repo deploy key. Those default to read-only, so the handshake succeeded and the push was still denied. Recreating the repo didn’t help — the fix was never the repo, it was the key’s scope.
Wrong Git identity, and two keys in the agentMy setup
The first commit landed under a leftover global user.email from another
project. On top of that, ssh-add -l showed the old and new keys both loaded, so
which one GitHub actually accepted was ambiguous — it kept authenticating through
the stale, read-only entry.
What worked
A repo-local Git identity (git config --local), a single account-level SSH key
(not a deploy key, so there’s no read/write toggle to fight), and clearing the
agent down to just that one key. Clean first commit, correct author, full
scaffold pushed. Boring, but honest.
How this was actually made — worth a note, because it’s a technique you can steal. The concept and the page designs didn’t come from one AI in one pass. Most of the thinking was done in Claude (Opus 4.8), with ChatGPT (5.6) pulled in as a second opinion; the UI mockups were made by Claude, then critiqued by ChatGPT, with the useful feedback folded back in by Claude. Having one model red-team another’s work caught things the first missed. Simple move, real payoff.
An honest correction, added later: this section used to promise “the full back-and-forth, with the actual critiques and prompts” in the repro pack — and the pack shipped without it, because none of it was ever captured into the repo. The original chat histories may still exist outside it, so this is a capture failure rather than a lost artifact, and it’s recoverable. What won’t happen is reconstructing the exchange from memory and presenting it as the original: a plausible-looking transcript written after the fact is a fabrication, however accurate it feels. Capturing this material during the build is now an explicit pipeline step, and the pack states exactly what it has and where it came from.
The test
For a site build the check isn’t a question set — it’s whether the foundation actually holds. What’s verified so far:
- 1
- collection drives the whole site
- 4
- views from that one source
- 0
- page edits to add a build
Adding a markdown file lights up the home page, the archive, its own detail page,
and the tools index with no page-code changes — the core invariant passes. The
“Runs on this site” badge and the freshness states render straight from
frontmatter — though only two of the three freshness states have actually been
seen render: verified and recheck-due. No build has been archived yet, so that
path is still untested. And it’s shipped: deployed on Netlify and live at
jigg.ai, on a custom domain with HTTPS.
Three checks are logged as pending rather than claimed, not one: the Lighthouse
performance pass (never run — Lighthouse now runs on every deploy, so there’ll be a
real number instead of an adjective), the accessibility audit (the site is built
for it — semantic landmarks, skip link, heading order, visible focus rings — but it
has never been formally audited, no axe run, contrast unmeasured), and the
archived freshness state above. An earlier version of this page said “the one
check,” which undercounted; test.md had it right and the page didn’t.
- Hosting (static, free tier)
- $0
- To publish a new build
- 1 file
- Framework version
- Astro 7.1
Reproduce this
The pack is public, in the repository — no email, no download gate. That’s the only version that’s consistent with claiming “no database, no lock-in”: a pack you have to pay for with your address would contradict the whole point.
It lives in builds/website/repro/:
architecture.md— the one-collection → four-views design, with a diagram drawn from the actual code, and why/toolsis a projection rather than a second list.schema.md— the content schema annotated field by field, including the three tool roles and why merging them would break the link/no-link split.reproduce.md— rebuild from an empty folder: exact commands, pinned versions, and how to re-run the core-invariant check yourself.deploy.md— the Netlify config, the Lighthouse plugin, and the full Git/SSH auth chain that ate the time, with the fix.
Alongside it, already public: build-notes.md
(the journal, dead ends included) and test.md
(the check set decided before building, and what’s still unrun).
What’s not in it, and why: this page used to advertise a curated prompt sequence and full-resolution editable diagrams. Neither exists — the session wasn’t recorded and no diagram sources were ever made. They’re absent rather than reconstructed, because inventing artifacts to satisfy an old promise is worse than retracting it.
The tool
Postscript: the newsletter signup (2026-07-25)
Eight days after launch, the email signup still redirected to Buttondown’s own page instead of submitting inline. Fixing that became the longest debugging chase of this build, and it ended somewhere that wasn’t in the code: a Buttondown spam-firewall setting our own testing had tripped.
That story continued — the endpoint turned out to have no abuse controls on it, and bots found it — and the whole of it, both halves, now lives on its own page: Hardening the email signup endpoint after the bots found it. It’s the one to read if you’re wiring a newsletter into a JavaScript site.
One correction worth carrying here, because this page used to state the opposite: the fix at the time was to switch Buttondown’s firewall settings off. They have since been switched back on, deliberately, and they now block the majority of the bot traffic. Don’t take the advice this section used to give.