vibedgames: Instructions file for Claude Code

CLAUDE.md

vibedgames CLAUDE.md is an instructions file for Claude Code from kyh/vibedgames. It costs 6,303 tokens per session, scanned A, original, MIT.

Project instructions for coding agents working on Vibedgames, a platform for deploying, hosting, and adding multiplayer features to browser games.

In plain words
What is it for?
Following the project workflow, setting up the development environment, checking the application, using the vg deployment command, and deciding which results need human review.
Why use it?
They give an agent the product context, design decisions, required commands, test checks, and conventions needed to work in the repository correctly.

Instructions file for Claude Code

Written for Claude Code: ${CLAUDE_SKILL_DIR} variable. Also seen: reads .claude/ paths; mentions .claude-plugin; positional $N argument.

This is kyh/vibedgames's own configuration. It tells Claude Code how to work on vibedgames itself, so it is not a mod to install elsewhere. Copy it as a starting point and replace the rules that are about this project. Everything vibedgames configures →

Reuse

Borrowing it

Nothing to install: this file belongs to kyh/vibedgames. Take a copy, put it at the same path in your own repository, and replace the rules that are about this project with yours.

Copy the file
curl -O https://raw.githubusercontent.com/kyh/vibedgames/main/CLAUDE.md
Clone the repo
git clone --depth 1 https://github.com/kyh/vibedgames

Made for: Claude Code.

Wrote this? Show the measurements

A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.

agentmods badge for vibedgames CLAUDE.md

README.md
[![agentmods](https://agentmods.dev/badge/instructions/kyh/vibedgames/claude-md/github.svg)](https://agentmods.dev/instructions/kyh/vibedgames/claude-md)
Your own site
<a href="https://agentmods.dev/instructions/kyh/vibedgames/claude-md"><img src="https://agentmods.dev/badge/instructions/kyh/vibedgames/claude-md/github.svg" alt="Measured on agentmods" height="20"></a>

Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.

agentmods 80×15 button for vibedgames CLAUDE.md

Your own site · 80×15
<a href="https://agentmods.dev/instructions/kyh/vibedgames/claude-md"><img src="https://agentmods.dev/badge/instructions/kyh/vibedgames/claude-md.svg" alt="Reviewed on agentmods" width="80" height="20"></a>
Per session 6,303 This file is loaded in full into every session.
When invoked 6,303 The same file — it is already loaded in full.
Security scan A 0 findings. A grade says what 26 rules found in the file — not that it is safe.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5.1 $0.06303 $0.06303
Opus 5.5 $0.02521 $0.02521
Sonnet 5.5 $0.01261 $0.01261
Haiku 4.5 $0.00630 $0.00630

Measured 13d ago against content hash 42e2be799b9c, method: parsed. Prices are Anthropic first-party input rates as of 2026-10-07, from the pricing page.

Security

Grade A, and why

vibedgames CLAUDE.md scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 13d ago.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Nothing flagged

None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.

CLAUDE.md · 142 lines

How it starts

The opening of the file, as written. The whole thing — 142 lines — stays where its author put it; the contents beside it link to each section on GitHub.

Agent Instructions

Agent-driven development

AGENTS.md is the runnable guide — quickstart, env files, seeded logins, headless auth, the pnpm verify gate, an agent-browser recipe, and which surfaces are checkable at runtime versus which need a human. Reach for it when you need to run, sign in, or verify something; a small edit does not need it. This file carries the product context, architectural decisions and conventions that sit on top of it.

  • pnpm lint is a clean gate. oxlint.config.ts extends the ultracite presets (core, react, anti-slop); every rule is an error. Fix the code, don't add config overrides; a // oxlint-disable-next-line rule -- why needs a stated reason.

What This Is

vibedgames — infrastructure platform for deploying, hosting, and adding multiplayer to browser games. Users build games locally, deploy via CLI (vg deploy), and their game is served at {slug}.vibedgames.com. The web app is the central hub for discovering and playing games.

The primary user of the vg CLI is a coding agent, not a human. A human prompts their agent ("build me a bomberman game"), and the agent uses vg + the bundled skills to scaffold, generate assets, add multiplayer, and deploy. Optimise CLI UX accordingly: machine-readable output (--json), self-describing errors, deterministic exit codes, skills that document the exact commands the agent should run. Friction that a human would tolerate ("now open this URL...") blocks an agent.

Product & Business Context

  • The bet (why us): Seed your coding agent with the abilities of a full game studio. The wedge isn't "another hosting platform" — it's that an agent, armed with vg + the bundled skills, can do everything a studio does (scaffold, generate art/audio, add multiplayer, ship) without the human assembling an engine, art pipeline, or server stack. The differentiator is being agent-native and end-to-end.

Key Architectural Decisions

  • Games are untrusted user code. Session cookies are scoped to apex domain only (vibedgames.com). Games on {slug}.vibedgames.com subdomains cannot access auth cookies. CSP frame-ancestors restricts embedding. Never weaken these boundaries.
  • Single active deployment per game. No version history, no rollback. New deploy replaces old. R2 keys are games/{gameId}/{deploymentId}/{path} — immutable per deployment, enabling long cache (1yr) for assets and short cache (60s) for index.html.
  • CLI auth uses device-code flow. CLI shows 6-char code → user confirms in browser → CLI polls for token. Not OAuth.
  • better-auth 1.7 scopes account identity by (issuer, accountId). account.issuer is NOT NULL with a unique (issuer, accountId) index (account_issuer_account_id_uidx in packages/db/src/drizzle-schema-auth.ts). Credential accounts carry local:credential with accountId = the owning user's id; an OAuth provider with no real issuer carries local:oauth:<providerId>. Keep better-auth, @better-auth/api-key and @better-auth/expo on the same minor. Nothing in pnpm verify touches D1, so a schema/column mismatch surfaces only as a failed sign-in against the live database — any further change to these tables needs a matching db:push plus a backfill of existing rows.
  • Never regenerate the auth schema with @better-auth/cli. It is stuck at 1.4.21: generate:auth-schema emits no issuer, and it strips the hand-curated index(...) calls and the hand-added rate_limit table. Edit drizzle-schema-auth.ts by hand.
  • Declare uniques as named unique indexes, never .unique(), and keep the composite PK named deployment_file_pk. Production D1 was pushed by drizzle-kit 0.31, which spelled every .unique() as a CREATE UNIQUE INDEX <table>_<column>_unique and left the deployment_file PK unnamed (introspected as deployment_file_pk). drizzle-kit 1.0 spells .unique() as an inline UNIQUE constraint and names PKs, and treats either difference as a table recreate: PRAGMA foreign_keys=OFF; CREATE __new; INSERT; DROP; RENAME. D1 ignores that PRAGMA, so the DROP cascades through every ON DELETE CASCADE child (account, session, game, ...). With uniqueIndex("<table>_<column>_unique") in the table's extra config and that PK name, drizzle-kit push --explain against a 0.31-shaped database reports no changes. drizzle-kit push applies a recreate without asking, so db:push-remote prints the --explain plan first and applies only on a typed y — refuse a plan that recreates a table.
  • Every PR gets Cloudflare Worker Previews, Vercel-style, driven by Actions rather than Workers Builds. .github/workflows/preview.yml runs on workflow_run after CI is green (same-repo branches only, since that trigger holds secrets), deploys cf previews deploy pr-<n> for web and party when the PR touches them, keeps one sticky status comment plus a GitHub deployment per Worker (.github/scripts/worker-preview.mjs), and deletes the previews when the PR closes. Previews inherit no bindings: each cloudflare.config.ts binds, when isPreview, vibedgames-preview (D1) and vibedgames-games-preview (R2) by name, which the workflow creates on first use. PR code never reaches prod D1 or the prod bucket. The games Worker has no preview because it routes by {slug}.vibedgames.com. Preview secrets live in Cloudflare's preview base config (wrangler preview base-config secret put --worker-name <worker>; cf has no preview secret command yet), not in GitHub.
  • Multiplayer is host-authoritative, last-write-wins. No conflict resolution. First player becomes host; if host leaves, reassigns. Good for turn-based and host-controlled games. Real-time feel comes from the SDK's netcode helpers, never a hand-rolled throttle or lerp. FixedRate drives send clocks. Interpolator renders remotes from sender-stamped updates. A guest's own body is predicted locally and corrected by Reconciler. Intents go to the host only, and the host handles its own locally. The party server relays a host's state_patch (path ops: the leaves that changed) to everyone but the host. Beyond relaying, the server runs only game-agnostic room services: server time (serverNow(), the timebase every stamp uses), first-come claims, ordered input ticks for lockstep/rollback, radius interest filtering, player-state limits, persistence of shared state and claims, host-set room locks and meta, and lobbies (VgLobby) that list the rooms naming them and quick-match players into the fullest open one. No back-compat in this protocol: SDK and server ship together, and a game that changes its own wire format versions its room ids.
  • Plugins ship from a mirror repo. kyh/vibedgames-plugins holds only plugins/, .claude-plugin/ and LICENSE, synced by .github/workflows/sync-plugins.yml (deploy key in the PLUGINS_MIRROR_DEPLOY_KEY secret). vg init and the plugin directory listing point at the mirror because both download a whole repo archive and this one is ~140 MiB compressed. Edit skills here; anything committed straight to the mirror is overwritten on the next sync.
  • vg publishes as one esbuild bundle with no dependencies. apps/cli/scripts/build.mjs inlines every dependency (their licences go to dist/THIRD_PARTY_NOTICES.txt) and splits each command into a chunk loaded when it runs, so a cold npx vibedgames is one small download that no transitive package can print a deprecation warning into. A runtime dependency of the CLI goes in devDependencies. Source (src/lib/) and chunks (dist/) sit at different depths, so a file the package ships is found from PACKAGE_ROOT (src/lib/package-root.ts), never spelled as ../... Every request carries x-vg-cli: <version> (@repo/contract/cli). Builds before it (≤0.6.3, oRPC 2.0.0-beta.31) refuse an error body without oRPC's old inferable field, so apps/web's RPC handler adds it back for Node requests without the header; delete that once those installs are gone.
  • Deploy on push to main. GitHub Actions detects changed apps and deploys via cf deploy --prebuilt. Never run cf deploy locally. Changed example games (games/*, plus anything downstream of a changed package) deploy the same way through vg deploy, authenticated by the VG_TOKEN repo secret — an API key from Settings.
  • Signup is open; credit is bought or redeemed. New accounts start at $0. Credit arrives three ways, all as ledger entries: a Stripe Checkout purchase (credits.checkout returns a hosted URL; only the signed checkout.session.completed/async_payment_succeeded webhook at /api/stripe/webhook credits it, keyed purchase:{checkoutSessionId}, $1 paid = $1 credit), a credit code redeemed in Settings or with vg credits redeem (code:{codeId}:{userId}, once per account per code, within the code's max_uses), or an admin grant. Credit codes live in the invite_code table — it predates launch, when the same codes gated signup, and renaming it would be a recreate. Accounts that signed up with an invite before launch (user.invited_by_code set) still get the old $20 signup:{userId} grant, lazily on first credit access; nobody else does. Either of STRIPE_SECRET_KEY / STRIPE_WEBHOOK_SECRET unset turns purchases off, nothing else: credits.me reports purchasesEnabled: false, Settings shows only the code button, checkout answers 412 and the insufficient_credits message offers codes only. Neither is required to deploy: apps/web/cloudflare.config.ts leaves them out of production builds, and a key set later with cf workers secrets update binds anyway.
  • Per-user generation credits (micro-USD ledger). credit_entry is an append-only ledger of integer micro-USD deltas — balance is SUM(delta_micro), there is no cached balance column, and idempotency lives in deterministic entry ids (signup:{userId}, code:{codeId}:{userId}, purchase:{sessionId}, hold:{requestId}, ...). generation tracks the per-request lifecycle: generate.forward blocks a non-admin's queue submits at balance ≤ 0 (insufficient_credits) or to an endpoint GET /v1/models/pricing lists no price for (unknown_endpoint; an admin's are metered but never blocked), debits an estimated hold at submit (provider historical per-call estimate, clamped $0.01–$5), settles to actual cost from the x-fal-billable-units result-fetch header and the endpoint's unit price, and refunds holds when a status poll reports FAILED/CANCELLED. Pricing that cannot answer (network error, 5xx, 429) never blocks a submit: it holds the estimate, else a flat $0.10, and settles at the hold; only a priced answer is cached (packages/service/src/credits/endpoint-pricing.ts). The ledger reads a queue hop's endpoint and request id off path as sent, while fal percent-decodes the path and finds its application whatever the case, so the contract holds a queue path to lowercase letters, digits and -._~/, and every queue POST bills as a submit whatever its path: otherwise the ledger prices or settles a hop other than the one fal runs. Only generation is metered; deploys/hosting are free. Never bypass the gate or write ledger rows outside packages/service/src/credits/.
  • Playtest decisions go through TypeSafe Jev (internal only). vg playtest run lets a model play a game. The loop runs inside the game's page (apps/cli/src/lib/playtest/agent.ts, injected as source): several times a second it reads __GAME_DIAGNOSTICS__, POSTs to /api/playtest/decide and holds the answer as real input, with an optional per-frame reflex from the game's window.__GAME_PLAYTEST__ manifest for fast games. Every decision also asks a score question — the model's own 0–1 read of progress towards the goal — which the report carries as decisions.progress; it is advisory, never a gate. That endpoint is cross-origin and cookie-blind by design — the page is untrusted user code — and honours only a 15-minute HMAC token minted by playtest.session for that run (packages/service/src/playtest/session-token.ts, signed with BETTER_AUTH_SECRET). The server holds TYPESAFE_API_KEY and forwards exactly one System One request shape — state plus typed questions — so neither the token nor the key can be used for anything else. Not metered: a run costs a fraction of a cent, and the per-call caps (64 KB state, 32 questions) bound it. games/pong is the reference manifest, reflex included. The globals are the contract; @vibedgames/playtest (packages/playtest) only types and publishes them — a game may set them by hand, and the CLI never depends on the package.
  • Media goes through fal (internal only). vg generate exposes run, models, schema, upload, pricing, status, docs. The server holds FAL_API_KEY; the CLI proxies through the API. fal is a gateway to OpenAI, Veo, Sora, Kling, Flux, ElevenLabs, Retro Diffusion, etc. — there's no per-provider routing. End-user-facing surfaces (the vg generate CLI help and the skills under plugins/vibedgames/skills/) must not name fal as a brand. To the user this is just a CLI that generates assets; "fal" stays an implementation detail. The one exception is model endpoint IDs: they're passed through verbatim (e.g. fal-ai/flux/dev, bytedance/seedance-2.0/...), exactly as the upstream API expects — the CLI does no id rewriting. Keep branding out of prose and help text, but never alter an endpoint ID.
  • /mcp is the platform as MCP tools, bearer-only. One tool per vg command that reaches the server, named as the agent thinks of it (me, credits, deployments, fork, generate, skills, …), in apps/web/src/lib/mcp-tools.ts; mcp.ts serves them with @orpc/mcp's McpRegistrar on a fresh McpServer per request (stateless Streamable HTTP). Most tools are appRouter's own procedures; the generate_* family is vg generate's subcommands over generate.forward, reached through oRPC's call() so the session check, input rules and credit ledger run exactly as for the CLI; the dedicated asset tools (generate_image, generate_video, generate_3d, …) are the same path on the defaults MEDIA_MODELS names, which mcp.test.ts holds to the model-catalog skill. deployments_upload is deploy.upload, which writes inline files through the R2 binding into a staged deployment beside the live one and, on publish, points the game at it before removing every other deployment of the game: unlike deploy.create, nothing goes dark mid-upload. A url file is fetched by the Worker only from the media hosts isMediaUrl (@repo/contract/generate/media-hosts, shared with the CLI's downloads) names, so it is no general fetch proxy; source: true tars the published files in the Worker (source-archive.ts) into the same sources/ archive vg deploy --source uploads, so an uploaded game forks like any other. The mcp.tool meta lives in apps/web, never in @repo/contract: the CLI bundles the contract and @orpc/mcp would drag the MCP SDK in. The cookie is dropped before the context is built, so only a vg_… key or session bearer signs a call: a game page is same-site with the apex, and SameSite=Lax would otherwise carry the session into a tool call. Not tools: what only touches the caller's machine (init, login, new, update, …) and playtest run, which drives a local browser. mcp.test.ts holds the tool list, the annotations, the cookie drop and that no prose names fal.

Read the full file on GitHub · 142 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. 13d ago Changed · +92 tokens per session 42e2be799b9c
  2. 14d ago Changed · +1 lines · +424 tokens per session 08149e77bec6
  3. 28d ago Changed · +1 lines · +337 tokens per session af3b24a49815
  4. 29d ago Changed · +164 tokens per session 784ddd5635fd
  5. 1mo ago Changed · +1 lines · +234 tokens per session a9ebe6a15259
  6. 1mo ago Changed · +6 tokens per session d91a42196643
  7. 1mo ago Changed · +167 tokens per session 952f21b2fd23
  8. 1mo ago Changed · +5 lines · +561 tokens per session 559ca395e2fa
  9. 1mo ago Changed · +1 lines · +234 tokens per session 437dc6352368
  10. 1mo ago First seen · 133 lines · 4,084 tokens per session scan A 4a375c1fb29c

Subscribe to this mod's changes

vibedgames CLAUDE.md is an instructions file published in the GitHub repository kyh/vibedgames (61 stars, last pushed 2d ago), licensed MIT. It adds 6,303 tokens to every session, about $0.0252 per session on Opus 5.5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-30.

Related

vibedgames CLAUDE.md compared with instructions from other repositories

vibedgames CLAUDE.md next to 6 instructions from other repositories
ModTypeStarsLast pushLicenceScanTokensWorks with
vibedgames CLAUDE.mdkyh/vibedgamesInstructions file612d agoMITA6,303Claude Code
vscode buildNext.instructions.mdmicrosoft/vscodeInstructions file195kyesterdayMITA9,719GitHub Copilot
next.js AGENTS.mdvercel/next.jsInstructions file143kyesterdayMITA7,461Codex, OpenCode
langchain AGENTS.mdlangchain-ai/langchainInstructions file149kyesterdayMITA4,680Codex, OpenCode
vscode oss-third-party-notices.instructions.mdmicrosoft/vscodeInstructions file195kyesterdayMITA5,516GitHub Copilot
vscode copilot-instructions.mdmicrosoft/vscodeInstructions file195kyesterdayMITA3,093GitHub Copilot
deepseek-harness AGENTS.mddeepseek-ai/deepseek-harnessInstructions file274k2d agoMITA4,313Codex, OpenCode