this site

a portfolio is the artifact a hiring manager scans for ten seconds before deciding to read. so the constraint isn't "build a portfolio" — it's "prove the taste in ten seconds, prove the engineering in the next ten."

0openapi endpoints · llms.txt · /.well-known/agent-card.json · /mcp
status
shipped · in continuous edit
stack
next 16 · hono · neon · mastra · fly

the problem

i interview every two years and i was tired of having to talk people through the same screenshots of the same projects. i wanted a site that did three things: be skim-readable in ten seconds for the hiring manager, be inspectable by an AI agent for the company that ships an AI agent for candidate review (this is now a real thing), and not look like every other developer portfolio generated in 2026.

the second constraint mattered more than i expected. the wave of AI-generated developer portfolios in 2025 collapsed the median into a recognizable pattern: hero with purple-to-blue gradient, "unleash" or "elevate" in the headline, a 4×3 icon wall of every technology touched, and a proficiency radar chart. the tell isn't any single element — it's the conjunction. so the design brief became a bans list before it became a feature list.

the approach

frontend: next 16 (turbopack), react 19, tailwind 4, shadcn/ui · api: hono on fly machines, oRPC, drizzle, neon serverless · ai: mastra, openrouter, ai sdk, langfuse · agent surfaces: model context protocol (mcp), /.well-known/agent-card.json (a2a), llms.txt · infra: fly machines, cloudflare r2, sentry, infisical

every layer is something an AI agent can read directly — the openapi spec via /reference, the prose via /llms.txt, the tool catalog via /mcp.

the case-study infrastructure you're reading came out of a single constraint: every project page should look like a careful editorial decision, not a template. that meant building a small library of components instead of one mega-template, then dogfooding it on the portfolio itself before using it on real apps. you're inside the dogfood right now.

Chose

scalar for /reference

  • reads the same openapi.json hono already emits
  • warm-machine-themed cleanly via css custom properties
  • keyboard-navigable, no jquery
  • agent-readable: scalar exposes the spec at the same origin
Over

swagger ui

  • 2008 chrome — the brand of "this is a backend"
  • theming is a fight
  • keyboard nav is incomplete
  • the page weighs 2mb of jquery and css resets

picked scalar because it lets the openapi spec _be_ the documentation without dressing it up as enterprise software. the spec is the source; scalar is just a viewer.

Chose

a single warm-machine palette

  • oklch tokens, monospace data, tinted neutrals — one direction
  • identity registers in the first paint
  • every component shares the same five border / text / surface tokens
Over

vs-code-shell theme picker

  • first iteration shipped a 16-theme chooser in the corner
  • diluted the identity — the visitor was looking at the picker, not the work
  • every theme was a compromise; none felt finished

killed the theme picker after a friend said “cool palette switcher.” that wasn't the takeaway i wanted.

rendering diagram…
runtime
rendering diagram…
agent-readable surface area

the 2026-native primitives

three protocols ship behind well-known paths so an AI agent can introspect the site without scraping. each is a single file, generated from the same data model the human pages render. the long version is making the site readable to agents.

  • /llms.txt — markdown summary of the site for llm context windows; lists the case studies, the stack, the contact path. one route handler, under 200 lines.
  • /.well-known/agent-card.json — A2A descriptor: the agent's name, capabilities, contact endpoint. fixed schema, served as a static-ish JSON.
  • /mcp — model context protocol server hosted on the hono api. tools are eight read-only tools — projects, posts, experience, profile, tech stack, activity. zero write tools — there's nothing to mutate from outside. you can watch an agent call them at /mcp/try.
building an ai-chat portfolio that doesn't feel like ai slop

rebuilt the chat with the same warm-machine palette as the rest of the site, killed the gradient send button (rust accent only on the active state), wrote the empty-state copy as a real question ("what do you want to know about my work?" → not "ask me anything"), and lowered the avatar density. the bans list i ran against:

  • no purple-to-blue gradient anywhere (banned at the css-token layer)
  • no "elevate, seamless, unleash, next-gen" in any headline
  • no "ask me anything" / "learn more" placeholder copy
  • no avatar bubbles wider than 32px
  • no emoji in the assistant's replies (configured at the system prompt)
  • no skill radar charts, no proficiency bars, no tech-stack icon walls
  • no centered hero with a glow effect
  • no model name shown in chrome — the model is implementation, not branding
What I tried first

default vercel ai sdk chat ui — purple gradient send button, generic empty state, “ask me anything” placeholder.

Why it failed

the chat looked exactly like every other AI integration in 2025. the visitor stopped reading after the third familiar pattern. the chat was supposed to be a feature; it was reading as a stamp.

Try it

the same public /mcp endpoint, called by a live agent. real round-trips; no fixture.

/mcp/try runs a mastra agent against the public server and shows each json-rpc call with its latency, next to a terminal running the npx bokendell cli.

the result

30openapi endpoints
22api packages
3agent-readable surfacesllms · a2a · mcp
1design direction across every page

continuous deploy on fly · sentry tracing on every route · scale-to-zero web and api machines · zero gradient text · zero skill radars · zero icon walls.

⌘Kterminal⌘Lask