I built a real, production website with AI in one weekend, zero lines of code by hand. The lesson surprised me: I expected the AI to be the hard part. It turned out I was.

Everyone talks about AI coding right now, mostly in the form of "look, I had ChatGPT write a todo app." I'm writing up the honest version of a real project instead: bilingual, with AI-powered personalization, a protected chat, a database that tracks visitors, a custom domain, and SEO (so it's findable on Google). I built it with Claude Code, the AI tool that doesn't just suggest text but edits files and runs commands itself. Here's what worked, what broke, and what I'd do differently next time.

How It Started, Which Is Not How I Planned It

I didn't set out to build a website.

On a Friday evening I had just set up KIRA, a personal AI agent system of six specialized agents with one role each, research, strategy, content, analysis. I was experimenting with how far you can push AI orchestration as a personal tool. Somewhere in that process I read a Substack article about the agentic web, the idea that personal AI agents could represent you online, answer questions, and handle interactions.

That's when the thought landed: what if my website itself were an AI agent? Instead of a static page with a CV, a website where an AI that knows my career talks to visitors, answers their questions and adapts its content. A website that proves I understand the technology by being the technology.

I told Claude: "I'd like to set up my own website." The answer came back: "Understood. I'll stop asking questions and start building."

Three days later I had a production website, but the path from idea to launch was anything but smooth.

The Numbers

Let me be transparent about what this actually cost:

  • Time: 3 days. Friday evening to Sunday night. Maybe 15 hours of actual work, spread across 4 chats with Claude Code.
  • Tokens: Roughly 15 million tokens (the unit AI usage is billed in) across all chats. That's the equivalent of reading and writing about 50 novels worth of text.
  • Cost: Around $60-80 in API usage for Claude Code (Opus model). Less than a freelance developer charges per hour.
  • Code: ~7,000 lines across 93 files. 51 commits (saved snapshots of the code). Zero lines written by me manually.
  • Result: A production website with features that would take a solo developer weeks to build.

15 million tokens for a personal website sounds insane, until you see how the work actually happens. Claude reads a file, suggests a change, I say "that's not right," it reads the file again, tries differently, reads three more files for context (what it needs to remember), generates new code, I say "closer, but the mobile version looks off," it reads the screenshot and adjusts. Every round like that multiplies the tokens used. The intelligence is cheap, the iteration expensive.

Three Brains, One Project

I didn't use the same model for everything. The website runs on three different Claude models: Opus, the biggest, built the code via Claude Code, Sonnet from the mid-tier powers the chat and page personalization, and Haiku, the smallest, answers single short questions. Each task gets the brain it deserves.

I felt the downside more than once: Claude Code runs on Opus, and with a subscription you hit usage limits fast. Several times I was mid-flow, fixing a bug, got cut off, had to wait, come back, and re-explain the context. Losing that momentum costs more than tokens.

Where It Got Messy

The hamburger menu incident. On mobile, the navigation overlay wasn't covering the full screen, and content showed through behind it. Sounds simple, right? The fix took three attempts, because backdrop-blur on the parent nav creates a new containing block in CSS, which broke fixed positioning on its children. The actual fix was to make the entire nav element fullscreen when the menu opens, with no nested overlay at all. Claude found this only after I kept saying it still wasn't working.

The chat language problem. The website is bilingual, and the chat kept answering in English, even on the German version. The reason: a setting called locale (which language) never made it from the frontend to the backend. It existed in the component, in the hook (a small reusable bit of code), and in the API route, but nothing connected the three. Four files needed one line each: a classic integration bug, easy to miss, easy to fix.

DNS hell. I'd bought the domain on Cloudflare and deployed it (put it live) on Vercel, and the main domain resolved right away. The www version of the site did nothing at all, for hours. It turned out that CNAME records simply propagate slower across the internet than A records, and I'd spent 20 minutes hunting for a misconfiguration of my own that didn't exist. The right answer was simply to wait.

The admin dashboard, three times. The first version was a flat list of database entries, ugly and hard to read. The second had a better layout, but the onboarding messages showed up as raw API input, VISITOR'S NAME: Theo WHAT THEY TOLD ME ABOUT THEMSELVES: "Tester", because that is exactly how they are stored in the database. The third groups by visitor, parses everything into readable fields and highlights the actual questions in the chat messages.

I kept looking at it and saying "this isn't right," and Claude kept rebuilding it until it was.

The AI Knows My CV. It Doesn't Know My Story.

I fed Claude detailed markdown files (plain text with simple formatting) about my career, timelines, projects, numbers, outcomes, everything it needed, and it used them. But using facts and telling the right story are two different things.

It would take a real achievement and frame it wrong, inflate a number, merge two projects into one, say I had been in my current role for two years when it has been less than one, and present something I struggled with as a clean success. The facts were in the files. The interpretation wasn't always what I meant.

I caught most of it. But it made me realize: AI can write your story, and it still cannot know which version of it is true to you. That takes a human rereading every sentence and asking whether that is actually what happened.

The Profile Picture That Cost 1.4 MB

The profile photo was a 1.4 MB PNG, on a website that's supposed to be fast. Nobody caught it during development because locally everything loads instantly, and it took the SEO audit to flag it. Converted to WebP: 26 KB at the same quality, 98% smaller. It's the kind of thing that's obvious in hindsight and invisible while you're building.

Lessons Learned: What I'd Do Differently

1. Define the scope before starting. The website grew organically from "let me experiment with AI agents" to "full production website with admin dashboard, security hardening, and SEO optimization". That is exciting in the moment, but it also meant I spent time on features I didn't need yet. An admin dashboard on day one, for a website with zero visitors? Next time I ship the core first and add features when there is a reason.

2. Don't let the AI set the pace. Claude will happily keep building forever, add a feature, refactor something, improve another thing, and it doesn't know when to stop. Several times I caught myself going down a rabbit hole because the AI suggested something and I said "sure, why not," forgetting that the cost is always time. Next time I write down what is in scope and what is not, before the first prompt (what you type to the AI).

3. Review content more carefully, earlier. The AI generated website copy, section titles and descriptions, and I reviewed most of it. Some things still slipped through that didn't sound like me or subtly misrepresented my experience. Fixing content after it is woven into multiple components is harder than getting it right in a standalone document first. Next time I write all content in a single markdown file, review it thoroughly, and then let the AI build the UI (what people actually see) around it.

4. Plan for token limits. I hit the Claude Code subscription limit multiple times, always at the worst moment: mid-bug-fix, mid-deployment, mid-security-review. When a chat gets cut off, I lose the context and have to rebuild it by hand. Next time I break work into self-contained chats and avoid starting anything that needs three hours straight when I might get cut off after one.

5. Test on mobile from the start. Every layout issue I hit was a mobile issue, the hamburger menu, the profile photo centering, text overflow, and I was building on a laptop, looking at laptop screens. Next time I check mobile after every visual change, not at the end.

6. Separate the models earlier. Using three different Claude models for different tasks was the right call, but I arrived at it through trial and error: Opus for code, Sonnet for chat, Haiku for quick questions. The cost difference is massive. Next time I decide model allocation upfront as part of the architecture.

7. Don't trust the AI's version of your story. This is the big one. AI is excellent at generating text that sounds right, and bad at knowing whether the text is true to your experience. Every piece of content about me needed a careful, factual read: Did I actually do that? Was it really that many? Is that how it happened? Next time I treat AI-generated personal content like a first draft from a ghostwriter who did good research but wasn't in the room.

What AI Is Good At, and What It's Not

AI is good at:

  • Writing boilerplate code (repetitive, standard code) fast. API routes, database schemas, metadata. Done in seconds.
  • Knowing framework specifics. "How does Next.js 16 (the framework it's built on) handle metadata for client components?" Claude just knows.
  • Doing tedious refactors. Changing x-forwarded-for to x-real-ip across 7 API routes? One prompt.
  • Security reviews. The AI found timing-safe comparison issues (a subtle bug in comparing values) and IP spoofing vectors I wouldn't have thought of.
  • Not getting tired. At hour 6, the AI is as sharp as at hour 1. I'm not.

AI is not good at:

  • Knowing when something looks wrong. Every layout issue was me looking at a screenshot and saying "that's off."
  • Making content decisions. "Should this be a story or a list?" "Is this too self-congratulatory?" "Does this sound like LinkedIn-speak?" All me.
  • Stopping. AI will keep adding features, improving code, refactoring, and it doesn't know when to ship. I do.

The Real Lesson

The website is live at adrianfoehl.com, with AI-powered personalization, a protected chat, bilingual content, database tracking, an admin dashboard, SEO optimization and security hardening. 15 million tokens, ~7,000 lines of code, 51 commits, one weekend, zero lines written by hand.

What I actually learned is something else, though: the technology never fails because of the technology.

The hamburger menu broke because of a CSS containing block rule, the chat spoke the wrong language because of a missing parameter, the DNS didn't work because of propagation timing, and the admin dashboard was ugly because nobody had asked what the user actually needs to see.

Every single problem was a human one in the end: understanding what users need, knowing what to build, making decisions the AI can't make, and having taste.

AI made me build faster. Knowing what to build, when to stop, and whether the result was actually good remained entirely on me.

That's what I tell organizations every day: AI is not the hard part. You are.