Skip to content

Case study

This résumé site

Bilingual static résumé (Astro + Tailwind CSS) that exposes 19 WebMCP tools to AI agents, runs semantic search on the device (multilingual-e5-small on WebAssembly) and publishes llms.txt, mcp.json and agent.json, with zero backend: every tool, search and CV runs in the browser against resume.json.

Company
Oscar Arenas
Period
2025 – Present
My role
Design, engineering and content

The problem

Recruiters and their AI agents need resume data they can read, verify and query, not only a PDF.

Approach and architecture

One typed data module drives every surface (page, JSON-LD, resume.json, CV files, agent tools); search and tools run in the browser against the published data.

How the pieces fit
  1. Data

    • resume.ts and projects.ts: typed, bilingual content
    • Zod schema check before every build (npm run validate)
  2. Build time

    • Passage embeddings precomputed with multilingual-e5-small (int8)
    • Astro renders the EN/ES pages with JSON-LD, resume.json, llms.txt and social cards
    • CV files: Puppeteer prints the PDF, html-to-docx writes the Word file
  3. Hosting

    • Firebase Hosting serves the static build; the site needs no application server to work
  4. In the browser

    • WebMCP tools and plain HTML forms work on the published data
    • Semantic search in a Web Worker: Transformers.js embeds only the visitor’s query

Every step is a file or a script in this site’s repository.

Architecture

  • Astro static site in English and Spanish; one typed data module (resume.ts) feeds the HTML, JSON-LD, resume.json, the PDF/DOCX generators and the agent tools.
  • 19 WebMCP tools: 16 imperative tools (read-only queries and page actions) registered with document.modelContext in one all-or-nothing batch and also exposed as window.oscarResume, plus 3 declarative <form toolname> tools for the actions a person sends (intro call, CV download, contact).
  • On-device semantic search: passage embeddings (multilingual-e5-small, int8) are precomputed at build time and only the visitor’s query is embedded in the browser with Transformers.js on WebAssembly (WASM), in a Web Worker.
  • Discovery for agents without a browser: llms.txt and llms-full.txt, resume.json with the tool contract, .well-known/agent.json and the .well-known/mcp.json card of the read-only remote MCP server.
  • Zero backend: Firebase Hosting serves static files; every tool, search and CV runs in the browser. The Cloudflare Worker is optional and only relays the contact form and mirrors the tools over MCP.
  • CV pipeline: Puppeteer prints the /print/ route to PDF (a default version and two focus versions) and html-to-docx builds the Word file, in both languages, on every release; all of them, and the Markdown CV, are rendered from one CV model (scripts/lib/cv-model.ts).
  • Quality gates: Vitest unit tests (including a 1.5K-character budget on every tool output), Playwright end-to-end and axe accessibility tests, Lighthouse CI budgets and a CV regression check, in GitHub Actions.

Key decisions and trade-offs

  • WebMCP, not scraping: an agent that calls typed tools gets exact, verifiable data and can act (fit check, tailored CV, a prepared intro-call request) instead of guessing from the markup; the annotations tell it which tools are read-only.
  • On-device embeddings, not an API: the pasted job post never leaves the browser, there is no key to leak or bill to watch, and the ~135 MB model downloads only when the visitor asks for it (never without consent on Data Saver or a metered connection).
  • Declarative tools only for the forms a person has to send (contact, intro call, CV download): the browser fills them in and the visitor presses the button, so nothing is sent silently; every read-only query is an imperative tool an agent can run without a prompt.
  • Zero backend by default: everything runs in the browser against resume.json, so the site keeps working with no server to maintain; the Cloudflare Worker stays optional.
  • JSON-LD is generated from the same data as the page, so search engines and agents see the same facts as people.
  • A Zod schema validates the resume data before every build, so broken dates or missing translations fail the build instead of shipping.
  • Built with AI-assisted coding and review (Claude Code), under strict TypeScript and that pre-build content check.

Outcome

19 agent tools, and CVs in 2 languages as PDF (3 focus versions), Word and Markdown, generated from the same data on every release.

Key facts

  • 19 agent tools
  • 2 languages, 10 CV files per release (6 PDF, 2 Word, 2 Markdown)
  • Lighthouse Agentic Browsing: {{LIGHTHOUSE_AGENTIC}}

Restated from the resume, with no estimates.

My role

Design, engineering and content

Stack

  • Astro
  • TypeScript
  • Tailwind CSS
  • Transformers.js
  • WebMCP
  • JSON-LD
  • Puppeteer
  • Playwright
  • Vitest
  • GitHub Actions
  • Lighthouse CI
  • Firebase Hosting

Related