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/.
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
nvm use 24
npm install
cp .env.example .env.local
npm run dev
Open http://localhost:3000.
Agent access
Codex Pets exposes a public read-only 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 <slug>
Connect Codex:
codex mcp add codexPets --url https://pets.ydb-qdrant.tech/mcp
Run a local stdio MCP server that proxies the public gallery:
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 slugget_install_instructionsβ get install commands without incrementing metricsget_badge_codeβ generate README badge snippets for a known slugget_embed_codeβ generate iframe embed snippets for a known slugget_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/<slug>/api/pets/<slug>.toon/pets/<slug>/markdown/api/tags/api/tags.toon/api/pets/<slug>/share/badge/<slug>.svg/card/<slug>.gif/embed/<slug>
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/<slug>.
/api/pets and /api/pets.toon accept optional page and pageSize parameters. Supplying either parameter enables the additive pagination metadata object; requests without them retain the legacy response shape. In paginated responses, top-level total is the number of returned pets and pagination.totalItems is the full filtered count.
If you deploy under a subpath such as /codex-pets, set:
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 /<key>.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:
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:
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:
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/<slug> to those endpoints before proxying to the normal App Router pages. See:
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:
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:
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:
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:
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:
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:
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:
ydb -e "$YDB_PETS_ENDPOINT" -d "$YDB_PETS_DATABASE" scripting yql -f ydb/schema.yql
Apply migrations to an existing database:
npm run db:migrate
Preview and apply the approved-pet text and visual backfills after the migrations:
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.
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.
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-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:
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.txtis served fromsrc/app/robots.ts.sitemap.xmlis dynamic and includes all currently approved pets.llms.txtis 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.txtis dynamic and provides expanded AI-readable docs with API
reference links, auth notes, examples, and webhooks status.
/openapi.jsonis 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.
/developersand/docs/apiare indexed developer-resource pages for API,
OpenAPI, MCP, auth, and webhooks discoverability.
/mcpis a public read-only Streamable HTTP MCP server 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.jsonand/.well-known/mcp/server.jsonexpose MCP Registry
metadata for the public remote server.
/.well-known/mcp-registry-authexposes 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 read-only tools:
search_pets, get_pet, get_install_instructions, get_badge_code, get_embed_code, get_card_code, and get_pet_request_info
/openapi.jsonand/api/openapi.jsonβ OpenAPI 3.1 public
agent/developer contract subset
/llms-full.txtβ expanded LLM-readable API, auth, MCP, package, and
webhooks documentation
/developersand/docs/apiβ developer portal and API docs pages/server.jsonand/.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=<query>&kind=all|creature|object|characterβ approved pet
list/search JSON without private contact emails
/api/pets.toon?q=<query>&kind=all|creature|object|characterβ TOON
mirror of approved pet list/search without private contact emails
/api/pets/<slug>β public detail JSON for one approved pet without
private contact emails
/api/pets/<slug>.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/<slug>/shareβ sanitized install, badge, and embed snippets/api/pets/<slug>/installβ read-only install instructions with no metric
mutation
/badge/<slug>.svgβ README badge SVG/card/<slug>.gifβ animated GIF share surface. Supportsmode=sprite|card,state, andscale; default sharable output is sprite-only./embed/<slug>β iframe embed page. Supportsmode=sprite|card,state,scale,theme,compact, and visibility toggles.npx @astandrik/codex-pets install <slug>β 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/petsget_codex_petβ fetch one approved pet through/api/pets/[slug]get_codex_pets_manifestβ fetch/api/manifestget_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
- 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_KEYin 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 read-only 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:
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:
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.jsonspritesheet.webporspritesheet.png- downloadable ZIP containing both files at the root
The registry accepts both Codex atlas versions, each using 192x208 cells:
- v1: omit
spriteVersionNumberor set it to1; use an 8x9 atlas at
1536x1872.
- v2: set
spriteVersionNumberto2; use an 8x11 atlas at1536x2288,
including the 16 clockwise look directions in rows 9 and 10.
CLI install
Approved gallery pets can be installed into Codex from npm:
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/<slug>/. 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.











