docs(docs): add AGENTS documentation and README files

This commit is contained in:
Prad Nukala committed 2026-08-19 14:11:48 -04:00
1 parent bff9f9f999
commit 8a191f65cc
8 files changed
+364 -42

No files matched your search

+47
View File
@@ -0,0 +1,47 @@
<!-- Generated: 2026-06-30 | Updated: 2026-06-30 -->
# prad.nu
## Purpose
Personal CV / portfolio site for Prad Nukala (https://prad.nu). A static [Astro](https://astro.build) v6 site (forked from the Astro Cactus theme) organised into four content sections — **Projects**, **Experience**, **Writing**, **Speaking** — where Experience entries double as a cross-linking taxonomy. See `README.md` for the human-facing overview.
## Key Files
| File | Description |
|------|-------------|
| `package.json` | Dependencies and scripts (pnpm). |
| `astro.config.ts` | Astro integrations (MDX, sitemap, icon, robots, webmanifest, expressive-code), markdown remark/rehype pipeline, Satori OG fonts. |
| `tailwind.config.ts` | Tailwind v4 config (most styling is in `src/styles/global.css`). |
| `tsconfig.json` | TypeScript config; defines the `@/*` → `src/*` path alias. |
| `biome.json` | Biome linter/formatter config (`pnpm check` / `pnpm lint`). |
| `mise.toml` / `pnpm-workspace.yaml` | Toolchain + workspace config. |
| `README.md` | Project purpose, content model, frontmatter reference. |
## Subdirectories
| Directory | Purpose |
|-----------|---------|
| `src/` | All application source (see `src/AGENTS.md`). |
| `public/` | Static assets served as-is (see `public/AGENTS.md`). |
## For AI Agents
### Working In This Directory
- Package manager is **pnpm**. Output is **static** (`output: 'static'`, `./dist`) — no SSR adapter.
- Import from source via the `@/` alias (e.g. `@/site.config`), not long relative paths.
- Most site-wide config (title, url, `socialLinks`, `streamOrigin`, `menuLinks`) lives in `src/site.config.ts`.
### Testing Requirements
- `pnpm build` is the primary correctness gate — it runs `astro check`-level content validation and fails on bad frontmatter, broken collection refs, or type errors.
- `pnpm check` runs `astro check` + Biome. `pnpm dev` serves locally for visual checks.
### Common Patterns
- Content lives in Content Collections; schema is defined once in `src/content.config.ts`.
- `is:inline` is required on `<script type="application/ld+json">` and similar non-bundled scripts.
## Dependencies
### External
- `astro` v6, `tailwindcss` v4 — framework + styling.
- `@astrojs/mdx`, `@astrojs/rss`, `@astrojs/sitemap`, `astro-icon`, `astro-webmanifest`, `astro-robots-txt`, `astro-expressive-code`.
- `satori` + `sharp` — OG image generation. `pagefind` — static search. `@mux`? no — speaking uses Cloudflare Stream via an iframe (no player dep).
<!-- MANUAL: Any manually added notes below this line are preserved on regeneration -->
+154
View File
@@ -0,0 +1,154 @@
<!--toc:start-->
- [What this is](#what-this-is)
- [Experience as a taxonomy](#experience-as-a-taxonomy)
- [Tech](#tech)
- [Commands](#commands)
- [Content](#content)
- [Projects (`src/content/projects`)](#projects-srccontentprojects)
- [Experience (`src/content/experience`)](#experience-srccontentexperience)
- [Writing (`src/content/writing`)](#writing-srccontentwriting)
- [Speaking (`src/content/speaking`)](#speaking-srccontentspeaking)
- [Configure](#configure)
- [Deploy](#deploy)
- [Acknowledgment](#acknowledgment)
- [License](#license)
<!--toc:end-->
<div align="center">
<img alt="Prad Nukala" src="./public/avatar.png" width="96" />
</div>
<h1 align="center">pradnukala.com</h1>
<p align="center">The personal CV &amp; portfolio site of <strong>Prad Nukala</strong> — engineer and founder.</p>
## What this is
This repo is my personal website at [www.pradnukala.com](https://www.pradnukala.com) (prad.nu redirects here). It's a static [Astro](https://astro.build) site (originally forked from the [Astro Cactus](https://github.com/chrismwilliams/astro-theme-cactus) theme) reworked into a portfolio organised around four sections:
| Section | Route | Purpose |
| ------------------ | -------------- | ------------------------------------------------------------ |
| **Projects** | `/projects` | Things I've built, with links to live sites and source. |
| **Experience** | `/experience` | Resume-style roles, which also act as a taxonomy (see below). |
| **Writing** | `/writing` | Essays, notes, and articles. |
| **Speaking** | `/speaking` | Talks, with an embedded YouTube player. |
### Experience as a taxonomy
Experience entries are the connective tissue of the site. Projects, writing, and talks each declare an `experiences` array in their frontmatter that references experience entries by id. Each experience page then renders its own write-up **plus** every project, post, and talk filed under it — so the content cross-links automatically.
## Tech
- [Astro](https://astro.build) v6 (static output, no adapter required)
- [Tailwind CSS](https://tailwindcss.com) v4
- [Content Collections](https://docs.astro.build/en/guides/content-collections/) with type-checked frontmatter (`src/content.config.ts`)
- Embedded YouTube players for speaking videos
- [Satori](https://github.com/vercel/satori) OG images, [Pagefind](https://pagefind.app/) search, RSS, sitemap, and `Person` JSON-LD on the homepage for SEO
- Dark / light mode, accessible semantic markup
## Commands
| Command | Action |
| :--------------- | :-------------------------------------------------- |
| `pnpm install` | Install dependencies |
| `pnpm dev` | Start the local dev server |
| `pnpm build` | Build the production site to `./dist/` |
| `pnpm postbuild` | Build the Pagefind static search index |
| `pnpm preview` | Preview the production build locally |
| `pnpm sync` | Generate types from the content config |
## Content
Content lives in `src/content/<collection>` as `.md`/`.mdx` files; the filename becomes the slug. The schema for each collection is defined in `src/content.config.ts`.
### Projects (`src/content/projects`)
| Property | Required | Notes |
| --------------- | :------: | -------------------------------------------------- |
| `title` | ✓ | Max 60 chars. |
| `startDate` | ✓ | Date. |
| `endDate` | | Omit for ongoing projects. Projects are sorted by `endDate`, most recent first (ongoing on top). |
| `description` | | Used for meta description. |
| `link` | | URL to the live project. |
| `repo` | | URL to the source repository. |
| `tags` | | Skills/technologies — double as tags for cross-project browsing at `/projects/tags/<tag>`. |
| `experiences` | | Array of experience ids this project is filed under. |
### Experience (`src/content/experience`)
| Property | Required | Notes |
| --------------- | :------: | -------------------------------------------------- |
| `title` | ✓ | Display name of the experience (also its id via filename). |
| `organization` | ✓ | Company / org. |
| `startDate` | ✓ | Date. |
| `endDate` | | Omit for current/ongoing. |
| `role` | | Job title. |
| `location` | | e.g. "Remote". |
| `url` | | Org website. |
| `description` | | Short summary. |
### Writing (`src/content/writing`)
| Property | Required | Notes |
| --------------- | :------: | -------------------------------------------------- |
| `title` | ✓ | Max 60 chars. |
| `description` | ✓ | Meta description. |
| `publishDate` | ✓ | Date. |
| `updatedDate` | | Date. |
| `coverImage` | | `{ src, alt }`. |
| `ogImage` | | Skip Satori generation with a custom OG image. |
| `tags` | | String array. |
| `experiences` | | Array of experience ids. |
| `externalUrl` | | If set, the entry links out to this URL (an article published on Fast Company, Medium, LinkedIn, …) instead of rendering a local page. |
| `publisher` | | Publisher name shown as a badge next to external entries (e.g. "Fast Company"). |
| `draft` | | `true` excludes the post from production builds. |
| `pinned` | | Pin to the top of `/writing`. |
To surface an article published elsewhere (PESOS), add a stub with no body:
```md
---
title: "Why user-owned identity matters"
description: "A short summary of the piece."
publishDate: "2025-01-15"
externalUrl: "https://www.fastcompany.com/…"
publisher: "Fast Company"
tags: ["identity"]
---
```
It appears in `/writing`, RSS, and the `/skills` taxonomy, links straight to the publisher (new tab, with a `↗ Publisher` badge), and gets no local detail page — so there's no duplicate-content risk.
### Speaking (`src/content/speaking`)
| Property | Required | Notes |
| ---------------- | :------: | ------------------------------------------------- |
| `title` | ✓ | Max 60 chars. |
| `description` | ✓ | Meta description. |
| `publishDate` | ✓ | Date. |
| `youtubeId` | ✓ | YouTube video ID (the `v=` value). |
| `event` | | Conference / event name. |
| `tags` | | String array. |
| `experiences` | | Array of experience ids. |
| `draft` | | `true` excludes the talk from production builds. |
## Configure
Most site-wide settings live in **`src/site.config.ts`**:
- `siteConfig` — title, author, description, `url` (used for canonical URLs and OG tags), locale.
- `socialLinks` — GitHub / X / LinkedIn / Medium / Discord / Telegram / email, shown in the footer and homepage intro.
- `menuLinks` — header/footer navigation.
Replace `public/avatar.png` (header logo) and `public/social-card.png` (default OG image) with your own.
## Deploy
Static output, so it builds to `./dist/` with no adapter. See the [Astro deploy guides](https://docs.astro.build/en/guides/deploy/). For Cloudflare Workers, point the assets directory at `./dist` with a static [Wrangler config](https://developers.cloudflare.com/workers/framework-guides/web-apps/astro/).
## Acknowledgment
Built on the [Astro Cactus](https://github.com/chrismwilliams/astro-theme-cactus) theme by Chris Williams.
## License
MIT
-42
View File
@@ -1,42 +0,0 @@
<div align="center">
<img src="./assets/generated/galaxy-header.svg" width="850" alt="Galaxy Header"/>
</div>
<br/>
<p align="center">
<a href="https://x.com/basedprad"><img alt="Custom badge" src="https://shieldcn.dev/badge/.svg?variant=outline&amp;size=default&amp;logo=ri%3APiXLogo" /></a>
<a href="https://linkedin.com/in/pradn"><img alt="badge" src="https://shieldcn.dev/badge/.svg?variant=outline&amp;size=default&amp;logo=lu%3ALinkedin" /></a>
<a href="https://medium.com/@prnk28"><img alt="badge" src="https://shieldcn.dev/badge/.svg?variant=outline&amp;size=default&amp;logo=ri%3AFaMedium" /></a>
<a href="https://discord.com/users/788422222930640936"><img alt="badge" src="https://shieldcn.dev/badge/.svg?variant=outline&amp;size=default&amp;logo=discord" /></a>
<a href="mailto:i@prad.nu"><img alt="badge" src="https://shieldcn.dev/badge/.svg?variant=outline&amp;size=default&amp;logo=lu%3AMail" /></a>
<a href="https://pradnukala.com"><img alt="badge" src="https://shieldcn.dev/badge/.svg?variant=outline&amp;size=default&amp;logo=lu%3AGlobe" /></a>
</p>
<br/>
## About Me
I help shape the open standards behind user-owned identity as a working-group member at the W3C ([DIDs](https://www.w3.org/groups/wg/did/former-participants/), WebAuthn, [WebAssembly](https://www.w3.org/groups/wg/wasm/former-participants/)) and the Decentralized Identity Foundation (UCAN, DWN). I've been shipping software since age 12 — three apps with over 1M downloads, technical writing read 120k+ times, and bylines in Fast Company.
<br/>
<div align="center">
<img src="./assets/generated/stats-card.svg" width="850" alt="Mission Telemetry"/>
</div>
<br/>
<p align="center">
<img alt="chart" src="https://shieldcn.dev/chart/github/commits/prdlk.svg?align=true&amp;bg=transparent&amp;logo=false&amp;title=Commit+History+%28prdlk%29" />
</p>
<br/>
<div align="center">
<img src="./assets/generated/tech-stack.svg" width="850" alt="Tech Stack"/>
</div>
<br/>
+50
View File
@@ -0,0 +1,50 @@
<!-- Parent: ../AGENTS.md -->
<!-- Generated: 2026-06-30 | Updated: 2026-06-30 -->
# src
## Purpose
All application source: configuration, content collections, pages/routes, layouts, components, data helpers, styles, and build plugins.
## Key Files
| File | Description |
|------|-------------|
| `site.config.ts` | Site metadata (`siteConfig`), `socialLinks`, `menuLinks`, and Expressive Code options. Primary place to edit site-wide settings. |
| `content.config.ts` | Content Collection definitions + Zod schemas for `writing`, `projects`, `experience`, `speaking`. Experience refs are validated via `reference("experience")`. |
| `types.ts` | Shared TS types (`SiteConfig`, `SiteMeta`, webmention types, `AdmonitionType`). |
| `env.d.ts` | Ambient type declarations. |
## Subdirectories
| Directory | Purpose |
|-----------|---------|
| `assets/` | Build-time assets, currently OG fonts (see `assets/AGENTS.md`). |
| `components/` | Reusable `.astro` components (see `components/AGENTS.md`). |
| `content/` | Markdown content for the four collections (see `content/AGENTS.md`). |
| `data/` | Collection query helpers (see `data/AGENTS.md`). |
| `layouts/` | Page shells (see `layouts/AGENTS.md`). |
| `pages/` | File-based routes + endpoints. **No `AGENTS.md` here** — any `.md` under `src/pages` becomes a public route, so docs for this dir live in this file (see "Routing & OG images" below). |
| `plugins/` | Custom remark plugins (see `plugins/AGENTS.md`). |
| `styles/` | Global CSS + block/component styles (see `styles/AGENTS.md`). |
| `utils/` | Pure helper functions (see `utils/AGENTS.md`). |
## For AI Agents
### Working In This Directory
- Collection **keys match their content dir and route**: `writing`→`/writing`, `projects`→`/projects`, `experience`→`/experience`, `speaking`→`/speaking`.
- When changing a collection schema in `content.config.ts`, run `pnpm build` to regenerate `astro:content` types and catch frontmatter mismatches.
### Routing & OG images (`src/pages`)
- Any `.md`/`.mdx`/`.astro` under `src/pages` becomes a route — do **not** put `AGENTS.md` or other docs there (they'd ship as public pages). Document `pages/` here instead.
- Each section has `[...page].astro` (paginated list) + `[...slug].astro` (detail); plus `rss.xml.ts` feeds and a dynamic OG-image endpoint.
- `og-image/[...slug].png.ts` generates per-entry social images for **all** collections (namespaced `/og-image/<type>/<id>.png`) via Satori + Sharp, cached by `_cacheUtil.ts` (bump `CACHE_VERSION` when changing `_ogMarkup.ts`). Files prefixed `_` are private modules, not routes.
- The `/experience/[...slug]` page is the taxonomy hub (`getContentForExperience`), listing related projects/writing/talks.
### Common Patterns
- The `experiences` frontmatter array (on projects/writing/speaking) holds `reference("experience")` entries, resolved with `getEntries`.
## Dependencies
### Internal
- Nearly everything imports `@/site.config` and `@/content.config`-derived collection types.
<!-- MANUAL: -->
+26
View File
@@ -0,0 +1,26 @@
<!-- Parent: ../AGENTS.md -->
<!-- Generated: 2026-06-30 | Updated: 2026-06-30 -->
# layouts
## Purpose
Page shells that wrap route content with `<head>`, header, footer, and theming.
## Key Files
| File | Description |
|------|-------------|
| `Base.astro` | Root shell for all pages. Renders `BaseHead`, `ThemeProvider`, `Header`, `<main class="mb-20">`, `Footer`, and prefetch speculation rules. Takes a `meta: SiteMeta` prop; `description` defaults to `siteConfig.description`. Sets `max-w-3xl`, `font-mono`, padding. |
| `BlogPost.astro` | Layout for individual writing entries. Renders `Masthead`, optional `TOC`, the prose body, webmentions, and a back-to-top button. Builds the OG image URL as `/og-image/${post.id}.png`. |
## For AI Agents
### Working In This Directory
- Every page should render inside `Base.astro` (directly or via `BlogPost.astro`) and pass a `meta` object (`title` required; `description`, `ogImage`, `articleDate` optional).
- `<main>` carries `mb-20` to separate content from the footer's top border — adjust here for global content/footer spacing.
## Dependencies
### Internal
- `@/components/BaseHead.astro`, `@/components/layout/*`, `@/components/blog/*`, `@/site.config`, `@/types`.
<!-- MANUAL: -->
+27
View File
@@ -0,0 +1,27 @@
<!-- Parent: ../AGENTS.md -->
<!-- Generated: 2026-06-30 | Updated: 2026-06-30 -->
# plugins
## Purpose
Custom remark plugins wired into Astro's markdown pipeline (`astro.config.ts` → `markdown.remarkPlugins`).
## Key Files
| File | Description |
|------|-------------|
| `remark-admonitions.ts` | Turns `:::tip`/`:::note`/`:::important`/`:::caution`/`:::warning` directives into styled admonition blocks. Types defined in `@/types` (`AdmonitionType`); styled by `src/styles/components/admonition.css`. |
| `remark-github-card.ts` | Renders a GitHub repo card from a directive. Styled by `src/styles/components/github-card.css`. |
| `remark-reading-time.ts` | Computes reading time (via `reading-time`) and injects it into frontmatter; surfaced as `remarkPluginFrontmatter.readingTime` in `BlogPost.astro`. |
## For AI Agents
### Working In This Directory
- These use the unified/mdast ecosystem (`unist-util-visit`, `mdast-util-directive`, `hastscript`). Directive syntax requires `remark-directive` (already configured).
- Adding/removing a plugin requires editing `astro.config.ts`. Add matching CSS under `src/styles/components/` for any new block type.
## Dependencies
### External
- `unified`, `unist-util-visit`, `mdast-util-directive`, `mdast-util-to-string`, `hastscript`, `reading-time`.
<!-- MANUAL: -->
+31
View File
@@ -0,0 +1,31 @@
<!-- Parent: ../AGENTS.md -->
<!-- Generated: 2026-06-30 | Updated: 2026-06-30 -->
# styles
## Purpose
Global CSS and component/block styles. Tailwind v4 is configured via CSS (`global.css`) rather than a large JS config.
## Key Files
| File | Description |
|------|-------------|
| `global.css` | Tailwind import + theme: color tokens (`--color-global-bg`, `--color-global-text`, `--color-accent`, `--color-link`, `--color-muted`, `--color-special-*`), dark/light variants, base element styles, and the `cactus-link` / `title` utility classes. |
## Subdirectories
| Directory | Purpose |
|-----------|---------|
| `blocks/` | `search.css` — Pagefind search UI styling. |
| `components/` | `admonition.css` and `github-card.css` — styles for the matching remark plugins. |
## For AI Agents
### Working In This Directory
- Use the defined color tokens (e.g. `text-muted`, `bg-global-bg`, `border-global-text/15`) for theme consistency rather than hardcoded colors — they adapt to dark/light mode.
- New markdown block plugins (in `src/plugins/`) should get their CSS here under `components/`.
## Dependencies
### External
- `tailwindcss` v4, `@tailwindcss/typography` (prose), `cssnano`, `autoprefixer`.
<!-- MANUAL: -->
+29
View File
@@ -0,0 +1,29 @@
<!-- Parent: ../AGENTS.md -->
<!-- Generated: 2026-06-30 | Updated: 2026-06-30 -->
# utils
## Purpose
Pure, framework-agnostic helper functions used across components, pages, and data helpers.
## Key Files
| File | Description |
|------|-------------|
| `date.ts` | `getFormattedDate` (locale-aware, per `siteConfig.date`) and `collectionDateSort` — sorts `writing`/`projects`/`speaking`/etc. by `publishDate` descending. |
| `generateToc.ts` | Builds a nested table-of-contents tree from Astro markdown headings (used by `TOC.astro`). |
| `remark.ts` | Shared remark/markdown helpers. |
| `domElement.ts` | Small DOM helpers for client-side scripts. |
| `webmentions.ts` | Fetches and caches webmentions from webmention.io for the webmention components. |
## For AI Agents
### Working In This Directory
- `collectionDateSort` is typed for entries with a `publishDate`; experience entries (which use `startDate`/`endDate`) are sorted in `@/data/experience.ts` instead.
- Keep these pure and side-effect-free where possible; `webmentions.ts` is the exception (network + cache).
## Dependencies
### Internal
- `@/site.config` (date locale), `@/types`.
<!-- MANUAL: -->