Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions docs/ai-python/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Geistdocs agent instructions

This project uses the packaged Geistdocs architecture. The `@vercel/geistdocs` package owns shared runtime behavior; this app owns local content, configuration, adapters, and site-specific routes.

Use these instructions when an AI coding agent edits this project.

## Architecture

- Runtime features come from `@vercel/geistdocs`, including the docs page renderer, layout helpers, MDX components, search, Ask AI, markdown routes, proxy helpers, and source helpers.
- `@vercel/geistdocs` owns the Ask AI client, server route behavior, and AI SDK v6 runtime dependencies. Do not fork package internals to fit an older app-level `ai` version.
- Local files are user-owned adapters. They should stay thin and call public package exports from `@vercel/geistdocs/*`.
- Do not copy package internals into the app to make a customization. Prefer configuring an adapter file or upgrading `@vercel/geistdocs`.
- Do not deep import from `@vercel/geistdocs/dist` or edit files in `node_modules/@vercel/geistdocs`.
- Do not edit generated directories such as `.source/`, `.next/`, `node_modules/`, or build output.

## Package Docs For Agents

- When package API behavior is unclear, read the installed package docs in `node_modules/@vercel/geistdocs/docs` before guessing.
- Start with `node_modules/@vercel/geistdocs/docs/agents.md` and `node_modules/@vercel/geistdocs/docs/sitemap.md` to identify the relevant focused page.
- Use `node_modules/@vercel/geistdocs/docs/pages/*.md` for task-specific guidance and `node_modules/@vercel/geistdocs/docs/llms.txt` only when you need broad package context.
- These package docs are read-only generated artifacts. Do not edit files under `node_modules/@vercel/geistdocs`; change local adapter files or update the package instead.

## Common edit targets

| Task | Edit |
| --- | --- |
| Configure site title, logo, nav, GitHub links, AI prompt, suggestions, translations, `basePath`, or `siteId` | `geistdocs.tsx` |
| Add or update documentation pages | `content/docs/**/*.mdx` |
| Control sidebar order, groups, and labels | `content/docs/meta.json` |
| Override MDX components | `components/geistdocs/mdx-components.tsx` |
| Wrap the site provider, analytics, or global client behavior | `components/geistdocs/provider.tsx` |
| Customize the docs layout shell | `components/geistdocs/docs-layout.tsx` |
| Configure the Fumadocs source adapter or versioned docs | `lib/geistdocs/source.ts` |
| Configure Fumadocs collections and source-safe MDX processing | `source.config.ts` |
| Configure the docs page renderer | `app/[lang]/docs/[[...slug]]/page.tsx` |
| Configure AI-readable markdown output | `app/[lang]/agents.md/route.ts`, `app/[lang]/.well-known/mcp.json/route.ts`, `app/[lang]/llms.txt/route.ts`, `app/[lang]/llms.mdx/[[...slug]]/route.ts`, `app/[lang]/sitemap.md/route.ts` |
| Configure chat or search APIs | `app/api/chat/route.ts`, `app/api/search/route.ts` |
| Add request handling before or after Geistdocs routing | `proxy.ts` |
| Edit the marketing home page | `app/[lang]/(home)/**` |
| Edit shared styles | `app/global.css`, `app/styles/geistdocs.css` |

## Content guidelines

- Put docs in `content/docs` unless the project has added another source in `lib/geistdocs/source.ts`.
- Add each new page to `content/docs/meta.json` so it appears in the sidebar.
- Use MDX frontmatter with at least `title` and `description` for documentation pages.
- Keep slugs stable unless the task explicitly includes redirects or link updates.
- When adding translated content, follow the existing locale suffix pattern, such as `page.cn.mdx`.
- Use `CopyPrompt` when a page should give readers a prompt they can copy into a coding agent.

## Routing and proxy guidelines

- Keep App Router route files as thin adapters around package helpers such as `createDocsPage`, `createChatRoute`, `createLlmsRoute`, and `createProxy`.
- Keep `export const config` in `proxy.ts` as a static object. Next.js must parse proxy matchers at build time.
- Use proxy matcher exclusions that only match `/api` and `/api/...`, such as `api(?:/|$)`. Do not exclude broad prefixes like `api`, because that also excludes routes such as `/api-reference`.
- Preserve markdown negotiation unless the task explicitly changes AI-readable output. Geistdocs serves `/agents.md`, `/llms.txt`, `/.well-known/mcp.json`, and per-page Markdown for `.md`, `.mdx`, `Accept: text/markdown`, and AI-agent requests.
- When adding custom proxy behavior, prefer `before`, `after`, and `markdownRoutes` options on `createProxy` instead of replacing the proxy.
- Use explicit `markdownRoutes` for root-mounted docs or any site where homepage/app routes coexist with docs routes.

## Ask AI and Vertex proxy guidelines

- Leave `GEISTDOCS_CHAT_PROXY_URL` unset to use the default AI Gateway path. In that mode, `app/api/chat/route.ts` calls `createChatRoute` without a `proxy` option and uses the local docs search tool during the AI SDK `streamText` loop.
- Geistdocs Ask AI targets AI SDK v6: `ai` v6 and `@ai-sdk/react` v3. Keep those dependencies on the generated package versions unless a `@vercel/geistdocs` release changes them.
- If the app uses `ai` or `@ai-sdk/react` for product code outside Geistdocs, migrate that app code separately or let the package manager install separate versions. Do not downgrade Geistdocs Ask AI to match unrelated app code.
- Set `GEISTDOCS_CHAT_PROXY_URL` only when Ask AI should route through the central Vertex-backed proxy. The value must include the `/vertex` route, such as `https://<geistdocs-platform-deployment>/vertex`.
- Do not add Vertex credentials to a Geistdocs site. The central platform proxy forwards the Vercel OIDC token in `x-vercel-trusted-oidc-idp-token`; the Vertex deployment should trust the platform Vercel project through Deployment Protection Trusted Sources.
- Use `GEISTDOCS_CHAT_PROXY_TOKEN` only for a custom proxy that requires bearer authentication. The default Geistdocs platform `/vertex` proxy does not require it.
- Keep `app/api/chat/route.ts` as a thin adapter around `createChatRoute`. Prefer configuring `GEISTDOCS_CHAT_PROXY_URL` and `GEISTDOCS_CHAT_PROXY_TOKEN` over forking the package chat route.
- If custom chat client code uses `DefaultChatTransport.prepareSendMessagesRequest`, preserve `messages` in the returned `body` when adding fields such as `currentRoute`. Returning a custom `body` replaces the AI SDK default request body.

## Migration guidelines

- When migrating from Fumadocs or a custom Geist docs site, inventory `source.config.ts`, route files, `middleware.ts` or `proxy.ts`, `public/llms.txt`, OG routes, Tailwind CSS setup, and required environment variables before editing.
- Inventory direct app usage of `ai` and `@ai-sdk/react`. Package-owned Ask AI uses AI SDK v6; migrate local AI SDK code separately from Geistdocs route adapters.
- Import source-config helpers from `@vercel/geistdocs/source-config` in `source.config.ts`. Do not import runtime component entry points from source config.
- Move existing `middleware.ts` behavior into `createProxy({ before })` or `createProxy({ after })` hooks.
- Delete `public/llms.txt` when using `createLlmsRoute`; otherwise the static file can mask the App Router route.
- Set `openGraph.images` in `createDocsPage` only when the app includes the Geistdocs OG route, or override metadata to avoid broken `/og/...` URLs.
- Add Tailwind CSS v4 `@source` entries for `@vercel/geistdocs` and related runtime dependencies when migrating styles.
- Add local fallbacks for production-only environment variables so migration builds do not require production secrets.

## Package updates

- Use `pnpm exec geistdocs update` to update package-based Geistdocs projects.
- `geistdocs update` updates the `@vercel/geistdocs` dependency. It does not overwrite local adapter files.
- Review dependency changes and run the verification commands before committing an update.

## Commands

- Start development: `pnpm dev`
- Build for production: `pnpm build`
- Start the built app: `pnpm start`
- Regenerate Fumadocs output after dependency installation: `pnpm postinstall`
- Update Geistdocs: `pnpm exec geistdocs update`
- Run translations if configured: `pnpm translate`

## Verification

- Run `pnpm build` after changing routes, config, source setup, MDX components, or package versions.
- Run `pnpm dev` and open the changed pages when visual layout, navigation, or MDX rendering changes.
- Check both `/docs` and AI-readable routes such as `/agents.md`, `/.well-known/mcp.json`, `/llms.txt`, or a page-level `.md` URL when changing content routing or proxy behavior.
- Confirm no secrets were added to source files. Use `.env.local` for local values and keep it out of Git.
2 changes: 1 addition & 1 deletion docs/ai-python/app/[lang]/(home)/components/hero.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { ReactNode } from "react";
import { Badge } from "@/components/ui/badge";
import { Badge } from "@vercel/geistdocs/components/badge";

interface HeroProps {
badge: string;
Expand Down
7 changes: 4 additions & 3 deletions docs/ai-python/app/[lang]/(home)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { HomeLayout } from "@/components/geistdocs/home-layout";
import { GeistdocsHomeLayout } from "@vercel/geistdocs/home-layout";
import { config } from "@/lib/geistdocs/config";
import { source } from "@/lib/geistdocs/source";

const Layout = async ({ children, params }: LayoutProps<"/[lang]">) => {
const { lang } = await params;

return (
<HomeLayout tree={source.pageTree[lang]}>
<GeistdocsHomeLayout config={config} tree={source.pageTree[lang]}>
<div className="pt-0 pb-32">{children}</div>
</HomeLayout>
</GeistdocsHomeLayout>
);
};

Expand Down
2 changes: 1 addition & 1 deletion docs/ai-python/app/[lang]/(home)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
CommandPromptTrigger,
CommandPromptTriggerDivider,
CommandPromptViewport,
} from "@/components/ui/command-prompt";
} from "@vercel/geistdocs/components/command-prompt";
import { CenteredSection } from "./components/centered-section";
import { CTA } from "./components/cta";
import { Hero } from "./components/hero";
Expand Down
8 changes: 8 additions & 0 deletions docs/ai-python/app/[lang]/.well-known/mcp.json/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { createMcpManifestRoute } from "@vercel/geistdocs/routes/mcp";
import { config } from "@/lib/geistdocs/config";

export const { GET, generateStaticParams, revalidate } = createMcpManifestRoute(
{
config,
}
);
6 changes: 6 additions & 0 deletions docs/ai-python/app/[lang]/agents.md/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { createAgentsRoute } from "@vercel/geistdocs/routes/agents";
import { config } from "@/lib/geistdocs/config";

export const { GET, generateStaticParams, revalidate } = createAgentsRoute({
config,
});
5 changes: 4 additions & 1 deletion docs/ai-python/app/[lang]/docs/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { MobileDocsBar } from "@vercel/geistdocs/mobile-docs-bar";
import { createDocsPage } from "@vercel/geistdocs/pages/docs";
import { getMDXComponents } from "@/components/geistdocs/mdx-components";
import { MobileDocsBar } from "@/components/geistdocs/mobile-docs-bar";
import { config } from "@/lib/geistdocs/config";
import { geistdocsSource } from "@/lib/geistdocs/source";

const docsPage = createDocsPage({
config,
mdx: ({ link }) => getMDXComponents({ a: link }),
openGraph: {
images: true,
},
source: geistdocsSource,
tableOfContentPopover: {
enabled: false,
Expand Down
12 changes: 6 additions & 6 deletions docs/ai-python/app/[lang]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import "../global.css";
import { Footer } from "@/components/geistdocs/footer";
import { Navbar } from "@/components/geistdocs/navbar";
import { Footer } from "@vercel/geistdocs/footer";
import { Navbar } from "@vercel/geistdocs/navbar";
import { GeistdocsProvider } from "@/components/geistdocs/provider";
import { basePath } from "@/geistdocs";
import { config } from "@/lib/geistdocs/config";
import { mono, sans } from "@/lib/geistdocs/fonts";
import { cn } from "@/lib/utils";

Expand All @@ -16,10 +16,10 @@ const Layout = async ({ children, params }: LayoutProps<"/[lang]">) => {
suppressHydrationWarning
>
<body>
<GeistdocsProvider basePath={basePath} lang={lang}>
<Navbar />
<GeistdocsProvider basePath={config.basePath} lang={lang}>
<Navbar config={config} />
{children}
<Footer />
<Footer config={config} />
</GeistdocsProvider>
</body>
</html>
Expand Down
2 changes: 1 addition & 1 deletion docs/ai-python/app/[lang]/llms.mdx/[[...slug]]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ import { geistdocsSource } from "@/lib/geistdocs/source";

export const { GET, generateStaticParams, revalidate } =
createDocsMarkdownRoute({
source: geistdocsSource,
sources: [geistdocsSource],
});
2 changes: 1 addition & 1 deletion docs/ai-python/app/[lang]/llms.txt/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ import { createLlmsRoute } from "@vercel/geistdocs/routes/llms";
import { geistdocsSource } from "@/lib/geistdocs/source";

export const { GET, revalidate } = createLlmsRoute({
source: geistdocsSource,
sources: [geistdocsSource],
});
4 changes: 2 additions & 2 deletions docs/ai-python/app/[lang]/sitemap.md/route.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { createSitemapMarkdownRoute } from "@vercel/geistdocs/routes/sitemap";
import { config } from "@/lib/geistdocs/config";
import { source } from "@/lib/geistdocs/source";
import { geistdocsSource } from "@/lib/geistdocs/source";

export const { GET, generateStaticParams, revalidate, dynamic } =
createSitemapMarkdownRoute({
config,
source,
sources: [{ source: geistdocsSource }],
});
18 changes: 0 additions & 18 deletions docs/ai-python/app/actions/feedback/emotions.ts

This file was deleted.

45 changes: 0 additions & 45 deletions docs/ai-python/app/actions/feedback/index.ts

This file was deleted.

13 changes: 12 additions & 1 deletion docs/ai-python/app/api/chat/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,18 @@ import { createChatRoute } from "@vercel/geistdocs/routes/chat";
import { config } from "@/lib/geistdocs/config";
import { geistdocsSource } from "@/lib/geistdocs/source";

const chatProxyUrl = process.env.GEISTDOCS_CHAT_PROXY_URL;
const chatProxyToken = process.env.GEISTDOCS_CHAT_PROXY_TOKEN;

export const { POST, maxDuration } = createChatRoute({
config,
source: geistdocsSource,
proxy: chatProxyUrl
? {
url: chatProxyUrl,
headers: chatProxyToken
? { Authorization: `Bearer ${chatProxyToken}` }
: undefined,
}
: undefined,
sources: [geistdocsSource],
});
4 changes: 2 additions & 2 deletions docs/ai-python/app/api/search/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createSearchRoute } from "@vercel/geistdocs/routes/search";
import { config } from "@/lib/geistdocs/config";
import { source } from "@/lib/geistdocs/source";
import { geistdocsSource } from "@/lib/geistdocs/source";

export const GET = createSearchRoute({ config, source });
export const GET = createSearchRoute({ config, sources: [geistdocsSource] });
11 changes: 1 addition & 10 deletions docs/ai-python/app/global.css
Original file line number Diff line number Diff line change
@@ -1,20 +1,11 @@
@import "tailwindcss";
@import "./styles/geistdocs.css";

/* Pulsing dot used by the landing page hero badge. */
@theme {
--animate-badge-glow: badge-glow 3s ease-in-out infinite;
--animate-badge-dot: badge-dot 3s ease-in-out infinite;
}

@keyframes badge-glow {
0%, 100% {
box-shadow: 0 0 4px 0 rgb(96 165 250 / 0.2);
}
50% {
box-shadow: 0 0 14px 3px rgb(96 165 250 / 0.35);
}
}

@keyframes badge-dot {
0%, 100% {
opacity: 0.6;
Expand Down
Loading
Loading