src/pages/File-based routes. Every page wraps itself in ../layouts/BaseLayout.astro (which provides head/meta, header, footer, theme, and the scroll-reveal script) except blog posts, which use PostLayout (itself built on BaseLayout). All pages are prerendered (output: "static").
| File | Route | Layout |
|---|---|---|
index.astro | / | BaseLayout |
about.astro | /about | BaseLayout |
projects/index.astro | /projects | BaseLayout |
blog/index.astro | /blog | BaseLayout |
blog/[...slug].astro | /blog/<slug> | PostLayout |
rss.xml.js | /rss.xml | — (endpoint) |
sitemap-index.xml and robots.txt are generated by integrations, not pages.
index.astro (117 lines) — homepageCompact landing: hero → What I do → Selected work → Contact.
Imports Image, Icon, BaseLayout, StatusPill, CopyEmail, SectionLabel, ProjectRow, ContactCard, featuredProjects, RESUME/SITE/SOCIALS, and me (portrait). Defines whatIDo — three { title, body } blocks:
<BaseLayout title={SITE.title} description={SITE.description}>.<section class="container-page pt-8 md:pt-12"> — deliberately not a .reveal (must paint on first frame). The padding was cut from pt-14 md:pt-24: the header is sticky with a bg-canvas/80 backdrop-blur-md, so it needs no clearance beneath it, and the 96px was dead space that pushed HeroDiagram below the fold.
<StatusPill /> (“Open to AI engineering roles · currently @ Petpooja”).label-mono: “Software Engineer · AI Systems · Payments Infrastructure · India”.<h1 class="mt-4 max-w-[22ch] text-display font-700"> “I build AI workflows that hold up in production.” (wraps to two lines at desktop). Stays full-bleed — it sits above the two-column split, not inside it.<div class="lg:grid lg:grid-cols-[minmax(0,1fr)_340px] lg:items-start lg:gap-12">. Column one is the copy/CTA/meta stack described next; column two is <div class="hidden lg:block"><HeroDiagram /></div>. Below lg the diagram is dropped entirely and this collapses to the original single column. The 340px track is what fills the dead space to the right of the lead paragraph at desktop; at lg (1024px) it leaves the left column ~540px, just under max-w-text (560px), so the lead never reflows awkwardly.<p class="max-w-text text-lead text-muted">: “Document pipelines, RAG assistants, tool-calling agents — with evals, guardrails, and a human in the loop where it matters. By day I work on offline payments infrastructure at Petpooja, where a retried request can’t be allowed to move money twice. I bring that discipline to everything with a model in the loop.”<a href="/projects" class="btn-primary">View work</a> + <CopyEmail /> (ghost); stack vertically below sm./about.border-t border-line pt-6): 56px round <Image src={me} width={112} densities=[1,2] loading="eager"> + SITE.location in mono; social icon links (icon-link); “Resume ↗” → RESUME.<section aria-labelledby="what-i-do" class="container-page reveal …">: <SectionLabel id="what-i-do" label="What I do" /> then a md:grid-cols-3 list; each <li class="reveal md:border-l md:border-line md:pl-6 first:md:border-l-0 first:md:pl-0" style="transition-delay: {i*60}ms"> with text-sub title and text-muted body.<section aria-labelledby="selected-work" class="container-page reveal …">: <SectionLabel label="Selected work"> with an “All projects →” accent link in the slot; <ul> of <ProjectRow project index first={i===0} /> for featuredProjects (compact variant, three rows).<section class="container-page reveal …"><ContactCard /></section>.Section spacing: mt-16 md:mt-28.
about.astro (221 lines) — /aboutLong-form, 640px measure, left-aligned. Order is deliberate: AI systems lead, payments is the credibility, stack is quietest.
expertise: two tiers rendered with descending emphasis —
text-fg): Structured extraction · RAG & hybrid retrieval · Tool-calling agents · Evals & regression testing · Guardrails & human-in-the-loop · Prompt & context design · Cost & latency budgeting.text-muted): Offline payment rails (EDC, QR) · Settlement & reconciliation · Idempotent webhooks · Payment orchestration · Postgres performance · Zero-downtime schema evolution.stack (one quiet mono line): TypeScript · Node.js · React · Next.js · PostgreSQL · pgvector · Prisma · Anthropic & OpenAI APIs · LangChain · LangGraph · Zod · Redis · Docker.aiTools: Claude Code / Cursor / ChatGPT & Claude with one-clause uses. (No Copilot — Jay doesn’t use it.).reveal with a SectionLabel)<Image src={me} width={320}> 96/128/160px, radius 14.·-separated inline lists, then STACK mono line.<!-- TODO(jay): add model/API names and one measurable outcome -->); What a workflow needs before I’d call it done (5-bullet checklist: eval set + regression run, confidence signal + review path, idempotent side effects, cost/latency budget, honest failure mode); Where it doesn’t help (why-questions, data modelling, naming, deciding what not to build; “plausible code that quietly does the wrong thing”); What I actually use (2-col mono/name + use).sm:grid-cols-[6rem_1fr]: date column [TODO] — Present (<!-- TODO(jay): start date -->), “Software Engineer” at Petpooja ↗, three bullets (offline payments infra; LLM-backed features in production; partner integrations + idempotent webhooks) marked <!-- TODO(jay): replace with 2–4 specific, defensible bullets -->.<ContactCard />.Meta description is page-specific (passed to BaseLayout).
rss.xml.js (31 lines) — /rss.xmlexport const prerender = true (build-time artifact).GET(context): getCollection("blog", ({ data }) => !data.draft) sorted by pubDate desc; returns rss({ title: "Jay Boricha — Writing", description: SITE.description, site: context.site, items, customData: "<language>en-us</language>" }).title, description, pubDate, link: /blog/<slug>/, and content = full body rendered by markdown-it then sanitize-html (default allow-list + img).site in astro.config.mjs — without it @astrojs/rss throws and the route 500s (that was the state before the revamp).projects/ → projects/AGENT.mdblog/ → blog/AGENT.md