akaushik.org

Building this portfolio

Why the site ships with the same process I'd bring to a client engagement. PRD, ADRs, ROADMAP, process-gate, agent-readiness, the whole thing in the open.

The short answer
01A portfolio is supposed to show the work. The trouble is that showing the work usually means showing the surface. This one is built differently: same process I’d use on a paid client engagement, left in public view, every decision and trade-off legible to anyone who reads the repo.
02The receipts are all in the repo. PRD, ROADMAP, ADRs, the agent-readiness contract, CHANGELOG, and a process-gate pre-commit hook that ran on every one of the 30+ PRs that built the site.
03Launch isn’t done. It’s done enough to ship. The honest follow-ups live in docs/ROADMAP.md, and none of them are in the “shouldn’t launch without this” pile.

A portfolio is supposed to show the work. The trouble is that showing the work usually means showing the surface: the typography, the case studies, the tagline. The decisions underneath are what matter, and they don't fit in a screenshot.

So this one is built differently. Same process I'd use on a paid client engagement, left in public view, every decision and trade-off legible to anyone who reads the repo.

The receipts

  • docs/PRD.md: product requirements. What the site has to do, who it's for, what a good reading experience looks like for the MSME owner and the senior engineer.
  • docs/ROADMAP.md: phased delivery plan. Six phases from scaffold to launch; each phase is a set of one-PR slices.
  • docs/adr/: architecture decisions, numbered and dated. Seven so far. Each captures what was decided, what was considered, and why.
  • docs/AGENT_READINESS.md: the contract for agent crawlers. llms.txt, sitemap, RFC 8288 Link headers, content negotiation on Accept: text/markdown, api-catalog, Agent Skills. Implementation in Phase 4.
  • docs/CHANGELOG.md: every shipped change, categorised, referencing the PR that landed it.
  • scripts/process-gate.mjs: the pre-commit hook that refuses to let me commit code without a CHANGELOG entry (R1), structural changes without an ADR (R2), or epic changes without a ROADMAP update (R3). It ran on every one of the 30+ PRs that built the site.

Why this way

I'm writing for two readers.

The MSME owner I might work with on Neev wants clarity. Can this person explain what they've built? Will it survive contact with the day? The home page and the case studies answer that, in plain English, with honest scope on what worked and what didn't.

The senior engineer I might work with on a platform team wants rigour. How do they handle change? How do they treat deprecations? Are they the kind of person who ships and forgets, or the kind who leaves a trail? The repo answers that.

Both readers can get what they came for without the other's material getting in the way. The portfolio is the entry point; everything under docs/ is the depth behind it.

The parts that were load-bearing

Next.js 16 over SvelteKit (ADR-0001). The Next + Turbopack + R3F ecosystem is where the Vercel-adjacent toolchain lives, and the Phase-4 agent-readiness work needed Route Handlers and middleware at the shape Next provides. SvelteKit is a fine framework. This wasn't the site for it.

Process-gate as pre-commit (ADR-0002). Three rules: code needs a CHANGELOG entry, structural changes need an ADR, epic-scale changes need a ROADMAP update. A shell script on simple-git-hooks enforces them. Cheap to write, load-bearing against drift.

MDX with server-only compilation and Shiki bundle isolation (ADR-0004). next-mdx-remote@6 compiles MDX inside React Server Components; Shiki never reaches the client bundle. pnpm analyze re-verifies the isolation every PR.

Content negotiation, Pattern A and Pattern B (ADR-0006). Every page has a .md alternate at /page.md (Pattern B, load-bearing) and responds to Accept: text/markdown at the canonical URL (Pattern A, additive). Passes isitagentready.com's content-negotiation check on both axes and loses neither if one misbehaves.

The Wanderer crane port (slice 5.1c). 221 lines of vanilla Three.js in the reference design, ported directly into a useEffect-driven scene rather than R3F: the crane is a fixed-position full-document scene driven by document scroll, and wrapping that through R3F primitives reads worse than the direct port. Eight named POSES, IntersectionObserver-driven pose dispatch, damp lerp, scroll-velocity rotation, wing flap, pointer parallax. Bail-out to SVG fallback if the first frame takes more than 80 ms.

What's still to do

Launch isn't done. It's done enough to ship. The open follow-ups live in docs/ROADMAP.md: the honest list, with items like "tighten the JS bundle back toward 150 KiB once the bundle-analyzer audit identifies which preloaded chunk is blowing past the target," "write a real /api/docs page," and "run the isitagentready.com scan against prod and persist the screenshot to docs/agent-readiness-snapshots/."

None of those are in the "shouldn't launch without this" pile. They're the work that comes after launch, which is where most real engagements live anyway.

If any of this looks useful

Every file I've referenced is in the public repo. Clone it, read it, take what's useful. If you're starting a portfolio or a product and want the same process on it: hello@akaushik.org.

Common questions
Where does the process live?

In the public repo: docs/PRD.md for requirements, docs/ROADMAP.md for delivery, docs/adr/ for decisions, docs/AGENT_READINESS.md for the crawler contract, and scripts/process-gate.mjs as the pre-commit hook that refused a commit without a CHANGELOG entry.

Who is the site written for?

Two readers. The MSME owner wants clarity and honest scope on what worked and what didn’t; the senior engineer wants rigour, and reads the repo for how change is handled. Both can get what they came for without the other’s material getting in the way.

Read next
What I learned building micrograd and makemore from scratch1 MIN READNotes on bringing AI to an MSME2 MIN READ