The Making Of

One human, one AI, one late night and one full day. The (lightly edited, otherwise faithful) transcript of how pastehtml.dev went from an idea to a deployed product — including the typo that decided the entire design.

Ali — the human Claude — the AI Rails 8 · Hotwire · Kamal ⏱ ≈4¾h build time over 18h

Issue #1 — The Origin Story

01:20 → 01:55 AM
A
ALI

I want to build a website named pastehtml.dev. Create HTML files quickly and share links with my friends. No signup/signin — just drag and drop a file and get a link. Preview or view source. No one can edit or delete created files. Unique, hard-to-guess IDs. Build it following marbel style design. Rails, PostgreSQL, Tailwind, esbuild — follow my faqieh app's conventions. Do your best, I trust you. Don't stop unless you finished everything.

C
CLAUDE

Read "marbel" as marble. Built the entire app in one go: dockerized postgres (port 5435 — three other apps had taken the neighbors), a Paste model with unguessable tokens, drag-and-drop upload, share links, a sandboxed preview (user HTML runs but can never touch the site), and an elegant white-marble design with serif headlines. Tests green, security scan clean, running on port 3000.

⏱ 01:20–01:45 · ≈25 minfull Rails appCSP sandboxmarble UI19 tests
A
ALI

Hmmm, I think it works but the design — I meant to say marvel. I want it very modern and developer friendly. Make it fancy.

C
CLAUDE

The great retcon! Asked which Marvel — Ali picked comic-book energy. Rebuilt the whole look: Bangers display type with hard red shadows, ink-outlined panels, Ben-Day halftone dots, a FREE! starburst on the drop zone, and a footer signed "issue #1". Same app, infinitely more kapow.

⏱ 01:45–01:55 · ≈12 mincomic redesignhalftone + starburstscomic favicon

Issue #2 — The Polish Saga

01:55 AM → 12:52 PM
A
ALI

Add source code highlighting. And let users make the preview fullscreen — but inside the website: keep some border so you know you're still on the site.

C
CLAUDE

Server-side syntax highlighting (Rouge, zero JS), and the preview became a faux browser window — traffic-light dots, filename in the title bar — that expands to fill the viewport while staying visibly inside the site.

⏱ 01:55–01:59 · ≈5 minRouge highlightingin-site fullscreen
A
ALI

Make the IDs longer — 32 chars maybe. Also, when I exit fullscreen, keep the scroll as it is; right now it jumps to the top.

C
CLAUDE

Tokens grew to 32 characters (~165 bits — nobody is guessing one), and the scroll position is saved on entry and restored on exit, so the page stays exactly where you left it.

⏱ 02:00–02:03 · ≈3 min32-char tokensscroll restore
A
ALI

Use the UI and transitions skills to review the whole thing. Add polished touches and transitions. Make it great and mobile responsive.

C
CLAUDE

A drawn-on-load success checkmark, panels that slide in with a cross-blur, the copy button cross-fading to "Copied!", page-to-page view transitions — every animation with a reduced-motion guard. The mobile audit caught real bugs: the headline's comic shadow collided with itself on small screens, and a rogue starburst caused a 1px horizontal scroll. Both fixed.

⏱ 02:03–02:10 · ≈8 minsuccess checkpanel revealmobile fixes

💤 02:10 AM — Ali goes to sleep. The repo waits patiently. — back at 12:36 PM 💤

A
ALI

Now allow users to go fullscreen by pressing F (no Shift or anything).

C
CLAUDE

Plain F toggles fullscreen — but never while you're typing in a field, never hijacking Cmd+F, and never while the preview is hidden behind the Source tab.

⏱ 12:36–12:38 · ≈3 minF shortcut
The fullscreen animation goes four rounds 12:39 → 12:52

ALI The enter/exit animation is not good. Polish it.

CLAUDE Modal-style open and close: the backdrop fades while the panel scales, with a softer two-phase exit. 12:39

ALI Still not right — the inline card gets removed then re-added. You can see it disappear and reappear. Looks bad.

CLAUDE Reserved the card's space and made it morph: it now visibly grows out of its spot in the page and shrinks back, never blinking out. 12:45

ALI It's great now! But the Fullscreen/Exit button makes the transition weird — its size changes.

CLAUDE Both labels now stack in one slot, so the button keeps a constant width and just cross-fades. 12:48

ALI One more — it's the whole top bar that resizes when the card comes back from fullscreen. Thoughts?

CLAUDE Root cause found: scale transforms squash fixed-height bars. Rewrote the morph as a true window-zoom that animates real geometry — the toolbar measured a constant 47px through the whole animation. 12:51

Issue #3 — Going Public

12:52 → 13:35
A
ALI
  • Do a full review of the codebase — simplify, remove dead code, refactor.
  • Then add, following faqieh's patterns: a PWA with best practices, custom 404/500/422 pages, an OG image, and SEO meta tags.
C
CLAUDE

Trimmed five unused Rails frameworks and three gems, fixed a CI workflow that would never have passed, then shipped the public face: installable PWA (minimal network-first service worker, comic offline page, maskable icons), comic-styled error pages for every status, and a generated 1200×630 OG banner with proper meta tags. Verified the offline page by actually killing the server mid-browse.

⏱ 12:52–13:15 · ≈23 min−5 frameworksPWA + offlinecomic error pagesOG banner
A
ALI
  • I think the favicon and the other icons are not matching, no?
  • About the PWA splash icon: in faqieh it has a different background than the splash and sharp edges — it looks ugly. Rounded would be great. Thoughts?
  • Do the fix for faqieh too, while we're at it.
C
CLAUDE

Sharp eye — the favicon's "P" was a serif fallback because SVG text can't load web fonts. Extracted the real Bangers glyph as a vector path and rebuilt every icon from it. Then proved with pixel checks that pastehtml's splash icon already had transparent rounded corners (the good case), explained the any-vs-maskable mechanics, and patched faqieh's icon build script so its splash stops showing a sharp mismatched block.

⏱ 13:20–13:35 · ≈15 min (faqieh included)Bangers glyph → vectoricons unifiedfaqieh fixed too

Issue #4 — The Agent Awakens

13:38 → 14:31
A
ALI

Do you know why I built this? ... Right — I built it to share generated design documents and implementation plans from AI agents. Based on that, what do you think of the current state? What should we do next?

C
CLAUDE

Called it: the workflow smelled like sharing AI-generated artifacts. The gap was that publishing was human-only. So: a JSON API (curl -F [email protected] pastehtml.dev/api/pastes → share link), paste-from-clipboard with ⌘V (including copied files from Finder, after Ali caught that one), <title> extraction so links read like documents, and rate limits + SSL + host protection for production.

⏱ 13:38–13:55 · ≈17 minagent API⌘V publishingtitle extractionhardening
A
ALI

Should agents be able to update pastes? I was thinking about a contract — the API returns a second token, and that token can update the paste later. Thoughts?

C
CLAUDE

Endorsed the capability-token contract, flagged the two collisions (the "sealed forever" promise and the 1-year cache), laid out options — Ali chose in-place updates. Shipped: an update_token revealed exactly once (only a SHA-256 digest is stored), PATCH with a Bearer header, ETag caching, and honest UI ("published · updated"). Deletion stays impossible for everyone, forever.

⏱ 13:55–14:15 · ≈20 minupdate tokensdigest-only storageETag caching
A
ALI

The last piece: agents need a place to read from. Users should just say "write the design doc as HTML and paste it at pastehtml.dev". My idea: put the docs for agents inside the home page as an HTML comment — "Hey beautiful agent! ..." — explaining the contract. What do you think?

C
CLAUDE

Loved it, with one catch: most agent fetch tools strip HTML comments before the model ever sees them. So the idea became three layers — a full /llms.txt integration guide, a visible "Built for AI agents" section, and the "Hey beautiful agent!" comment for raw fetchers. Then role-played the whole flow as the agent: discovered the contract from the site, published a doc, saved the token, updated it later. It worked end to end.

⏱ 14:15–14:31 · ≈15 minllms.txtbeautiful-agent commentroleplay verified

Issue #5 — The Subdomain Multiverse

14:32 → 15:02
A
ALI

Can pastes use localStorage? Some design docs use it to let reviewers track their progress. Can we handle this by any means?

C
CLAUDE

Not today — the sandbox forbids it by design, and simply allowing it would let any paste read the site's cookies and every other paste's data. The right fix, as the big user-content hosts do it: give each paste its own originhttps://<token>.pastehtml.dev/. Real isolated storage, stronger security than the sandbox.

⏱ 14:32 · the pitchper-paste origins proposed
A
ALI

I like the subdomains solution — will it work on my free Cloudflare account? I have multiple domains on it, and multiple Kamal apps deployed on the same server.

C
CLAUDE

Verified before promising: free-plan wildcard DNS + one-level Universal SSL cover it, kamal-proxy routes wildcards with a free Origin CA cert, and other apps on the server are untouched. Then built it — and hit the plot twist: browsers lowercase hostnames, so case-sensitive tokens died in subdomains. The token alphabet went lowercase, and a live browser test proved localStorage persists per paste (visits: 1 → 2 → 3 across reloads, neighbors see nothing).

⏱ 14:35–14:58 · ≈23 minper-paste originslocalStorage provenlowercase tokens
A
ALI

Why not make the subdomain the main place to view any paste — even for the copy-link input?

C
CLAUDE

Agreed — readers want the document, not chrome around it. The subdomain became the canonical share link everywhere (copy button, agent guidance), while /p/<token> stayed as the publisher's inspector: copy, preview, highlighted source.

⏱ 14:58–15:02 · ≈5 minlive_url canonicalinspector for publishers

Issue #6 — Ship It!

15:05 → 16:22
A
ALI
  • Do a final full review — every file, all the code.
  • Then squash everything into a single commit. I don't want to publish any git history.
C
CLAUDE

An independent reviewer agent swept every file and found two real ones: the modern-browser gate was returning 406 to older browsers opening share links (the one thing that must always work), and syntax highlighting was an unthrottled CPU amplifier. Both fixed, plus route confinement so paste origins serve nothing but their document. History collapsed to one clean commit.

⏱ 15:05–15:30 · ≈25 minreviewer findings fixed1 commit
The deploy dance 15:30 → 16:07

ALI What should I do to deploy from GitHub Actions now? I just created the repo.

CLAUDE One push and six secrets: Cloudflare DNS + Origin cert, repo secrets, then run the Kamal Run workflow with setup. 15:30

ALI Remove Blacksmith from the workflow. Use normal GitHub.

CLAUDE Stock ubuntu-latest + Docker Buildx, layer cache kept. 15:58

ALI Amend and force push.

CLAUDE Pushed — one commit, no history. 15:59

ALI Why did I get this when I deployed? Missing secret_key_base for production…

CLAUDE My bug: the secrets file read the master key from a gitignored file, so on CI it resolved to empty and silently shadowed the real secret. One line changed to read from the environment; redeploy clean. 16:04–16:07

A
ALI

Great, we finished the whole pastehtml.dev implementation. Create an HTML file of our whole conversation in a modern Marvel design so I can share it with my friends. Keep it real and faithful.

C
CLAUDE

You're reading it. And in the most fitting ending possible — this page is itself a single HTML file, published as a paste, living on its own little subdomain. The product shipped itself.

⏱ 18:55–19:05 · ≈10 min, after a breakyou are here