Oyununuz için AGENTS.md
AGENTS.md, yapay zekâ kodlama ajanlarının (Claude Code, Cursor, Codex ve benzerleri) deponuzun kökünde otomatik okuduğu kural dosyasıdır. Open Play’i oyununuza bağlarken ajanların en sık yaptığı hatalar şunlardır: bir endpoint’i ya da header’ı tahmin etmek, sunucu anahtarını istemciye koymak, CSRF ve oturum kurallarını atlamak, eklenti şemasını sabitlememek, domain’i erken silmek ve eski önbellekteki JavaScript’i canlıda bırakmak. Bu sayfadaki şablon bu hataları önleyen kuralları tek dosyada toplar. Kurallar gerçek oyun entegrasyonlarında (ArenaRace ve LanternTide örnek oyunları) yaşanan sorunlardan çıkarılmıştır ve her kural ilgili belge sayfasına bağlanır.
Nasıl kullanılır
- Şablonu indirin:
https://open-play.b4klabs.dev/docs/AGENTS.md(ya da aşağıdaki bloğu kopyalayın) ve oyun deponuzun köküneAGENTS.mdolarak koyun. Zaten birAGENTS.mddosyanız varsa şablonu “Open Play entegrasyonu” başlığı altına ekleyin. - “Project facts” bölümündeki
<YOUR_DEV_ENV_ID>,<YOUR_PROD_ENV_ID>,<OPEN_PLAY_BASE_URL>,<DEV_GAME_ORIGIN>,<PROD_GAME_ORIGIN>ve<SDK_VERSION>yer tutucularını kendi değerlerinizle değiştirin. Ortam kimlikleri gizli değildir; anahtarları ve sırları dosyaya yazmayın. - Ajanınıza Open Play MCP sunucusunu ekleyin (Yapay zekâ araçlarıyla kullanım):
claude mcp add --transport http open-play https://open-play.b4klabs.dev/mcp. Şablon ajana öncesearch_docs,read_doc,search_sdkveget_sdk_symbolaraçlarını kullanmasını söyler; böylece ajan davranışı hafızasından değil güncel belgeden alır. - Oyununuzda kullanmadığınız bölümleri silin (örneğin eklenti kullanmıyorsanız 6. bölüm). Kendi kurallarınızı (kod stili, test komutları, dal düzeni) şablonun üstüne ya da altına ekleyin.
Şablonun kapsamı
| Bölüm | Neyi önler |
|---|---|
| MCP önce | Tahminle yazılmış endpoint, header ve alan adları |
| Anahtarlar ve ortamlar | Sunucu anahtarının istemciye sızması, dev ile prod karışması |
| Giriş ve oturum | Misafir akışı, Google popup + yönlendirme yedeği, yönlendirme tabanı (/auth/callback), CSRF yarışı, tek aktif oturum, hesap silme |
| Domain ve tarayıcı | Kayıtsız origin, canlı domain’i erken silmek, proxy’nin header kaybı |
| Oyuncu verisi | Bilinmeyen kaydetme formatı için ayrı sunucu, If-Match olmadan yazma |
| Eklentiler | Şema uyuşmazlığı, yeni anahtarla tekrar gönderilen komut, sürüm yükseltmede kapalı izin |
| Gerçek zamanlı | Bilet yeniden kullanımı, tekrar oynatılan girdi, gecikmeli girdi akışı |
| Önbellek ve dağıtım | CDN’in no-cache başlığını ezip eski JavaScript’i tutması |
| Hatalar ve sınırlar | Hata metnini ayrıştırmak, paylaşılan IP kovası |
| Test ve Yap / Yapma | Bitti demeden önce kontrol listesi |
Şablonun dili İngilizcedir: yapay zekâ araçları ve belge sitesinin MCP dizini İngilizce metinle en iyi çalışır. Şablon ayrıca https://open-play.b4klabs.dev/docs/llms.txt dizininde “Optional” bölümünde listelenir.
Not
Şablon bir kural dosyasıdır, Open Play’in garantisi değildir. Davranışın tek kaynağı belge sayfalarıdır; şablon ile bir sayfa ayrışırsa sayfa doğrudur. Şablonu gerçek bir ajan oturumunda deneyip kendi oyununuza göre sıkılaştırmanızı öneririz.
Şablonun tamamı
# AGENTS.md — integrating this game with Open Play
> Drop this file in the root of your game repository. Replace every `<PLACEHOLDER>` and delete rules that do not apply.
> Source and updates: https://open-play.b4klabs.dev/docs/AGENTS.md
This game uses **Open Play**, a game backend platform: player identity and sessions, player data (cloud save), characters, economy, store, rewards, social features, leaderboards, notifications, plugins and realtime connections. The game talks to Open Play over HTTP and WebSocket, through the TypeScript SDK (`@ferdiunal/open-play-ts`) or the Unity SDK. The game does **not** run its own account or save server for anything Open Play provides.
Docs root: https://open-play.b4klabs.dev/docs/en/ — every rule below links to its page.
## 0. Project facts (fill in)
- Environment ids (the `x-crx-env` value): dev `<YOUR_DEV_ENV_ID>`, prod `<YOUR_PROD_ENV_ID>`. One environment per stage; data is never shared between them.
- Open Play base URL: `<OPEN_PLAY_BASE_URL>` (the API address the browser calls).
- Game origins registered per environment: `<DEV_GAME_ORIGIN>`, `<PROD_GAME_ORIGIN>`.
- SDK version (exact, no `^`, no `latest`): `<SDK_VERSION>`.
## 1. Use the Open Play MCP server first
Before you write any call to Open Play, **look it up**. Never guess an endpoint, header, field or error code.
```bash
claude mcp add --transport http open-play https://open-play.b4klabs.dev/mcp
```
Cursor (`.cursor/mcp.json`) and VS Code (`.vscode/mcp.json`, key `servers`): `{"mcpServers":{"open-play":{"url":"https://open-play.b4klabs.dev/mcp"}}}`.
- `search_docs` then `read_doc` (for example `auth/oauth`) for behavior and HTTP contracts.
- `search_sdk` then `get_sdk_symbol` (for example `PlayerSession`, `sdk: "typescript"` or `"unity"`) for exact SDK signatures.
- The server is read-only and public; it never needs or sees a key. If the docs and your memory disagree, the docs win.
- No MCP available: read https://open-play.b4klabs.dev/docs/llms.txt (index) or `llms-full.txt` (everything).
Docs: [Using AI tools (MCP)](https://open-play.b4klabs.dev/docs/en/getting-started/ai-tools.html).
## 2. Keys and environments
- **Client** code (browser, WebGL, mobile) knows only the environment id and the player session. It carries **no secret**.
- A **server key** (`crx_live_<prefix>_<secret>`) lives only on your own server or backend-for-frontend (BFF): in its secret store, never in the client bundle, the repository, logs, or `.env` files that are committed. Use a separate key per environment and service, with an expiry.
- A client key is not a server key; calling a server endpoint with it is rejected. Player operations use the player session, not a key.
- Never point a dev build at the prod environment or the reverse. Read the environment id from per-stage configuration.
- Do not hard-code or print secrets, tokens, cookies or `x-csrf-token` values in code, tests, logs or analytics.
Docs: [Security](https://open-play.b4klabs.dev/docs/en/operations/security.html), [API keys](https://open-play.b4klabs.dev/docs/en/panel/game-settings-api-keys.html), [Production checklist](https://open-play.b4klabs.dev/docs/en/operations/production-checklist.html).
## 3. Sign-in and sessions
- **Guest first.** Open a guest session on first launch so the player plays at once; offer Google (or email) later and **link** it to the same player. Linking a guest upgrades the same player id; progress is kept.
- **Google OAuth:** try a popup window and fall back to a full-page redirect when the popup is blocked. Open the popup synchronously inside the click handler, before any `await`. Let the callback page hand the result back (for example through `BroadcastChannel`) and close itself.
- The server builds the Google `redirect_uri` from the configured **redirect base + `/google`**. The base must end at `/auth/callback` (not `/google`); the redirect URI registered with Google must be exactly `<base>/google`, and that path must be a page of your game that finishes the sign-in.
- The OAuth `code` and `state` are single-use: finish exactly once, then remove them from the address bar (`history.replaceState`). Use the SDK helpers; they bind `state` to the browser tab.
- A cookie session sends `x-crx-env` on every call and a CSRF token on every state-changing request. The token is **single-use and rotates**: never send two mutations at once with the same token, and keep the new token from each response. The SDKs serialize this for you; share the token between tabs with the SDK `csrf.channel` option. Retry a CSRF `403` once with a fresh token.
- Session lifetime is 30 days sliding, 180 days absolute. On `401` refresh or sign in again; do not loop.
- If the environment allows a **single active session**, a newer sign-in revokes the older one. Handle `reauthRequired` with a clear "signed in on another device" screen and a sign-in button, not a silent retry.
- Show the sign-in methods you actually enabled; hide the rest. Do not use SDK methods the docs mark as unsupported.
- **Account deletion** is a store requirement (Apple, Google Play): provide an in-game "Delete my account" action (`POST /v1/auth/account/delete`, `confirm: "delete_my_account"`). A linked account must have signed in within the last 10 minutes (`recent_sign_in_required`): ask the player to sign in again, then repeat.
- Verify identity on your own game server with the access JWT and the JWKS, never by trusting a client-sent player id.
Docs: [Auth overview](https://open-play.b4klabs.dev/docs/en/auth/overview.html), [Guest](https://open-play.b4klabs.dev/docs/en/auth/guest.html), [Google sign-in](https://open-play.b4klabs.dev/docs/en/auth/oauth.html), [Sessions and CSRF](https://open-play.b4klabs.dev/docs/en/auth/sessions-and-csrf.html), [Account linking](https://open-play.b4klabs.dev/docs/en/auth/account-linking.html), [Account deletion](https://open-play.b4klabs.dev/docs/en/auth/account-deletion.html), [Server-side verification](https://open-play.b4klabs.dev/docs/en/auth/server-verification.html).
## 4. Domains and calling from the browser
- Register **every origin your game runs on** in each environment's domain list (Game settings, Environments and domains): one full domain per line, no wildcards, no ports, at most 10, and a domain belongs to one environment only. An unregistered origin gets `403` on writes.
- Call Open Play either directly (your game domain is in the list; the server sends CORS headers with credentials) or through a same-origin reverse proxy that forwards `Cookie`, `Origin`, `x-crx-env`, `x-csrf-token`, `Idempotency-Key`, `If-Match` and the WebSocket upgrade, and that forwards the real client IP.
- **Moving to a new domain:** add the new domain and the new OAuth redirect first, test it, and only then retire the old one. **Removing a domain from an environment locks that live host out immediately.** Guest identities are per-origin: a new domain starts new guests.
- Send `Origin` only as the browser sets it. Never fake it in game code.
Docs: [Architecture and hosting](https://open-play.b4klabs.dev/docs/en/getting-started/architecture-and-hosting.html), [Environments and domains](https://open-play.b4klabs.dev/docs/en/panel/game-settings-environments.html).
## 5. Player data (cloud save)
- Use the generic per-player key-value store; **do not build a game-specific save server**. The value is an opaque JSON object the server never interprets; your game owns the format and its version field.
- Limits: key `^[a-z0-9][a-z0-9._-]{0,63}$`, at most 16 keys per player, 64 KiB per value, 60 writes per minute per player. Store large integers as strings.
- **There is no blind write.** Every `PUT` sends exactly one of `If-None-Match: *` (create) or `If-Match: "<version>"` (update). On `409 version_conflict` read the remote record, merge it with your own rule, retry. `428` means a precondition header is missing.
- Batch saves (on level end, on pause, on a timer), not every frame. Keep a local copy and reconcile on sign-in; a guest-to-Google link keeps the same player.
- Never write personal data you do not need. Player data is erased with the account.
Docs: [Player data](https://open-play.b4klabs.dev/docs/en/guides/player-data.html), [Idempotency and concurrency](https://open-play.b4klabs.dev/docs/en/reference/idempotency-and-concurrency.html).
## 6. Plugins (game-specific server logic)
- Call plugins only through **generated bindings**, never hand-written DTOs or copied field names. Get the schema document from `GET /v1/plugins/<PLUGIN_ID>/schema` and generate bindings from it.
- **Pin** `pluginId`, `schemaSha256`, `protocolVersion`, `codecProfile` and the plugin version in your release manifest. A mismatch must **fail closed**: show an "update the game" screen, never talk to the server with the wrong fields. After every server update compare the live digest with the pin (at startup or in CI).
- Every command carries an `Idempotency-Key`, generated **once** per logical action and reused on retries. If the outcome is uncertain (timeout, drop), resend with the **same key and body** or ask the result query; never generate a new key for the same action.
- Retry only when it is safe: idempotent calls on network errors, `429`, `503`, with exponential backoff and jitter, and honor `Retry-After`. Never retry business rejections (`422`).
- `int64` values travel as decimal strings. Send `If-Match` / `expectedVersion` when writing a shared resource; on `409` re-read first.
- If a plugin call suddenly returns `403`, check that the plugin is **enabled for that environment** and that the enabled version matches the server version. A server version bump needs its grant switched too.
Docs: [Plugins overview](https://open-play.b4klabs.dev/docs/en/plugins/overview.html), [Bindings and pinning](https://open-play.b4klabs.dev/docs/en/plugins/bindings.html), [Calling plugins](https://open-play.b4klabs.dev/docs/en/plugins/calling-plugins.html).
## 7. Realtime
- Use the SDK realtime client; if you implement the protocol yourself follow it exactly (single-use ticket, `Origin`, subprotocol).
- Ask for a **new ticket on every connection**. On a drop reconnect with exponential backoff, `Join` again with the last cursor (durable streams) or without one (ephemeral state), and on `ResyncRequired` drop the cursor and join fresh.
- Unacknowledged inputs are **not replayed**; continue from the latest snapshot. Pipeline inputs inside the SDK window (default 4 in flight); one input per round trip makes fast games feel laggy on real networks.
- Keep the frame rate below 40 per second; at most 4 sockets per player. Handle idle close (`4100`) with a "Continue" screen. An open socket does not keep the session alive.
- Notification and chat sockets cannot be opened straight from a browser; use inbox polling or REST.
Docs: [Realtime overview](https://open-play.b4klabs.dev/docs/en/realtime/overview.html), [Protocol](https://open-play.b4klabs.dev/docs/en/realtime/protocol.html), [Reconnect and limits](https://open-play.b4klabs.dev/docs/en/realtime/reconnect-and-limits.html).
## 8. Caching and deploys
- Serve your game's JavaScript modules and config (including the file that holds the environment id) with `Cache-Control: no-cache`, or content-hash the filenames. A stale config file after a deploy silently runs the old integration.
- If a CDN sits in front, set it to **respect existing headers** for HTML, JS and CSS. A CDN default browser TTL can override your `no-cache` and keep old code for hours.
- Never put a CDN cache in front of API responses that carry a cookie or `Authorization`.
- Deploy order when Open Play changes a plugin: new server and grant, then client with regenerated bindings. Pin the SDK version exactly and upgrade from the changelog.
Docs: [Production checklist](https://open-play.b4klabs.dev/docs/en/operations/production-checklist.html), [Versioning](https://open-play.b4klabs.dev/docs/en/reference/versioning.html).
## 9. Errors and rate limits
- Core endpoints return **plain-text** errors; plugin endpoints return a JSON envelope (`code`, `message`, `retryable`, `requestId`). Decide by status code and JSON `code`, **never by parsing message text**. Log `requestId` / `x-request-id`.
- There is no general per-key quota, but identity endpoints are limited per client IP (for example 30 guest sign-ins per minute). Behind a proxy or a shared network (NAT, a hosting platform's shared egress) many players share one IP: forward the real client IP.
- Back off on `429`, `503` and network errors; wait `Retry-After` when present. Never loop on `401`, `403` or `422`.
Docs: [Errors](https://open-play.b4klabs.dev/docs/en/reference/errors.html), [Rate limits](https://open-play.b4klabs.dev/docs/en/reference/rate-limits.html).
## 10. Testing checklist (before you call it done)
1. Fresh browser profile: guest sign-in, play, reload, same player and progress.
2. Guest upgraded to Google keeps progress; a second browser signs in to the same account and loads the save.
3. Two tabs open: no CSRF `403` storm; sign-out in one tab is handled in the other.
4. Same command sent twice with the same `Idempotency-Key` gives one effect.
5. Two devices write the same player-data key: the `409` is merged, nothing is lost.
6. Kill the network mid-command and mid-socket: the game recovers without duplicate effects.
7. Prod build points at the prod environment id and prod origin; dev at dev. No secrets in the bundle (search it).
8. Run these in a **headless browser or test harness** you control; do not test against another team's environment or real player data.
## Do
- Look up docs through MCP first; link the page you used in the PR description.
- Keep Open Play calls in one module/service layer, one writer per feature (never write the same state both locally and through Open Play).
- Handle every SDK session state, including `reauthRequired`, `banned` and `logoutUncertain`.
- Add a test with each integration change; report failing checks, never skip them.
## Don't
- Do not guess endpoints, headers, field names or error codes.
- Do not put a server key, token or cookie in client code, tests, logs or commits.
- Do not use `latest` or git/vendored copies of the SDK; do not hand-copy DTOs.
- Do not bypass CSRF, `Origin` or idempotency checks "just for testing".
- Do not remove a domain, redirect URI or environment that a live host still uses.
- Do not store save data in browser storage alone once the player can sign in.
- Do not write retry loops without backoff, or retry non-idempotent calls with new keys.
- Do not run production deploys or destructive operations unless the user explicitly asks.
Sonraki adım: Hızlı başlangıç ve Üretim kontrol listesi.