2028-games-guide
AGENTS.md0 starsChanged 24 days agoMITView on GitHub
Six independent scripts; each reads JSON output of upstream stages and writes one file. Run in order, or any subset with --sport=<name> / --force / --dry-run. Paid API calls authenticate through scripts/lib/anthropic-client.ts: locally the SDK finds ANTHROPIC_API_KEY in .env (or an ant auth login profile); in GitHub Actions it uses Workload Identity Federation with no stored key. Research stages (sport, venue, and session facts) use Claude's server-side web search tool ($10 per 1,000 searches plus tokens) and return results through…
- Reads credentials
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,700 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository10 other files it gives its agents.
- .agents/skills/vercel-composition-patterns/AGENTS.mdAGENTS.md
- .agents/skills/vercel-react-best-practices/AGENTS.mdAGENTS.md
- .agents/skills/vercel-react-view-transitions/AGENTS.mdAGENTS.md
- public/llms.txtllms.txt
- frontend-designSkill
- skill-creatorSkill
- vercel-composition-patternsSkill
- vercel-react-best-practicesSkill
- vercel-react-view-transitionsSkill
- web-design-guidelinesSkill
The file
We split this AGENTS.md into the rules it gives an agent
10 rules. About 0 are common, 5 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈5
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 7
Use pnpm for package management in this repo.
- Very specific: line 8
Prefer existing package.json scripts over ad-hoc shell commands when a matching script exists.
- Distinctive: line 41
Every script prints a usage summary with an estimated cost.
- Very specific: line 69
Always ask the user before using any Vercel MCP tools or running vercel CLI commands that touch remote resources (pull, env, deploy, …
- Very specific: line 117
Use existing CSS variables (--lagoon, --sea-ink, --sand, etc.) for theme colors
- Distinctive: line 131
Never include Co-Authored-By or other attribution lines in commits or pull requests
- Very specific: line 132
Use Conventional Commits: type(scope): description (lowercase, imperative mood)
- Distinctive: line 136
Keep commits atomic — one logical change per commit
- Distinctive: line 137
Write concise subject lines (under 72 chars), use body for "why" when needed
- Distinctive: line 141
Keep main history linear: prefer rebasing topic branches onto main instead of merge commits
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
AGENTS.md
This file provides guidance to AI coding agents working with code in this repository.
Commands
- Use
pnpmfor package management in this repo. Do not usenpmoryarnunless the user explicitly asks. - Prefer existing
package.jsonscripts over ad-hoc shell commands when a matching script exists. pnpm dev— Start dev server on port 3000pnpm build— Production buildpnpm preview— Preview production buildpnpm serve:prod— Serve the production build the way Vercel does (static files first, Nitro fallback, brotli) on port 4173pnpm lighthouse— Run Lighthouse CI (mobile) againstpnpm serve:prod; budgets inlighthouserc.json. Requires a priorpnpm buildpnpm screenshot [url] [outFile]— Capture the README screenshot (defaults: production,screenshot.png). Run it manually after visible UI changes and commit the resultpnpm test— Run tests with Vitest (vitest run)pnpm test:e2e— Playwright smoke tests (e2e/) againstpnpm serve:prod, or againstENVIRONMENT_URLwhen set. Requires a priorpnpm build. Tests tagged@smokealso run in production as a Checkly check (checkly.config.ts,__checks__/)pnpm format:check— Check formatting with oxfmtpnpm lint— Lint with oxlintpnpm typecheck— Type-check withtsc --noEmit
Content pipeline commands
Six independent scripts; each reads JSON output of upstream stages and writes one file. Run in order, or any subset with --sport=<name> / --force / --dry-run.
pnpm generate:paris-medals— Rescrape Olympedia intosrc/data/paris-2024-medals.json. One-off; run only when medal data needs refreshing.pnpm generate:sport-facts— Regeneratesrc/data/sport-facts.jsonper sport via Claude with web search, anchored onparis-2024-medals.json. Extra flag:--forceregenerates even whenparisRecapalready populated.pnpm generate:venue-facts— Regeneratesrc/data/venue-facts.jsonper venue via Claude with web search (capacity, history, spectator experience, 2028 changes). Filter:--venue=<name>.pnpm generate:session-facts— Per-session Claude + web search grounding →src/data/session-facts.json(facts, related news, sources). Flags:--stale-days=<n>(re-check briefs older than n days),--no-previous(write briefs from scratch instead of re-checking the stored one),--no-batch,--concurrency=<n>(with--no-batch),--anthropic-model=<m>.pnpm generate:session-content— Per-session Anthropic writing →src/data/session-content.json(blurb, contenders). Requiressession-facts.jsonpopulated. Flags:--no-batch,--anthropic-model=<m>.pnpm generate:session-scores— Per-session Anthropic scoring →src/data/session-scores.json(ratings + scorecard). Requiressession-content.jsonpopulated. Flags:--no-batch,--anthropic-model=<m>.pnpm check:anthropic-auth— Free model lookup that confirms the scripts can authenticate (local key/profile, or federation in GitHub Actions).pnpm refresh <sessionId>— Refresh grounding+writing+scoring for a single session with an optional--prompt "..."correction. Flags:--skip-grounding|writing|scoring.
Paid API calls authenticate through scripts/lib/anthropic-client.ts: locally the SDK finds ANTHROPIC_API_KEY in .env (or an ant auth login profile); in GitHub Actions it uses Workload Identity Federation with no stored key. Research stages (sport, venue, and session facts) use Claude's server-side web search tool ($10 per 1,000 searches plus tokens) and return results through a strict record tool — see scripts/lib/claude-research.ts. Session grounding, writing, and scoring use prompt caching and Messages Batches (50% token discount) by default — see scripts/lib/session-content.ts for the batching helpers. A batched grounding request whose search turn pauses can't be resumed, so it fails and stays due for the next run; rerun, or use --no-batch for stragglers.
Cost controls (see scripts/lib/freshness.ts and scripts/lib/usage.ts):
- Grounding re-checks send each session's stored brief; when Claude reports no material change, the stored facts and
generatedAtstay put and onlycheckedAtmoves. Briefs written before a session's current session/sport corrections (tracked bycorrectionsHash) are rewritten from scratch instead. - Writing and scoring store an input hash per session and skip sessions whose inputs are unchanged;
--forceoverrides. - Each session stores only the search results its facts and news cite (at most 12, checked against what the searches actually returned), not the whole batch's results.
- Every script prints a usage summary with an estimated cost.
- Reader-facing output containing a trademarked term is rejected in code and retried on the next run.
- Sport and venue facts are stable — don't put them in scheduled runs. A scheduled refresh is
generate:session-facts --stale-days=<n>, thengenerate:session-content,generate:session-scores, andpnpm format.
.github/workflows/data-refresh.yml runs that refresh monthly (and on demand via workflow_dispatch) and opens a chore(data) PR with the results and a usage summary. Setup is in CONTRIBUTING.md under "Scheduled data refresh".
Persistent corrections
Hand-edited correction files override AI output across regenerations. Three files mirror the three correction scopes:
src/data/session-corrections.json— keyed by session id; injected intogenerate:session-facts,generate:session-content,generate:session-scores, andrefresh.src/data/sport-corrections.json— keyed by sport name; injected intogenerate:sport-facts, plus per-sport prompts in writing/scoring.src/data/venue-corrections.json— keyed by venue name; injected intogenerate:venue-facts.
Shape: { "<key>": ["correction text", ...] }. Each value is an array so corrections stack. Edit the file, then re-run the relevant generate command (or pnpm refresh <id>) — corrections are feed-forward, no version bump.
For globally-wrong Paris 2024 medal data, fix src/data/paris-2024-medals.json directly and rerun generate:session-facts for affected sessions. The medal block is already authoritative in every prompt that references it.
Pre-PR checks
Before opening a pull request, run the CI-equivalent checks locally and fix any failures first: pnpm format:check, pnpm lint, pnpm typecheck, and pnpm test. For UI or rendering changes, also run pnpm build, then pnpm test:e2e and pnpm lighthouse: CI fails the PR if a page drops below its Lighthouse budget. Run them in parallel when possible. This avoids pushing commits that fail CI.
Deploying
Production deploys happen automatically when Release Please cuts a release. .github/workflows/release.yml runs on every push to main; when it creates a release (release PR merged), a follow-up deploy job in the same workflow builds with the Vercel CLI (vercel build with NITRO_PRESET=vercel) and ships a prebuilt production deployment to Vercel. Git-triggered Vercel deploys of main are disabled in vercel.json so only the release job promotes to production. Manual deploys are forbidden. Do not run vercel deploy (or vercel --prod), do not re-add a deploy script to package.json, and do not add a manual-trigger workflow. Shipping code means: merge feature PRs to main → let Release Please open its release PR → user merges that → CI deploys.
Vercel operations
Always ask the user before using any Vercel MCP tools or running vercel CLI commands that touch remote resources (pull, env, deploy, domains, etc.). Local-only builds (pnpm build, NITRO_PRESET=vercel pnpm build) are fine without asking.
Architecture
This is a TanStack Start (React 19) full-stack app with SSR, file-based routing, and Tailwind CSS v4.
Data
Session data lives in JSON files under src/data/, committed to the repo and bundled into the server function at build time:
sessions.json— hand-validated source data (id, sport, venue, date, etc.); no generated contentparis-2024-medals.json— Olympedia-scraped medal results; authoritative history, used as grounding anchorsport-facts.json— per-sport Claude web-search output (gamesContext, parisRecap), keyed by sportvenue-facts.json— per-venue Claude web-search output (capacity, yearBuilt, location, iconicMoments, spectatorExperience, changes2028), keyed by venue namesession-facts.json— per-session Claude web-search output (facts, related news, sources), keyed by session idsession-content.json— Anthropic prose (blurb, contenders), keyed by session idsession-scores.json— ratings + optional Scorecard (dimension scores with explanations), keyed by session idsession-corrections.json/sport-corrections.json/venue-corrections.json— hand-edited authoritative overrides injected into prompts at generation time (see Persistent corrections above)
Runtime reads happen in src/data/sessions.data.server.ts, which merges sessions + session-facts + session-content + session-scores on module load. Writer scripts use scripts/lib/content-store.ts to upsert the generated files; each stage can be regenerated independently (e.g. refresh news without rewriting descriptions). Regenerated files are committed to the repo — there's no separate deploy step for data.
Routing
Routes live in src/routes/ and are auto-generated into src/routeTree.gen.ts by the TanStack Router plugin. Do not edit routeTree.gen.ts manually.
__root.tsx— Root layout wrapping all pages (HTML document, Header, Footer, devtools)- Filename maps to path:
venues.tsx→/venues,index.tsx→/ - Routes use
createFileRoute()/createRootRoute() - Router config in
src/router.tsx: preloads on intent, scroll restoration enabled
Agent access
The session guide is also served to AI agents. All three read the same catalog through src/data/agent.data.server.ts, which uses readable field names (score, round, ISO date):
/mcp— remote MCP server (src/routes/mcp.ts→src/lib/mcp-server.ts). Streamable HTTP, stateless (a fresh server and transport per request, JSON responses), read-only, no auth, open CORS. Tools:search_sessions,get_session,list_sports,list_venues,get_venue./api/sessions.json— every session summary in one document./llms.txt— static file inpublic/pointing agents at the two above.
Path Aliases
@/* resolves to ./src/* (configured in tsconfig.json).
Styling
- Tailwind CSS v4 with
@tailwindcss/viteplugin - Custom CSS variables and theme system in
src/styles.css - Dark mode via
data-themeattribute +prefers-color-schemefallback - Fonts: system UI stack (body), Georgia (display headings); no web fonts are loaded
- Use existing CSS variables (
--lagoon,--sea-ink,--sand, etc.) for theme colors
Vite Plugins (order matters)
devtools → tailwindcss → tanstackStart → nitro → viteReact
The @/* path alias comes from tsconfig.json through Vite's built-in resolve.tsconfigPaths, not a plugin.
Nitro builds the server. It auto-detects Vercel when VERCEL/NITRO_PRESET=vercel is set and emits .vercel/output; otherwise it emits a Node server in .output. Static-asset cache headers live in the nitro({ routeRules }) config in vite.config.ts.
/ is deliberately excluded from prerendering (it's SSR'd per URL and CDN-cached) because a static file would be served for every query string and break hydration on /?session=… deep links. Vercel Web Analytics and Speed Insights mount only when VITE_VERCEL_INSIGHTS=true at build time, which the release deploy job sets.
Git
- Never include Co-Authored-By or other attribution lines in commits or pull requests
- Use Conventional Commits:
type(scope): description(lowercase, imperative mood)- Types:
feat,fix,refactor,chore,docs,style,test,perf,ci,build - Scope is optional but encouraged (e.g.,
feat(routes): add dashboard page) - Breaking changes: add
!after type/scope (e.g.,feat!: remove legacy auth)
- Types:
- Keep commits atomic — one logical change per commit
- Write concise subject lines (under 72 chars), use body for "why" when needed
- PR titles follow the same conventional commit format (this becomes the squash commit message)
- PR descriptions should include a summary and test plan
- Squash merge all PRs — the PR title is the final commit message, so get it right
- Keep
mainhistory linear: prefer rebasing topic branches ontomaininstead of merge commits - Releases are managed by Release Please — it reads conventional commits to auto-generate changelogs and version bumps
feat→ minor version bumpfix→ patch version bumpfeat!/fix!/ breaking change footer → major version bump
Worktrees
- Store repo worktrees under
.worktrees/at the repository root when creating additional checkouts for this project
Agent skills
Project skills come from skills.sh and are tracked in skills-lock.json. The files live in .agents/skills/, and .claude/skills/ holds symlinks to them. Update them with pnpm dlx skills update --project -y, then review the diff before committing.
web-design-guidelinesis locally modified. Upstream tells the agent to fetch its rules fromraw.githubusercontent.com/vercel-labs/web-interface-guidelines/main/command.mdon every run. We vendor that file asreferences/guidelines.mdinstead, so the rules only change through a reviewed commit. Updating the skill overwritesSKILL.mdwith the fetching version. After an update, pointSKILL.mdback atreferences/guidelines.md. To refresh the rules themselves, download the upstreamcommand.md, review it, and replacereferences/guidelines.md. Then update the commit SHA in theSKILL.mdcomment.- TanStack skills ship inside the installed
@tanstack/*packages (node_modules/@tanstack/<pkg>/skills/) and update with those packages..agents/skills/tanstack-*are symlinks intonode_modules, and.claude/skills/tanstack-*link to those, so they resolve only afterpnpm install. They are not tracked inskills-lock.json, soskills updateleaves them alone. When you bump a TanStack package, review itsskills/diff, and add or remove symlinks if the package's skill list changed. We don't use@tanstack/intent installorskills experimental_sync. Sync only findsskills/<name>/SKILL.mdand would miss TanStack's nested sub-skills.
Key Conventions
- Strict TypeScript: no unused locals/parameters
- Components in
src/components/, routes insrc/routes/ - Server functions available via
createServerFn()from@tanstack/react-start - Navigation uses
<Link>from@tanstack/react-router
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

