New: Prompt then ship a website

< Prompting is quick. Shipping a website isn't. />

shipping-a-website-hero.png

Vibe coding a site is fast. Both of my production sites were built with Claude. What took the rest of the time was everything underneath it: the DNS chain, email deliverability, analytics, SEO that works for humans and AI assistants, Core Web Vitals, payments, design, automation. None of it shows up in the prompt that built the homepage.

This isn't a critique. I'm all for it. The question is what you do after the site looks good.

The two sites

Shacks_OG_1200_630.png

Shacksbloom.com runs a florist business. Nine public pages (Home, Services, Portfolio, About, Inquire, Pay, Privacy, Terms, and a standalone Instagram page) plus an admin portal behind auth. The visible part is the easy part.

Lukestahl_io.png

Lukestahl.io is this site. Astro 6 with Notion as the CMS, deployed to GitHub Pages. Blog, project listings, an AI models guide that checks for model updates every Monday and opens a PR when it finds them, a monthly newsletter built from scratch. Started with plain HTML, CSS, and JS, then migrated to Astro once the site needed more structure. Both are in production.

Tech stack decisions

These decisions happen before the first prompt, and they carry weight.

For shacksbloom.com: Vite + Vercel. React SPA with build-time prerendering. Each deploy runs a prerender script that generates static HTML per route. No running SSR server, just HTML snapshots Vercel serves directly. Two people touch it and neither needs a CMS yet.

For lukestahl.io: started with plain HTML, CSS, and JS, then migrated to Astro once the site needed real structure. Astro handles static page building; React handles interactive components like Shadcn UI. Posts live in Notion, sync at build time, render to static HTML. Adding a post is a Notion edit and a deploy. The stack should fit how you work, not the other way around.

Stack mismatches show up downstream. A framework that defaults to SSR when you're serving mostly static content adds complexity everywhere. Don't let a prompt make that call.

Design: I'm not a designer

Both sites needed design work. Before Claude Design existed, I was having Claude generate self-contained HTML files with inline styles, opening them in a browser, screenshotting what worked, and feeding that context back into the next session. I also used the Excalidraw MCP to export those HTML files into hand-drawn style visuals. More character than a polished AI mockup, and a useful middle ground between wireframe and finished design.

Claude Design changed the workflow considerably. Where I was stitching together HTML mocks, browser screenshots, and context drops, now I iterate in a design-system-aware tool. The output lands closer to finished when you bring intent to it. The "AI slop" label is becoming something people throw around to sound above it, or maybe because they're nervous about what it means for designers. I understand both positions. Not being a designer with access to these tools means I can ship sites that look like a designer worked on them. Nobody one-shots a design and ships it. The output on pass one is a starting point. Push back on defaults, redirect what's off, keep going. The output gets better every pass. That's the whole job, same as it's always been.

Excalidraw is worth knowing regardless of the AI workflow. It handles everything from rough architecture sketches to clean professional diagrams, and the hand-drawn aesthetic is a deliberate choice you can switch on or off. For visual thinking, system diagrams, and design assets that need a bit of character, it's one of the better tools out there. The MCP integration is a bonus: take an HTML mock, run it through, and you get a hand-drawn version that doesn't look like it came straight out of an AI tool.

DNS and deployment

The DNS chain for shacksbloom.com runs GoDaddyCloudflare → Vercel. Vercel terminates SSL, which means every Cloudflare record has to stay on DNS-only mode. Flip one record to orange-cloud and HTTPS breaks. That detail isn't documented anywhere visible. You find it by breaking things.

Cloudflare Email Routing came free with the domain. jackie@shacksbloom.com and hello@shacksbloom.com forward to Gmail without a Google Workspace account. hello@ is a catch-all. Small thing that eliminates a recurring cost.

Lukestahl.io is simpler at the DNS layer. GitHub Pages handles SSL and deployment. The complexity lives in the build pipeline.

Email infrastructure

Both sites use Resend for transactional email. Resend's free tier allows one verified domain per account, so shacksbloom.com and lukestahl.io each have their own. DKIM on each domain. SPF on the send subdomain. A p=none DMARC record at minimum: skip it and sending works fine for weeks, then Gmail starts routing inquiry replies to spam. No error, no warning. It just stops working.

The shacksbloom.com inquiry handler is a Vercel function at api/inquire.ts. It validates required fields, silently drops honeypot-flagged submissions, sends Jackie a styled HTML email with Reply-To set to the person inquiring, and fires an auto-reply. The API key is scoped to sending on shacksbloom.com only.

Lukestahl.io has a monthly newsletter. Not Mailchimp, not Beehiiv. Custom-built. Resend handles delivery. The list, scheduling, and template rendering are all code I own: no subscriber caps, no platform fees, templates that match the site exactly. It's one more thing to maintain, and it runs exactly how I want it to.

Analytics and automation

Both sites run PostHog. For shacksbloom.com, it's proxied through /ingest/* so ad blockers don't drop the events. Five explicit events, autocapture off, session replay scoped to the inquiry flow so I'm not burning the free tier watching generic page views.

For lukestahl.io, same setup without the proxy. Analytics feed content decisions: which posts get read, where people land, what converts to newsletter signups.

Automated GitHub Actions handle monitoring on lukestahl.io:

  • A link checker that emails me via Resend when internal or external links break
  • A Core Web Vitals monitor that opens a GitHub issue when LCP, CLS, or INP regress on tracked pages
  • An AI models guide updater that pulls Anthropic and OpenAI release feeds, runs a diff through a prompt, pushes a branch, and opens a PR when it finds changes

For shacksbloom.com, a GitHub Actions workflow runs every Monday, queries PostHog for the prior week, and emails a summary to Jackie and me via Resend.

SEO and AEO

Core Web Vitals affect ranking directly. Let LCP, CLS, or INP regress on mobile and organic traffic follows. The GitHub Actions monitor surfaces regressions before they add up to a traffic drop.

AEO is the other half: making the site readable and useful to AI assistants. Both sites have llms.txt files that explain what each site is for. Lukestahl.io has JSON-LD structured data on every post, an IndexNow integration that notifies Bing and Yandex within minutes of a new page, and a sitemap with canonical URLs and noindex filtering. Shacksbloom.com's llms.txt includes the payment page URL so an AI assistant can hand it to someone asking "how do I pay Jackie?"

Both sites run weekly Ahrefs audits. It surfaces broken links, crawl errors, missing metadata, and issues that don't show up in any build output. It's the tool that keeps SEO health visible on an ongoing basis rather than something you check once at launch and forget.

One thing it caught on shacksbloom.com: the homepage was flagged as orphaned three weeks after launch. Same index.html served every route, empty <div id="root">, no internal <a> tags visible to crawlers without JavaScript. The fix was a prerender step that emits a fully-hydrated HTML body per route. Most LLM scrapers and older search crawlers don't execute JavaScript. If your build emits a shell, those crawlers see a blank page.

Payments

Shacksbloom.com has a /pay page. A Venmo deep-link button that opens the app on mobile and falls back to the web on desktop. A Zelle card with copy-to-clipboard for the receiving email. No Stripe, no transaction fees on small deposits.

It's indexed, linked from the footer, and listed in llms.txt. Simple setup, but the discoverability piece matters. If someone asks an AI assistant how to pay for a custom arrangement, the assistant can surface the link.

Instagram

Shacksbloom.com/instgram pulls a live Instagram feed via Behold.so. The floral work is the product, and Instagram is where the portfolio lives. Behold.so handles the API connection and caching on their end; the site loads a widget script and stays current without a build.

Admin portal

Shacksbloom.com has a custom admin portal built on Neon serverless Postgres with Drizzle ORM, auth via Clerk backed by Google OAuth, and a full quote-to-invoice lifecycle. The entire admin bundle is lazy-loaded so none of its JS ships to public visitors.

Getting Clerk to production with Google OAuth isn't just enabling a toggle. You need a Google Cloud project, OAuth credentials with a client ID and secret, and authorized redirect URIs pointing to Clerk's callback, all wired into Clerk's dashboard. Most tutorials skip that step entirely. Once Google auth clears, there's a second layer: the user's email is checked against an ADMIN_EMAILS env var. The frontend blocks rendering if it fails, and every API call independently re-verifies the Clerk session token and re-checks the allowlist server-side. Two separate enforcement points, not one.

A quote starts as a draft, gets sent to the customer, and converts to an invoice when the job is confirmed. Invoices track payment method and paid date. Refunds are their own invoice type linked back to the original. Every quote and invoice has line items with description, date, notes, and amount. Every invoice can be emailed to the customer as a branded PDF, rendered server-side via @react-pdf/renderer with Jackie's logo, and every send is logged to an email_logs table with the Resend message ID and delivery status. A year view shows total collected, receipt count, and refund count.

This only works because one developer manages both sites. Build vs. buy math changes fast once you add team members or operational complexity. For a personal site or a small business where one developer owns the whole stack, custom-built is often the right call.

Knowledge is key

The jump from a fun vibe-coded site to one that's built to last isn't about the framework or the code quality. It's about knowing what needs to exist. That knowledge is the limiting factor. Having Claude as an agent to gut-check ideas, bake a plan, and work through the checklist with you gets you there considerably faster. Both are built to last and will keep evolving.

Developer Writing Assistant

Handbook
Developer Marketing Handbook

Goals

Developer marketing builds trust first, pipeline second.
The work connects your product to how developers actually build and helps that credibility translate into adoption and revenue.

A great developer experience is the foundation. It starts with discoverability, continues through docs, and carries into the product itself. Good documentation shortens time to value and builds confidence that your product can scale with real teams. Developers trust what they can inspect, so show how the product works and let the system speak for itself.

Success isn't clicks or vanity metrics. It's measurable engagement that creates product-qualified leads, builds influence across teams, and contributes to both product-led and sales-led growth.
When developers use your product by choice and advocate for it inside their company, you've done the job right.

Strategy

Start with reality, not aspiration.

Map where your product fits in the developer workflow, then help them do that job faster or with less friction.

Lead with clarity. Explain what it is, what it does, and why it matters.

Show the system behind the product. Architecture, examples, and tradeoffs explain more than positioning ever will.
If you can do it in a clever or playful way that still feels authentic, that's bonus points.

The best developer marketing respects time, delivers value, and makes something complex feel obvious.

Journey

Awareness → Evaluation → Adoption → Advocacy.
Each stage should connect clearly to the next.

Awareness happens in places developers already spend time: GitHub, Reddit, newsletters, blogs.
Evaluation happens in your docs, demos, and sandboxes.

For most developers, the docs are the real homepage, so accuracy and structure matter more than polish.

Adoption depends on how fast they reach first success.
Advocacy is when they start teaching others what they learned from you.

Personas

Create personas based on who buys the product and who actually uses it. For example:

Buyers: CTO or Engineering Leader, Senior Engineer, Implementation Architect.
Users: Frontend, Full-stack, App Developer.
Adjacent: Ops, Product, Design.

Each persona has different pain points and goals.
CTOs and Engineering Leaders care about governance and ROI.
Senior Engineers look for performance, flexibility, and code quality.
Implementation Architects focus on how well a tool integrates and scales.
Write for what each person owns, not what you wish they cared about.

These categories are shifting. PMs and designers who build with AI tools aren't adjacent anymore. They're users. Update your personas to reflect how people actually work, not how the org chart defines them.

Messaging

Be clear first. Be clever only if it helps.
Make every message easy to scan. Lead with the point before expanding on it.
Good developer messaging is specific, practical, and rooted in how people actually build.

Clarity earns trust, but a bit of personality makes it stick.
The goal isn't to sound like marketing. It's to communicate something real that developers recognize and care about.

Build around three pillars:

  • Speed: faster builds, fewer tickets
  • Efficiency: consolidated stack, lower maintenance
  • Control: safe scale, long-term confidence

If you can back it with code, data, or proof, keep it.
If it only sounds good, cut it.

Campaigns

Treat campaigns like product launches.
Plan, ship, measure, repeat.

Each campaign should answer three questions:

  • What developer problem are we solving?
  • What proof are we showing?
  • What happens next?

Treat developer feedback like bug reports and close the loop quickly when something needs to be corrected or clarified.

Make it easy for developers to try, test, or share.
Run retros on every launch and capture what worked, what didn't, and what to change next time. Always learn from what you launch.

Content

Write with clarity and intention. Every piece should help developers build faster, learn something new, or solve a real problem.

Strong content earns attention because it's useful.
Lead with the outcome or insight, then show how to get there. Make it easy to skim from top to bottom.
Show working examples, explain tradeoffs, and include visuals or code where it helps understanding. If it doesn't teach or demonstrate something real, it doesn't belong.

Core content types

  • Blog posts: tutorials, technical breakdowns, or opinionated takes grounded in experience.
  • Guides and tutorials: step-by-step instructions that lead to a working result.
  • Integration or workflow content: explain how tools connect and where they fit in a developer's process.
  • Technical guides and code examples: deeper material for experienced readers who want implementation detail.
  • Explainer or glossary content: clear, factual definitions written to answer specific questions directly.
  • Video or live sessions: demos, interviews, or walkthroughs that show real workflows.
  • Research and surveys: reports or insights that help developers understand the state of their field.

Content strategy buckets

  1. Awareness — generate buzz and discussion. Hot takes, thought leadership, or topics that invite conversation.
  2. Acquisition — bring new developers in through problem-solving content. Tutorials, guides, and explainers that answer real questions.
  3. Enablement — help existing users succeed. Deep tutorials, documentation extensions, and practical how-to content with long-term value.
  4. Convert Paid — drive upgrades or signups. Feature-specific walkthroughs or advanced use cases that show value worth paying for.

Each piece should fit into one of these buckets and serve a clear purpose. Awareness earns attention. Acquisition builds trust. Enablement drives success. Convert Paid turns success into growth.

Clarity is the standard. Use it to earn credibility.

Community

Reddit. GitHub. Discord. Slack. YouTube and other social platforms.
Join conversations, don't start pitches.

Be helpful. Add context. Share working examples.
When your content becomes the answer people link to, you've earned credibility.

Metrics

Measure adoption and revenue, not reach.
Awareness is useful, but only if it drives activation or expansion.

Focus on signals that show impact:

  • Product or API usage
  • Time to first success
  • Product-qualified leads
  • Developer-influenced revenue
  • Retention and repeat engagement

The goal is to prove that trust earned from developers shows up later in product usage and revenue.

Developer Marketing Skill

I built a Developer Marketing Skill for Claude that helps evaluate content, strategy, and campaigns against the principles in this handbook.

Use it to stress-test messaging, review technical content, plan developer campaigns, or get feedback on positioning. It applies a "trust first, pipeline second" philosophy with an emphasis on clarity, technical credibility, and measurable engagement.

Need more resources?

Check out my curated collection of developer marketing tools, newsletters, and resources.

ESC