This is a single Next.js 16 app (App Router) that serves both documentation and blog content for the .agent Community. It replaced a Fumadocs monorepo in Feb 2026.
The system has three layers:
content/ Markdown source files (MDX)
|
src/lib/ Content engine (pure logic, zero React)
|
src/app/ Next.js routes, renders MDX with custom components
src/components/ React components for layout, sidebar, TOC, etc.
All content lives in content/ as MDX files:
content/docs/*.mdx— Documentation pages. Navigation order defined inmeta.json.content/blog/YYYY-MM-DD-*.mdx— Blog posts. Sorted by frontmatterdatefield.
Content files use standard MDX. Custom components (Card, Cards, Callout) are injected at render time — no imports needed in MDX files.
{
"title": ".agent Community",
"pages": ["index", "work-items"]
}"index"maps tocontent/docs/index.mdx, route/docs- Other entries resolve to
{name}.mdxor{name}/index.mdx - Nested directories can have their own
meta.jsonwith apagesarray for child nav items
Filename: 2026-02-05-why-aid-now-supports-ucp.mdx
- Date prefix
YYYY-MM-DD-is stripped to produce the slug:why-aid-now-supports-ucp - Route:
/blog/why-aid-now-supports-ucp - The frontmatter
datefield takes precedence over the filename date for sorting
Pure TypeScript, zero React dependencies. Can be extracted as a standalone package.
| File | Purpose |
|---|---|
types.ts |
DocPage, BlogPost, Heading, NavItem interfaces |
docs.ts |
getDoc(slug[]), getAllDocSlugs(), getDocNavigation() |
blog.ts |
getPost(slug), getAllPosts(), getAllTags(), getAllPostSlugs() |
search.ts |
getSearchIndex(), search(query) — in-memory substring matching |
The content engine reads files from disk using fs and parses frontmatter with gray-matter. Headings are extracted via regex for the table of contents. No caching — filesystem is source of truth.
MDX is rendered server-side via next-mdx-remote/rsc:
MDX source
-> remark-gfm (tables, task lists)
-> rehype-slug (heading IDs)
-> rehype-autolink-headings (anchor wrapping)
-> mdx-components.tsx (style overrides, Card/Cards, mermaid detection)
-> HTML output
Custom MDX components (src/components/mdx-components.tsx) override all HTML elements with Tailwind-styled versions. Mermaid code blocks are detected and routed to a client-side renderer.
| Route | Type | Description |
|---|---|---|
/ |
Static | Redirects to /docs |
/docs |
SSG | Docs landing (catch-all [[...slug]]) |
/docs/[slug] |
SSG | Individual doc pages |
/blog |
Dynamic | Blog index with tag filtering via ?tag= |
/blog/[slug] |
SSG | Individual blog posts |
/api/search |
Dynamic | Search API (?q=query) |
/api/mdx/[...slug] |
Dynamic | Raw MDX export (text/markdown or ?format=json) |
/rss.xml |
Dynamic | RSS feed |
/sitemap.xml |
Static | Auto-generated from all content |
/robots.txt |
Static | Standard robots file |
/aid/* |
Redirect | Permanent redirect to aid.agentcommunity.org |
public/assets/— Logos (light/dark SVGs)public/og/— Build-time generated OG images (1200x630 PNG, gitignored)public/blog/— Blog post imagespublic/favicon.ico
OG images are generated by scripts/generate-og-images.ts using satori + resvg. They run at build time (not runtime), so Vercel serves them as static files with zero function invocations.
metadataBaseset in root layout — all relative OG URLs resolve correctly- Canonical URLs on every page
- OpenGraph + Twitter card meta tags with static OG images
- JSON-LD structured data: Organization + WebSite (root layout)
- RSS feed linked via
<link rel="alternate"> - Sitemap with all docs + blog URLs
Single Vercel project. vercel.json runs pnpm generate:og && pnpm build. No monorepo, no workspaces, no pnpm-workspace.yaml.
- No Fumadocs — Custom renderer is simpler for our small content set and gives full control.
- Server-side MDX —
next-mdx-remote/rscmeans zero client JS for content pages. - Static OG images — Built at build time to avoid Vercel function costs.
- Reusable lib/ — Content engine has zero React deps for portability.
- meta.json navigation — Simple JSON ordering instead of filesystem-order or frontmatter-based nav.
- Single app — Blog and docs share layout, theme, search. No multi-zone complexity.