AGENTS.md ยท diff
git:20260908.d7a9868 to git:20260908.ab222d4
2 added, 1 removed. Audit A to A.
# x-md
- Landing: `index.html` (`src/main.ts`), shared chrome in `src/chrome.ts`. Docs: Blume MDX in `docs/`, configured by `blume.config.ts`, mounted at `/docs`. Build Blume before Vite; Vite preserves the generated docs in `dist`.
- Tokens are the Tailwind v4 `@theme` block in `src/tokens.css` (shared by the landing page and Blume) (`ink`, `ink-2`, `ink-3`, `ink-4`, `surface`, `raised`, `raised-2`, `line`, `hair`, `accent`, `accent-deep`, `accent-soft`, `cyan`, dark `code`/`code-ink`/`code-dim`). Use them, not hex.
- Look: warm paper `#f7f6f2`, Satoshi, deep green `#146c43`, pill buttons, 16px cards, near-black code panes. Not pcstyle.dev styling.
- Landing copy frame (Theo's feedback): "Tweets are just markdown now", what-you-see vs what-your-agent-sees curl comparison in the `#how` bento, skill install under `#agents`. No stack or provider talk on the landing page.
- Motion: GSAP + ScrollTrigger in `setupMotion` (`src/main.ts`), all gated by `prefers-reduced-motion` via `gsap.matchMedia`.
- Status URLs serve Markdown by default. Discord, Telegram, and Slack preview bots get Open Graph HTML from `lib/embed.ts` via `api/convert.ts`; `GET /oembed` rewrites to `api/oembed.ts`.
- Landing content is pre-rendered at build time: `src/landing.ts` holds the markup, `src/vite-prerender-plugin.ts` writes it into `index.html`, and `src/main.ts` only enhances what is already there. The page must stay readable with JavaScript off, so put content in `landing.ts`, not in a runtime DOM build.
- `middleware.ts` (Vercel Routing Middleware) does Accept-based content negotiation for `/`, `/docs/*`, `/about`, `/contact`, `/privacy`, `/terms`: `Accept: text/markdown` or `?mode=agent` rewrites to the page's `.md` sibling, an unsatisfiable Accept is `406`, and every response gets `Vary: Accept` plus RFC 8288 discovery `Link`s. The parser is `lib/negotiate.ts`. A new negotiated page needs both a `.md` sibling and a matcher entry.
- Every API failure goes through `lib/apierror.ts`: RFC 9457 problem details built from `ERROR_CATALOG`, which is the single source of the machine `code`, its status, title, and `resolution`. Add a code there, not inline โ `lib/openapi.ts`, `api/index.ts`, and `docs/errors.mdx` all render from it.
- Routes are versioned: `/api/v1/*` is the stable machine surface, the permalink routes are the unversioned product surface, and `/api/convert` and `/api/browse` are deprecated aliases that must keep emitting `Deprecation`/`Sunset`/`successor-version` (`setDeprecationHeaders` in `lib/apierror.ts`). The published policy is `docs/versioning.mdx`; keep it, `x-api-lifecycle` in `lib/openapi.ts`, and the `versioning` block in `api/index.ts` in agreement.
- Quotas live in `lib/quotas.ts` and are advertised by `lib/ratelimit-headers.ts`. Policy names ship in response headers and the OpenAPI document, so renaming one is a breaking change.
- `lib/openapi.ts` is the OpenAPI 3.1 source; `bun scripts/build-openapi.ts` renders the committed `public/openapi.json` and `--check` fails when it is stale. Discovery documents are hand-written under `public/` and `public/.well-known/` (`llms.txt`, `agents.md`, `auth.md`, `pricing.md`, `ard.json`, `ai-catalog.json`, `api-catalog`, `mcp/server-card.json`); Vite copies `public/` last, which is how `openapi.json` overrides blume's own.
- Deploy: Vercel after `bun run build`. `vercel.json` configures `dist`, the API handlers, and the public route rewrites.
- Live search provider: `lib/xsearch.ts`; public allowance is a fixed 10 per IP per 15 min plus a shared pool computed in `lib/pool.ts`. Counters live in `lib/ratelimit.ts` (shared Redis via `lib/redis.ts`, memory fallback). Keep provider internals and capacity math out of public prose; describe it as a custom-built provider.
- - Checks before pushing: `bun --bun tsc`, `bun run test`, `bun run build`. `main` is protected: open a PR, CI `build` and CodeRabbit must pass.
+ - Checks before pushing: `bun run test` and `bun run build` (the build already starts with `tsc`). After touching `lib/openapi.ts`, run `bun run openapi:build` and commit the regenerated `public/openapi.json` โ the build rewrites it in place, so `openapi:check` only ever catches a stale committed copy, which is its job in CI. `main` is protected by a ruleset: open a PR, the `build` and CodeRabbit checks must pass, a `Preview` deployment is required, commits must be signed, and the branch must be up to date with `main`. No approvals are required; merges are squash or merge, not rebase.
+ - Open work and the reasoning behind anything deliberately left undone are in `TODO.md`. Read it before starting, and update it when an item lands rather than leaving it stale. It currently tracks the agent-readiness push, including two CodeQL alerts that are knowingly open โ check there before "fixing" them.