# Codex Pets [![codex-pets MCP server](https://glama.ai/mcp/servers/astandrik/codex-pets/badges/score.svg)](https://glama.ai/mcp/servers/astandrik/codex-pets) [![codex-pets on ModelScope](https://img.shields.io/badge/ModelScope-MCP-624AFF)](https://www.modelscope.cn/mcp/servers/astandrik/codex-pets) Community gallery for Codex-compatible animated pets with local accounts, manual moderation, public generation requests, YDB-backed asset storage, and public detail pages for approved and pending pets. Public site: https://pets.ydb-qdrant.tech/. ## My generations in this browser `/my-generations` lists tasks accepted here and available private results explicitly opened in the same browser, without signing in. Each entry stores only its private capability ID and saved/expiry timestamps in browser storage. Descriptions and images are not stored in this history. Keep browser data and private links safe; anyone with access to either can open the corresponding result. Statuses use the existing per-generation GET endpoint, with at most three reads at once. Live tasks refresh; ready/failed tasks stop polling. This view never creates, retries, cancels or publishes a task. Results still expire 24 hours after acceptance. History retains the latest 50 entries for seven days after expiry; expired entries cannot be opened. Clearing browser data removes this list, but does not reset quotas or cancel tasks. Earlier unknown links cannot be recovered; opening an existing available private link adds it to this browser's list. The history, form and result pages exclude analytics and search indexing. History has private/no-store and no-referrer headers. There is no IP-based ownership lookup, account synchronization, server-side history enumeration or new database schema. ## Generate a pet through remote MCP `generate_pet` accepts a text `prompt` (1–2000 characters), optional `displayName` (up to 80 characters), and a fresh random UUID `requestId`. Reuse that requestId with identical content after a disconnected response: no duplicate task or extra quota. Changed content with the same ID is rejected. Keep request and generation IDs private. Poll `get_pet_generation(generationId)` every 5 seconds. A completed job returns an unlisted preview and downloads: `pet.json`, lossless `spritesheet.webp`, and `pet.zip`. Format v2 is 1536×2288 with 9 animation states and 16 look directions. Results expire 24 hours after acceptance; idempotency hashes remain 7 days. Completed new tasks include editable name/description/tags. The private preview saves description changes atomically into pet.json and ZIP; tags are stored for the gallery submission. Saving is free of provider calls, keeps the sprite bytes unchanged, requires the current metadata revision and is disabled after submission. Existing completed tasks can be edited manually without a new model call. An unavailable or unknown metadata response leaves a usable image package and manual fields; it is never retried automatically, and unknown charges retain an accounting marker. The tool never publishes into the gallery. Before expiry, use **Submit for review** on the private result page to save a permanent gallery package and one pending submission, or upload the ZIP through `/submit`. Submission retries return the same receipt, including after a lost response. Anyone holding the private link can submit that result once; if signed in, the first submitter owns the submission. Contacts stay private. Submitting the saved package makes no generation-provider calls and does not change generation quotas. Later approval can prepare metadata and search embeddings through the existing admin workflow. The operator funds twelve GPT Image 2.5 Sunburst/high stages per task through sprite-gen 2.44.0: one base and eleven rows. After the base, up to eleven rows run concurrently. Each failed image stage can receive one retry after five seconds for RemoteDisconnected, IncompleteRead, HTTP 500 or HTTP 520, so the maximum is 24 image attempts. Successful stages are never repeated. New tasks then make at most one gpt-6.1-sol text/vision request to draft an English name, description and tags; metadata is not retried automatically. With `PET_GENERATION_REVIEW_FLOW_ENABLED=true`, the website accepts a character image, text, or both and pauses after the base character for explicit user confirmation. The flag defaults to false. Confirmation resumes the same task without another daily attempt; JSON and MCP admissions remain automatic regardless of the flag; existing jobs retain their saved policy. Before confirmation, **Edit character** creates a new text-guided version from the saved base, using one ordinary attempt while preserving the previous version. References remain private and expire with the job. See [website review and image references](docs/pet-generation-parallel-rows.md#website-character-review-and-image-references) for limits and rollout requirements. The website form at `/generate` and remote MCP share one queue. Limits are 200 accepted tasks/day globally, 10/IP by default, one active task and five waiting, counted by Moscow calendar day. Waiting expires after 30 minutes and failed tasks consume quota. Fully recorded terminal provider failures are isolated to their failed task; unconfirmed writes, lost leases and unclassified outcomes pause further paid work for operator review. A $50/day threshold checks recorded usage without monetary reservations. In-flight calls and unknown charges can exceed that amount; unknown-cost markers remain across task expiry and midnight. The prompt form and private previews exclude analytics/Webvisor. See [row recovery and accounting](docs/pet-generation-parallel-rows.md) for the operational contract. Generation is disabled by default and available through the website form and remote MCP. The npm CLI and browser WebMCP retain their catalog-only tools. See DEPLOYMENT.md for explicit schema, candidate and manual-enable steps. ## Stack - Next.js 16 App Router, React 19, TypeScript strict - Gravity UI + SCSS/BEM - local-ydb / YDB native gRPC via `ydb-sdk` - App-owned email+password auth with YDB-backed users and sessions - Pet assets stored in YDB as binary blobs - Dynamic `robots.txt`, `sitemap.xml`, `llms.txt`, `llms-full.txt`, and OpenAPI JSON - Agent-facing HTTP access through `llms.txt` / `llm.txt`, `/llms-full.txt`, `/mcp`, JSON routes, and TOON mirrors for core registry data - Optional read-only browser WebMCP tools in supported browser runtimes - Yandex Metrika using the same counter as `ydb-qdrant-ui` (`104844437`), with optional server-side aggregate MCP metrics - JSZip + Sharp for package validation ## Development ```bash nvm use 24 npm install cp .env.example .env.local npm run dev ``` Open `http://localhost:3000`. Run the local checks before submitting changes: ```bash npm run lint npx tsc --noEmit --incremental false npm test CODEX_PETS_DATA_SOURCE=mock NEXT_TELEMETRY_DISABLED=1 npm run build ``` ## Agent access Codex Pets exposes a public MCP server so coding agents can search, inspect, install, and share approved pet packs. Primary public surfaces: - Best guide: https://pets.ydb-qdrant.tech/guides/best-codex-pets-for-ai-coding-agents - LLM discovery: https://pets.ydb-qdrant.tech/llms.txt - MCP endpoint: https://pets.ydb-qdrant.tech/mcp - Public manifest: https://pets.ydb-qdrant.tech/api/manifest - CLI install: `npx @astandrik/codex-pets install ` Connect Codex: ```bash codex mcp add codexPets --url https://pets.ydb-qdrant.tech/mcp ``` Run a local stdio MCP server that proxies the public gallery: ```bash npx @astandrik/codex-pets mcp ``` Available MCP tools: - `search_pets` — discover approved pets when you need candidates or lack an exact slug - `get_pet` — fetch one public pet card when you already have an approved slug - `get_install_instructions` — get install commands without incrementing metrics - `get_badge_code` — generate README badge snippets for a known slug - `get_embed_code` — generate iframe embed snippets for a known slug - `get_card_code` — generate animated GIF snippets for a known slug, defaulting to sprite-only mode - `get_pet_request_info` — discover the public new-pet request workflow; it does not submit or inspect private requests HTTP fallback routes are public too: - `/openapi.json` - `/api/openapi.json` - `/llms-full.txt` - `/guides/best-codex-pets-for-ai-coding-agents` - `/guides/best-codex-pets-for-ai-coding-agents.md` - `/api/manifest` - `/api/manifest.toon` - `/api/pets` - `/api/pets.toon` - `/api/pets/` - `/api/pets/.toon` - `/pets//markdown` - `/api/tags` - `/api/tags.toon` - `/api/pets//share` - `/badge/.svg` - `/card/.gif` - `/embed/` The crawlable HTML gallery lives on `/`; numbered pages use `/?page=2`, `/?page=3`, and so on. The legacy `/pets` catalog URL permanently redirects to the equivalent homepage URL, while pet details remain on `/pets/`. `/api/pets` and `/api/pets.toon` accept optional `page` and `pageSize` parameters and always return `pagination` metadata. Without either parameter, the response is page 1 with up to 200 pets. With `page` but no `pageSize`, the page size remains 24. Top-level `total` is the number of returned pets; `pagination.totalItems` is the full filtered count and `pagination.hasNextPage` indicates whether more results are available. For the next request, increment `pagination.page` and pass the returned `pagination.pageSize` explicitly. If you deploy under a subpath such as `/codex-pets`, set: ```bash NEXT_PUBLIC_BASE_PATH=/codex-pets NEXT_PUBLIC_APP_URL=https://example.com/codex-pets ``` The public gallery renders without secrets. For account login, submit, moderation, and metrics you need `YDB_PETS_ENDPOINT`, `YDB_PETS_DATABASE`, and auth env. Optional server-side MCP metrics also need `YANDEX_METRIKA_MP_TOKEN` and `YANDEX_METRIKA_MP_CLIENT_ID`. Optional IndexNow notifications are enabled by `INDEXNOW_KEY`; the app serves `/.txt` and pings IndexNow after an admin approves a pet. Optional semantic search uses Yandex AI Studio text embeddings and exact cosine ranking in YDB. Query mode defaults to `PET_SEARCH_MODE=lexical`; `shadow` computes semantic ranking without changing public order, and `hybrid` combines lexical and text-semantic ranks. An independent `PET_SEARCH_VISUAL_MODE=off|shadow|hybrid` adds an offline visual-caption rank from four fixed sprite frames. Captions and their provenance remain internal; public JSON, TOON, homepage, MCP, and WebMCP shapes do not change. Configure `YANDEX_AI_STUDIO_FOLDER_ID`, `YANDEX_AI_STUDIO_API_KEY_FILE`, and `PET_SEARCH_MODEL_REVISION=yandex-text-embeddings-v2-768-2026-07`. The v2 runtime uses the managed `text-embeddings-v2-doc/query` models at 768 dimensions. Set `PET_SEARCH_VISUAL_MODEL_REVISION=yandex-text-embeddings-v2-768-pet-vision-qwen3.6-v1` for the compatible Qwen visual rank. Legacy 256-dimensional revisions remain registered for rollback. The API key is accepted only through the secret-file setting. Provider failures and timeouts fall back to lexical results; visual-only failures preserve the text-hybrid order. To run without YDB on generated sample data: ```bash CODEX_PETS_DATA_SOURCE=mock AUTH_MODE=single-user \ AUTH_SINGLE_USER_EMAIL=local-admin@example.com \ NEXT_PUBLIC_APP_URL=http://localhost:3000 \ npm run dev -- --port 3000 ``` ## Production notes For a dedicated public subdomain such as `https://pets.example.com`, prefer: ```bash NEXT_PUBLIC_APP_URL=https://pets.example.com NEXT_PUBLIC_BASE_PATH= ``` If the app container talks to YDB by Docker hostname, for example `grpc://ydb-local:2136`, run the app on the same Docker network as the YDB containers: ```bash docker run --network ydb-net ... ``` Telegram and similar preview crawlers are handled by lightweight preview routes: - `/api/preview/site` - `/api/preview/pets/[slug]` The reverse proxy should rewrite preview-bot requests for `/` and `/pets/` to those endpoints before proxying to the normal App Router pages. See: - [deploy/nginx-pets-subdomain.conf.example](./deploy/nginx-pets-subdomain.conf.example) - [deploy/nginx-pets-edge-proxy.conf.example](./deploy/nginx-pets-edge-proxy.conf.example) ### Local YDB quickstart For local app development, a plain local-ydb root database at `/local` is enough; you do not need a CMS tenant or dynamic node. The app runs on the host, so the local-ydb container must publish gRPC on `127.0.0.1:2136`. If you use the `local-ydb` MCP, start from a clean root database with `local_ydb_destroy_stack(confirm=true)` and `local_ydb_bootstrap_root_database(confirm=true)`. If the resulting container does not publish `127.0.0.1:2136`, recreate only the container on the same volume with a host gRPC port: ```bash docker rm -f ydb-local docker run -d --name ydb-local --no-healthcheck --network ydb-net \ --restart unless-stopped \ -p 127.0.0.1:2136:2136 \ -p 127.0.0.1:8765:8765 \ -v ydb-local-data:/ydb_data \ -e GRPC_PORT=2136 \ -e MON_PORT=8765 \ -e GRPC_TLS_PORT= \ -e YDB_GRPC_ENABLE_TLS=0 \ -e YDB_ANONYMOUS_CREDENTIALS=1 \ -e YDB_LOCAL_SURVIVE_RESTART=1 \ ghcr.io/ydb-platform/local-ydb:26.1.1.6 ``` Use these local app env vars: ```bash AUTH_MODE=single-user AUTH_SINGLE_USER_ID=local-admin AUTH_SINGLE_USER_EMAIL=local-admin@example.com AUTH_SINGLE_USER_NAME="Local Admin" SESSION_COOKIE_SECRET=dev-cookie-secret PASSWORD_PEPPER=dev-password-pepper INITIAL_ADMIN_EMAILS=local-admin@example.com YDB_ANONYMOUS_CREDENTIALS=1 YDB_ENDPOINT=grpc://127.0.0.1:2136 YDB_PETS_ENDPOINT=grpc://127.0.0.1:2136 YDB_PETS_DATABASE=/local NEXT_PUBLIC_APP_URL=http://localhost:3000 ``` `YDB_ENDPOINT` is needed for local host-to-Docker runs because `ydb-sdk` otherwise follows discovery endpoints that may contain the Docker container hostname. Apply schema, seed data, and start the app: ```bash docker cp ydb/schema.yql ydb-local:/tmp/codex-pets-schema.yql docker exec ydb-local /ydb -e grpc://localhost:2136 -d /local scripting yql -f /tmp/codex-pets-schema.yql npm run db:migrate npm run seed:dev:reset npm run dev -- --port 3000 ``` Open `http://localhost:3000`. The local YDB monitoring UI is `http://127.0.0.1:8765`. For a remote or tenant-backed deployment, point the app at a reachable tenant endpoint, for example: ```bash YDB_PETS_ENDPOINT=grpc://ydb-host:2137 YDB_PETS_DATABASE=/local/your-tenant YDB_STATIC_CREDENTIALS_USER=appuser YDB_STATIC_CREDENTIALS_PASSWORD_FILE=/run/secrets/app.password YDB_STATIC_CREDENTIALS_AUTH_ENDPOINT=grpc://ydb-host:2136 ``` For local development without a full account flow: ```bash AUTH_MODE=single-user AUTH_SINGLE_USER_ID=local-admin SESSION_COOKIE_SECRET=dev-cookie-secret PASSWORD_PEPPER=dev-password-pepper INITIAL_ADMIN_EMAILS=local-admin@example.com ``` For the normal built-in account flow: ```bash AUTH_MODE=app-session SESSION_COOKIE_SECRET=change-me PASSWORD_PEPPER=change-me-too INITIAL_ADMIN_EMAILS=admin@example.com ``` Create tables manually on the existing local-ydb tenant: ```bash ydb -e "$YDB_PETS_ENDPOINT" -d "$YDB_PETS_DATABASE" scripting yql -f ydb/schema.yql ``` Apply migrations to an existing database: ```bash npm run db:migrate ``` Preview and apply the approved-pet text and visual backfills after the migrations: ```bash npm run search:backfill -- --dry-run npm run search:backfill -- --apply npm run search:backfill -- --apply --slug orbit-otter --force npm run search:backfill-vision -- --dry-run npm run search:backfill-vision -- --apply --slug orbit-otter npm run search:backfill-vision -- --apply npm run search:eval:calibrate npm run search:eval:holdout ``` Both backfills require an explicit `--dry-run` or `--apply`; visual `--force` is valid only with `--apply`. They never print document text, captions, images, embeddings, prompts, or secrets. Dry-run still reads and hashes spritesheets but never calls either AI provider and never writes YDB. A safe rollout is base `lexical` and visual `off` → additive migrations → backfills → visual `shadow` → calibration → untouched holdout → human review of the combined `sexy` top five → both modes `hybrid`. An applied text or visual backfill that changes vectors prints the required related-pet snapshot follow-up. Run the full V24 derived-data sequence after embedding maintenance completes so snapshot rankings do not remain stale: ```bash npm run related:backfill-description-query -- --dry-run npm run related:backfill-description-query -- --apply npm run related:backfill-description-document -- --dry-run npm run related:backfill-description-document -- --apply npm run related:backfill-annotations -- --dry-run npm run related:backfill-annotations -- --apply npm run related:backfill-annotation-query -- --dry-run npm run related:backfill-annotation-query -- --apply npm run related:backfill-annotation-document -- --dry-run npm run related:backfill-annotation-document -- --apply npm run related:rebuild -- --dry-run npm run related:rebuild -- --apply npm run related:verify:v24 ``` Related-pets description similarity uses separate query and document revisions built from the same normalized `name + kind + description` text. Tags are excluded from both embedding inputs. The query revision uses the query role and the document revision uses the document role of the same 768-dimensional model. Run model backfills sequentially so they share the AI Studio rate budget. V24 combines description similarity with controlled entity, franchise, collection, and archetype annotations. Visual similarity contributes to ordering inside the qualified tier and also orders shared-topic sparse-fallback candidates after topic count and kind. Visual evidence alone cannot qualify or rescue a match. The relation policy adds verified parent families and known numbered-series roots without replacing entity/franchise identifiers or stored annotations. It preserves explicit family-field overrides. Registry changes require a new relation-policy revision and generation, not new annotation embeddings. The current ranking revision stores eight ordered slugs per approved pet. Pet detail pages render all eight immediately (four columns on desktop, three on tablet, and two on mobile); the private Markdown twin intentionally keeps the first four. Its persisted revision is immutable so the active generation can be checked against the exact current implementation. Text and visual backfills resolve their embedding provider independently from their active revision. Visual ranking is disabled safely when the text and visual revisions use incompatible embedding models. Admin approval can queue an atomic preparation that refreshes the ordinary search document, description query/document vectors, controlled annotation and both annotation-vector roles, plus visual input. It publishes the pet, review, and prepared generation in one transaction only after every input is current. Failures leave the pet pending and the previous generation active. When `PET_RELATED_PREAPPROVAL_ENABLED` is not exact `true`, approval fails closed instead of publishing a pet without current V24 inputs. Atomic generation activation also rotates the related-candidate and sitemap cache keys, so the standalone worker does not depend on a Next request context. `npm run related:verify:v24` is read-only: it recomputes V24 from stored inputs and checks coverage, integrity, the active revision, and exact ordered snapshot parity without calling AI Studio. The first rollback is `PET_SEARCH_VISUAL_MODE=off`; use `PET_SEARCH_MODE=lexical` to disable the text-semantic contour too. The additive caption and embeddings tables may remain. The checked-in eval queries live in `src/lib/pets/search/search-eval-fixtures.json` with frozen `calibration` and `holdout` splits. Calibration evaluates all observed visual scores against weights `0.25`, `0.50`, `0.75`, and `1.00`; the holdout command requires a committed revision-bound profile and must not be used for tuning. Live eval requires configured YDB and AI Studio access and prints aggregate results plus the public slugs in the final `sexy` review list. Seed local development data after the schema exists: ```bash npm run seed:dev ``` Use `npm run seed:dev:reset` to replace only the fixed `dev_*` seed records. ## Current behavior - Public users can browse the gallery and open `/pets/[slug]`. - Public users can submit a pet without logging in by providing files and an optional contact email. - Public users can request a generated pet without logging in by providing a contact email, text brief, and optional reference image. - Logged-in users can see only their own pets under `/my-pets`. - Logged-in users can see their own pet generation requests under `/my-requests`. - Admins are determined by `INITIAL_ADMIN_EMAILS`. - Admins can approve, reject, and delete pending pets from `/admin/submissions`. - Admins can review generation requests and link them to existing pets from `/admin/requests`. - Owners can delete their own pets from `/my-pets`. - Admins can delete any pet from the pet detail page. - Deleted pets disappear from owner lists, public listings, and `sitemap.xml`. ## SEO, agents, and analytics - `robots.txt` is served from `src/app/robots.ts`. - The canonical `/api/manifest` and `/api/manifest.toon` URLs allow search and AI crawler access and return `X-Robots-Tag: index, follow`. Both formats include the complete approved catalog. These exact-path exceptions do not open query variants, similarly named paths, or other restricted API routes. - `sitemap.xml` is dynamic and includes all currently approved pets. - `llms.txt` is dynamic and provides a curated AI-readable map of the gallery, manifest, and approved pet pages. `/llm.txt` is a direct plain-text alias for fetchers that request the singular filename. - `llms-full.txt` is dynamic and provides expanded AI-readable docs with API reference links, auth notes, examples, and webhooks status. - `/openapi.json` is the canonical OpenAPI 3.1 specification for the public agent/developer contract subset. It intentionally omits public metric mutation and download redirect routes. `/api/openapi.json` is an alias for scanners that probe predictable API paths. - `/developers` and `/docs/api` are indexed developer-resource pages for API, OpenAPI, MCP, auth, and webhooks discoverability. - `/mcp` is a public Streamable HTTP MCP server with read-only catalog tools and quota-limited generation for coding agents. Codex can connect with: `codex mcp add codexPets --url https://pets.ydb-qdrant.tech/mcp`. - Official MCP Registry name: `tech.ydb-qdrant.pets/codex-pets-ydb-qdrant`. - `server.json` and `/.well-known/mcp/server.json` expose MCP Registry metadata for the public remote server. - `/.well-known/mcp-registry-auth` exposes the public HTTP domain auth record used by `mcp-publisher`. - HTTP agent access is the primary public machine contract: - `/mcp` — Streamable HTTP MCP endpoint with catalog tools: `search_pets`, `get_pet`, `get_install_instructions`, `get_badge_code`, `get_embed_code`, `get_card_code`, and `get_pet_request_info` - `/openapi.json` and `/api/openapi.json` — OpenAPI 3.1 public agent/developer contract subset - `/llms-full.txt` — expanded LLM-readable API, auth, MCP, package, and webhooks documentation - `/developers` and `/docs/api` — developer portal and API docs pages - `/server.json` and `/.well-known/mcp/server.json` — MCP Registry metadata pointing to the public Streamable HTTP remote - `/.well-known/mcp-registry-auth` — public MCP Registry HTTP auth record - `/api/manifest` — approved pet list with page URLs, install commands, and asset URLs - `/api/manifest.toon` — TOON mirror of the public manifest for LLM-friendly retrieval - `/api/pets?q=&kind=all|creature|object|character` — approved pet list/search JSON without private contact emails - `/api/pets.toon?q=&kind=all|creature|object|character` — TOON mirror of approved pet list/search without private contact emails - `/api/pets/` — public detail JSON for one approved pet without private contact emails - `/api/pets/.toon` — TOON mirror of public detail data without private contact emails - `/api/tags` — current tag counts for approved pets - `/api/tags.toon` — TOON mirror of current tag counts - `/api/pets//share` — sanitized install, badge, and embed snippets - `/api/pets//install` — read-only install instructions with no metric mutation - `/badge/.svg` — README badge SVG - `/card/.gif` — animated GIF share surface. Supports `mode=sprite|card`, `state`, and `scale`; default sharable output is sprite-only. - `/embed/` — iframe embed page. Supports `mode=sprite|card`, `state`, `scale`, `theme`, `compact`, and visibility toggles. - `npx @astandrik/codex-pets install ` — CLI install command format - Browser WebMCP is a read-only progressive enhancement. It only works in browser runtimes that expose `navigator.modelContext`; ordinary HTTP crawlers and ChatGPT browsing sessions should use the endpoints above. Supported browser WebMCP tools: - `search_codex_pets` — search approved pets through `/api/pets` - `get_codex_pet` — fetch one approved pet through `/api/pets/[slug]` - `get_codex_pets_manifest` — fetch `/api/manifest` - `get_current_codex_pet` — inspect the approved pet open in the current tab - WebMCP intentionally does not expose submit, like, download/install counters, auth, admin, moderation, or delete actions. - The sitemap updates automatically after moderation changes; no cron or manual rebuild is needed for new approved pets to appear there. - Yandex Metrika is loaded in production only and tracks: - account register/login success and error - pet submit success and error - pet generation request success and error - moderation approve/reject/delete - related-pet impressions at 50% visibility and detail-navigation clicks, including source slug, target slug, and one-based position - related install-command copies and downloads, both directly on the card and for matching detail-page actions within a 30-minute browser session - Server-side MCP aggregate metrics are optional. They are enabled only when `YANDEX_METRIKA_MP_TOKEN` and `YANDEX_METRIKA_MP_CLIENT_ID` are configured. MCP metrics use a dedicated technical Metrika ClientID and send a synthetic `/mcp` pageview before the `mcp_tool_call` goal event. The payload includes only aggregate tool dimensions such as tool name, status, safe slug, kind, result count, and limit; it does not include raw MCP search text, IP address, user-agent, origin header, contact email, owner email, or owner identifiers. - IndexNow is optional. Set `INDEXNOW_KEY` in the runtime env to enable the public key file and approval-time notifications for the gallery, the new pet detail page, `sitemap.xml`, `llms.txt`, and `/api/manifest`. ## Main routes - `/` — public gallery - `/request` — public pet generation request flow - `/submit` — public submit flow - `/login`, `/register`, `/logout` — local account flow - `/my-pets` — owner view - `/my-requests` — logged-in user generation request view - `/admin/submissions` — admin moderation queue - `/admin/requests` — admin pet generation request queue - `/pets/[slug]` — pet detail page - `/agents` — agent and MCP connection guide - `/developers` — Codex Pets Developer Portal - `/docs/api` — Codex Pets API docs - `/guides/best-codex-pets-for-ai-coding-agents` — category guide for Codex pet selection - `/guides/codex-pets-vs-vscode-pets` — comparison guide for editor pet use cases - `/mcp` — public Streamable HTTP MCP endpoint - `/openapi.json`, `/api/openapi.json` — public OpenAPI specification - `/server.json`, `/.well-known/mcp/server.json` — MCP Registry metadata - `/api/manifest` — public agent/CLI manifest - `/api/manifest.toon` — TOON mirror of the public manifest - `/api/pets` — public approved pet list/search JSON - `/api/pets.toon` — TOON mirror of approved pet list/search - `/api/pets/[slug]` — public approved pet detail JSON - `/api/pets/[slug].toon` — TOON mirror of public pet detail data - `/api/tags`, `/api/pets/[slug]/share`, `/api/pets/[slug]/install` — read-only agent/share JSON - `/api/tags.toon` — TOON mirror of approved tag counts - `/badge/[slug].svg`, `/card/[slug].gif`, `/embed/[slug]` — share surfaces - `/robots.txt`, `/sitemap.xml`, `/llms.txt`, `/llm.txt`, `/llms-full.txt` — SEO and AI-readable outputs ## Agent-facing checks Use `CODEX_PETS_DATA_SOURCE=mock npm run dev -- --port 3000` to smoke-check agent-facing routes without local YDB. Expected public endpoints: ```bash curl -I http://localhost:3000/ curl -I http://localhost:3000/api/pets curl -I http://localhost:3000/api/pets.toon curl -I http://localhost:3000/api/manifest curl -I http://localhost:3000/api/manifest.toon curl -I http://localhost:3000/openapi.json curl -I http://localhost:3000/api/openapi.json curl -I http://localhost:3000/api/tags curl -I http://localhost:3000/api/tags.toon curl -I http://localhost:3000/llms.txt curl -I http://localhost:3000/llm.txt curl -I http://localhost:3000/llms-full.txt curl -I http://localhost:3000/developers curl -I http://localhost:3000/docs/api curl -I http://localhost:3000/guides/best-codex-pets-for-ai-coding-agents curl -I http://localhost:3000/guides/codex-pets-vs-vscode-pets curl -i http://localhost:3000/mcp ``` For a JSON-response MCP smoke test: ```bash curl -s http://localhost:3000/mcp \ -H 'Content-Type: application/json' \ -H 'Accept: application/json, text/event-stream' \ --data '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' ``` For WebMCP itself, use a WebMCP-capable Chrome or lab browser and check that `navigator.modelContext` exposes the read-only tools listed above. In normal browsers without WebMCP, the client registrar is a no-op; this is expected and does not affect the HTTP agent contract. ## Private deployment notes Concrete per-host instructions, local paths, and operational notes should live under a gitignored `private/` directory. The public docs in this repo should stay generic and safe to commit. ## Pet Package Each pet is distributed as: - `pet.json` - `spritesheet.webp` or `spritesheet.png` - downloadable ZIP containing both files at the root The registry accepts both Codex atlas versions, each using `192x208` cells: - v1: omit `spriteVersionNumber` or set it to `1`; use an 8x9 atlas at `1536x1872`. - v2: set `spriteVersionNumber` to `2`; use an 8x11 atlas at `1536x2288`, including the 16 clockwise look directions in rows 9 and 10. ## CLI install Approved gallery pets can be installed into Codex from npm: ```bash npx @astandrik/codex-pets install zero-two-2 ``` The CLI reads `/api/manifest` from `https://pets.ydb-qdrant.tech` by default and writes to `${CODEX_HOME:-~/.codex}/pets//`. Use `--force` to replace an existing local pet folder, or `CODEX_PETS_URL` / `--url` to point at another deployment. If Codex is already running, restart it before selecting the new pet in Settings -> Appearance -> Pets. ### Optional movement guidance `PET_GENERATION_ANIMATION_HINTS_ENABLED=true` enables one optional movement field before base confirmation. It defaults off. A single description may contain general preferences and conditions for individual animation states. The first accepted confirmation fixes the text; retries return those accepted settings. Guidance refines motion, turns and gestures in nine states; size changes and cursor-driven head motion are not supported. Base and gaze generation stay unchanged, with no extra provider stage or daily attempt. Deploy compatible web and generation-worker versions before enabling guidance. Turning the flag off prevents new guidance while accepted jobs and replays continue. Keep compatible readers/writers on rollback so saved guidance is not discarded. See `docs/pet-generation-parallel-rows.md` for the generation lifecycle. `PET_GENERATION_ANIMATION_REVISIONS_ENABLED=true` enables editing selected animations on a live completed private result with a saved base. The default is false. Select any of the nine ordinary states and optionally add corrections (2000 characters); one batch uses one ordinary daily attempt. A separate version has its own 24 hours, retains the base and all unselected atlas pixels, and requires explicit acceptance before download or publication. Gaze editing and editing after expiry are not supported. See [animation revisions](docs/pet-generation-parallel-rows.md#animation-revisions). ### Continue a failed generation `PET_GENERATION_CONTINUATION_ENABLED=true` enables continuation of unexpired failed website jobs with a confirmed, intact base; it defaults off. Rebuild reuses the same job and deadline without an image call or daily attempt (up to three accepted rebuilds, at least 30 seconds apart). It may finish a card-metadata step that has never started. Regeneration selects from all eleven strips, with missing, corrupt or diagnosed-bad strips mandatory, and creates an independent 24-hour version for one ordinary daily attempt. Existing movement guidance and corrections are inherited; no new text is accepted. Successful continuations are ready immediately, including ZIP download. Operation UUIDs recover uncertain responses. Only identifiers are saved in browser storage. Snapshot preparation has a five-minute lease; bounded artifact writes precede a short atomic admission transaction. The accepted child is independent of its parent's expiry. Existing costs and unknown outcomes are retained.