{"owner":"rommapp","repo":"romm","hasSkills":true,"totalSkillsCount":4,"totalTokensCount":3042,"categories":["root-instruction","mcp-config","marketplace","plugin-manifest"],"hasMcp":true,"mcpConfig":{"mcpServers":{"romm":{"command":"npx","args":["-y","@modelcontextprotocol/server-romm"]}}},"found":["AGENTS.md",".cursor/mcp.json",".claude-plugin/marketplace.json",".claude-plugin/plugin.json"],"skills":{"AGENTS.md":"# RomM - Repository Guide for Contributors & Agents\n\nRomM is a self-hosted ROM manager and player: scan a game library off disk, enrich it with metadata from 10+ providers, browse it in a web UI, and play in the browser.\n\n---\n\nThe frontend talks to the backend over `/api/*` (REST) and `/ws` (Socket.IO). TypeScript types are **generated** from the backend's OpenAPI schema into `frontend/src/__generated__/` - the backend is the single source of truth for API shapes.\n\n## Deep-dive references\n\n- **`docs/BACKEND_ARCHITECTURE.md`** - directory map, ER diagram, every endpoint, auth/scopes, tasks.\n- **`docs/FRONTEND_ARCHITECTURE.md`** - routing, stores, services, theming, build tooling.\n- **`DEVELOPER_SETUP.md`** - Docker and manual local setup (mock library, `.env`, services).\n- **`CONTRIBUTING.md`** - contribution flow, **AI-assistance disclosure**, translations.\n\n---\n\n## Stack-specific guidance\n\n`frontend/AGENTS.md` (v1 vs v2, frontend commands) and `backend/AGENTS.md` (backend commands) load when you work in those directories. New frontend work goes in v2 (`frontend/src/v2/`); v1 is frozen.\n\n---\n\n## Skills - load the focused guide for your task\n\nThese live in `.claude/skills/` and carry the detailed rules. Invoke the one that matches what you're doing. `pr-ready`, `address-bot-reviews`, and `draft-announcement` are run by the user, not auto-invoked.\n\n---\n\n## Repo-wide rules\n\n**Disclose AI assistance in the PR.** RomM requires it (see `CONTRIBUTING.md`): state that AI was used and to what extent. This is mandatory and non-negotiable for agent-written contributions.\n**Branch off `master`; open PRs against `master`.** Fork → feature branch → PR. Don't push to `master`.\n**Linting is via [Trunk](https://trunk.io)** (`trunk fmt && trunk check`), which wraps ruff, black, isort, ESLint, Prettier, and more, and runs in CI on every PR. **Never commit with `--no-verify`.**\n**The backend owns the API contract.** Changed a response schema or route? Regenerate frontend types (`npm run generate`) and re-typecheck.\n**Tests travel with code.** New logic gets a test; new endpoints get endpoint tests; new v2 primitives get a Storybook story (+ `play()` if interactive).\n**Verify before handoff.** Don't say \"done\" on UI work without testing it in the browser in both themes and all input modalities. See `review-polish`.\n**English first.** Outside of language files, all code, comments, identifiers, `.md` files, and commit/PR messages are in English.\n**No em-dashes.** Never use em-dashes (U+2014) when writing comments or text. Use commas, parentheses, or separate sentences instead. An em-dash string literal is code (an empty-value glyph) and stays allowed.\n**Prefer a check to a model review.** A mechanical rule (an import, a character, a CSS pattern, an SFC shape) belongs in ESLint, `tsconfig`, or Trunk. When a review finding repeats, propose a check as a named follow-up; see `review-polish`.\n**Keep comments short.** Comments should be concise, and focus on the \"why\" rather than the \"what\" (the code itself is the \"what\"). A comment is one or two lines; a docstring is one sentence plus `Args:`/`Returns:` when the signature needs it. Three or more lines of prose means you are explaining, not commenting. See `review-polish` for what to cut.\n**Don't restate the code.** The code is self-documenting, so skip comments that narrate what a reader can already see (which button sits where, that something is disabled when empty, obvious ordering). Comment only non-obvious \"why\" that the code can't convey on its own.\n**One home per value.** Before declaring a constant, type, limit, regex, or store getter, search for an existing one and import it. Validation limits live on the model and are imported by endpoints; a type lives in the component that owns it and is exported. Don't add a near-duplicate that differs only by sorting, and don't invent an identity scheme where a foreign key already exists.\n**Never commit secrets.** Never commit secrets (API keys, passwords, tokens, etc.) to the repo. Use environment variables or secret management tools instead.\n**Don't explain a change.** Avoid comments that explain why a change was made to the code, or that record what the code used to do. Focus instead on the current behaviour of the code and how it works. Reasons for a change go in the commit message and the PR body.\n**Python tools live in `backend/tools/`.** Standalone dev/test utilities and scripts (not part of the app runtime) go in `backend/tools/`, not scattered across `backend/`.\n**Link PRs to issues.** In the PR description, use `Fixes #XXXX` for issue/bug fixes and `Closes #XXXX` for feature implementations.\n**Use the PR template.** Base every PR description on `.github/PULL_REQUEST_TEMPLATE.md`.\n**Show UI changes in the PR.** A PR that touches anything visible ships with at least one screenshot under the template's `Screenshots` heading, captured from the running app during the `review-polish` browser pass. Enough shots to convey what changed, not a catalogue of every state. Save the files outside the repo and never commit them, and upload them with `gh pr create --attach` (or `gh pr edit --attach` on an existing PR) rather than handing the paths to the user.\n**Diagram architectural changes in the PR.** When a change moves a boundary (a new service, task, or provider in a path, a model relationship, a different call path across layers, an auth or socket flow), the PR description carries a `mermaid` block showing it. GitHub renders them. Draw what changed, not the whole system. See `review-polish`.\n\n---\n\n## Never run the full backend test suite locally\n\nA bare `uv run pytest` (or `pytest -vv`) over `backend/` runs serially, takes 20+ minutes, and\nburns a huge number of tokens on output. Don't do it, even to \"double check\" at the end.\n\nInstead, select the tests affected by the change and run only those. Add `-n auto` when the\nselection spans a directory or more: the suite is set up for `pytest-xdist` (one database per\nworker).\n\n```bash\ncd backend\nuv run pytest tests/path/to/test_file.py                # one file\nuv run pytest tests/path/to/test_file.py::test_name     # one test\nuv run pytest -n auto tests/handler/ tests/endpoints/   # affected areas, in parallel\nuv run pytest -k \"scan or queue\"                        # by name pattern\n```\n\nIt gains nothing on a single file or test, and `--pdb` and `-s` don't work under it, so drop it\nwhen debugging.\n\nPick the targets from the diff: the test file mirroring each changed module\n(`backend/<area>/x.py` → `backend/tests/<area>/test_x.py`), plus the tests of the\ncallers of anything whose signature or behavior you changed (`grep` for the symbol).\n\nCI runs the whole suite on the PR (`pytest.yml`, MariaDB + PostgreSQL). That is the\nplace for full-suite coverage; local runs stay scoped.\n\n**In a git worktree, run tests against a temporary database.** Every checkout shares\n`romm_test`, and one on another branch can migrate it to a revision yours lacks, so\nevery test errors in setup with `Can't locate revision`. Set `ROMM_TEST_DB_TAG` to a\ntag unique to the worktree: the run creates and migrates `romm_test_tmp_<tag>` (one per\nxdist worker), then drops it at the end. Never `stamp` or downgrade the shared `romm_test`.\n\n```bash\nROMM_TEST_DB_TAG=my_worktree uv run pytest -n auto tests/handler/\n```\n\n---\n\n## Environment setup\n\nEach tool version is pinned in one file: Python in `.python-version`, uv as `ARG UV_VERSION` in `docker/Dockerfile`, and Node in `frontend/.nvmrc`. Don't install these by hand. Run `scripts/dev-setup.sh`, which installs the pinned toolchain, the backend and frontend dependencies, and the Trunk launcher, and skips anything already in place. Add `--db` to also install and start MariaDB with the pytest database (Debian/Ubuntu only). Rerun it whenever a version is wrong or a dependency is missing.\n\nIn Claude Code cloud sessions, `.claude/hooks/cloud-setup.sh` runs `scripts/dev-setup.sh --db` at session start. Setting the environment's setup script to `bash /home/user/romm/scripts/dev-setup.sh --db || true` gets the install cached in the environment snapshot, so the hook only has to restart MariaDB. The setup script doesn't run from the repo root and `CLAUDE_PROJECT_DIR` isn't set yet, so the path must be absolute. The cloud clone lives at `/home/user/<repo-name>`; adjust the path for a renamed fork. `|| true` keeps a failed install from blocking the session (the hook retries it). Other agents should run `scripts/dev-setup.sh --db` from the repo root as their setup step.\n\n---\n\n## Quick command reference\n\n**Setup:** see `DEVELOPER_SETUP.md`. Docker path is `cp env.template .env` → `docker compose build` → `docker compose up -d` (app at `http://localhost:3000`).\n\n**Lint (both stacks):** `trunk fmt && trunk check`.\n",".cursor/mcp.json":"# Model Context Protocol (MCP) Configuration\n\nPath: `.cursor/mcp.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/rommapp/romm/HEAD/.cursor/mcp.json)",".claude-plugin/marketplace.json":"# Claude Plugin Marketplace Catalog\n\nPath: `.claude-plugin/marketplace.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/rommapp/romm/HEAD/.claude-plugin/marketplace.json)",".claude-plugin/plugin.json":"# claude-plugin Plugin Manifest\n\nPath: `.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/rommapp/romm/HEAD/.claude-plugin/plugin.json)"},"files":{"AGENTS.md":"# RomM - Repository Guide for Contributors & Agents\n\nRomM is a self-hosted ROM manager and player: scan a game library off disk, enrich it with metadata from 10+ providers, browse it in a web UI, and play in the browser.\n\n---\n\nThe frontend talks to the backend over `/api/*` (REST) and `/ws` (Socket.IO). TypeScript types are **generated** from the backend's OpenAPI schema into `frontend/src/__generated__/` - the backend is the single source of truth for API shapes.\n\n## Deep-dive references\n\n- **`docs/BACKEND_ARCHITECTURE.md`** - directory map, ER diagram, every endpoint, auth/scopes, tasks.\n- **`docs/FRONTEND_ARCHITECTURE.md`** - routing, stores, services, theming, build tooling.\n- **`DEVELOPER_SETUP.md`** - Docker and manual local setup (mock library, `.env`, services).\n- **`CONTRIBUTING.md`** - contribution flow, **AI-assistance disclosure**, translations.\n\n---\n\n## Stack-specific guidance\n\n`frontend/AGENTS.md` (v1 vs v2, frontend commands) and `backend/AGENTS.md` (backend commands) load when you work in those directories. New frontend work goes in v2 (`frontend/src/v2/`); v1 is frozen.\n\n---\n\n## Skills - load the focused guide for your task\n\nThese live in `.claude/skills/` and carry the detailed rules. Invoke the one that matches what you're doing. `pr-ready`, `address-bot-reviews`, and `draft-announcement` are run by the user, not auto-invoked.\n\n---\n\n## Repo-wide rules\n\n**Disclose AI assistance in the PR.** RomM requires it (see `CONTRIBUTING.md`): state that AI was used and to what extent. This is mandatory and non-negotiable for agent-written contributions.\n**Branch off `master`; open PRs against `master`.** Fork → feature branch → PR. Don't push to `master`.\n**Linting is via [Trunk](https://trunk.io)** (`trunk fmt && trunk check`), which wraps ruff, black, isort, ESLint, Prettier, and more, and runs in CI on every PR. **Never commit with `--no-verify`.**\n**The backend owns the API contract.** Changed a response schema or route? Regenerate frontend types (`npm run generate`) and re-typecheck.\n**Tests travel with code.** New logic gets a test; new endpoints get endpoint tests; new v2 primitives get a Storybook story (+ `play()` if interactive).\n**Verify before handoff.** Don't say \"done\" on UI work without testing it in the browser in both themes and all input modalities. See `review-polish`.\n**English first.** Outside of language files, all code, comments, identifiers, `.md` files, and commit/PR messages are in English.\n**No em-dashes.** Never use em-dashes (U+2014) when writing comments or text. Use commas, parentheses, or separate sentences instead. An em-dash string literal is code (an empty-value glyph) and stays allowed.\n**Prefer a check to a model review.** A mechanical rule (an import, a character, a CSS pattern, an SFC shape) belongs in ESLint, `tsconfig`, or Trunk. When a review finding repeats, propose a check as a named follow-up; see `review-polish`.\n**Keep comments short.** Comments should be concise, and focus on the \"why\" rather than the \"what\" (the code itself is the \"what\"). A comment is one or two lines; a docstring is one sentence plus `Args:`/`Returns:` when the signature needs it. Three or more lines of prose means you are explaining, not commenting. See `review-polish` for what to cut.\n**Don't restate the code.** The code is self-documenting, so skip comments that narrate what a reader can already see (which button sits where, that something is disabled when empty, obvious ordering). Comment only non-obvious \"why\" that the code can't convey on its own.\n**One home per value.** Before declaring a constant, type, limit, regex, or store getter, search for an existing one and import it. Validation limits live on the model and are imported by endpoints; a type lives in the component that owns it and is exported. Don't add a near-duplicate that differs only by sorting, and don't invent an identity scheme where a foreign key already exists.\n**Never commit secrets.** Never commit secrets (API keys, passwords, tokens, etc.) to the repo. Use environment variables or secret management tools instead.\n**Don't explain a change.** Avoid comments that explain why a change was made to the code, or that record what the code used to do. Focus instead on the current behaviour of the code and how it works. Reasons for a change go in the commit message and the PR body.\n**Python tools live in `backend/tools/`.** Standalone dev/test utilities and scripts (not part of the app runtime) go in `backend/tools/`, not scattered across `backend/`.\n**Link PRs to issues.** In the PR description, use `Fixes #XXXX` for issue/bug fixes and `Closes #XXXX` for feature implementations.\n**Use the PR template.** Base every PR description on `.github/PULL_REQUEST_TEMPLATE.md`.\n**Show UI changes in the PR.** A PR that touches anything visible ships with at least one screenshot under the template's `Screenshots` heading, captured from the running app during the `review-polish` browser pass. Enough shots to convey what changed, not a catalogue of every state. Save the files outside the repo and never commit them, and upload them with `gh pr create --attach` (or `gh pr edit --attach` on an existing PR) rather than handing the paths to the user.\n**Diagram architectural changes in the PR.** When a change moves a boundary (a new service, task, or provider in a path, a model relationship, a different call path across layers, an auth or socket flow), the PR description carries a `mermaid` block showing it. GitHub renders them. Draw what changed, not the whole system. See `review-polish`.\n\n---\n\n## Never run the full backend test suite locally\n\nA bare `uv run pytest` (or `pytest -vv`) over `backend/` runs serially, takes 20+ minutes, and\nburns a huge number of tokens on output. Don't do it, even to \"double check\" at the end.\n\nInstead, select the tests affected by the change and run only those. Add `-n auto` when the\nselection spans a directory or more: the suite is set up for `pytest-xdist` (one database per\nworker).\n\n```bash\ncd backend\nuv run pytest tests/path/to/test_file.py                # one file\nuv run pytest tests/path/to/test_file.py::test_name     # one test\nuv run pytest -n auto tests/handler/ tests/endpoints/   # affected areas, in parallel\nuv run pytest -k \"scan or queue\"                        # by name pattern\n```\n\nIt gains nothing on a single file or test, and `--pdb` and `-s` don't work under it, so drop it\nwhen debugging.\n\nPick the targets from the diff: the test file mirroring each changed module\n(`backend/<area>/x.py` → `backend/tests/<area>/test_x.py`), plus the tests of the\ncallers of anything whose signature or behavior you changed (`grep` for the symbol).\n\nCI runs the whole suite on the PR (`pytest.yml`, MariaDB + PostgreSQL). That is the\nplace for full-suite coverage; local runs stay scoped.\n\n**In a git worktree, run tests against a temporary database.** Every checkout shares\n`romm_test`, and one on another branch can migrate it to a revision yours lacks, so\nevery test errors in setup with `Can't locate revision`. Set `ROMM_TEST_DB_TAG` to a\ntag unique to the worktree: the run creates and migrates `romm_test_tmp_<tag>` (one per\nxdist worker), then drops it at the end. Never `stamp` or downgrade the shared `romm_test`.\n\n```bash\nROMM_TEST_DB_TAG=my_worktree uv run pytest -n auto tests/handler/\n```\n\n---\n\n## Environment setup\n\nEach tool version is pinned in one file: Python in `.python-version`, uv as `ARG UV_VERSION` in `docker/Dockerfile`, and Node in `frontend/.nvmrc`. Don't install these by hand. Run `scripts/dev-setup.sh`, which installs the pinned toolchain, the backend and frontend dependencies, and the Trunk launcher, and skips anything already in place. Add `--db` to also install and start MariaDB with the pytest database (Debian/Ubuntu only). Rerun it whenever a version is wrong or a dependency is missing.\n\nIn Claude Code cloud sessions, `.claude/hooks/cloud-setup.sh` runs `scripts/dev-setup.sh --db` at session start. Setting the environment's setup script to `bash /home/user/romm/scripts/dev-setup.sh --db || true` gets the install cached in the environment snapshot, so the hook only has to restart MariaDB. The setup script doesn't run from the repo root and `CLAUDE_PROJECT_DIR` isn't set yet, so the path must be absolute. The cloud clone lives at `/home/user/<repo-name>`; adjust the path for a renamed fork. `|| true` keeps a failed install from blocking the session (the hook retries it). Other agents should run `scripts/dev-setup.sh --db` from the repo root as their setup step.\n\n---\n\n## Quick command reference\n\n**Setup:** see `DEVELOPER_SETUP.md`. Docker path is `cp env.template .env` → `docker compose build` → `docker compose up -d` (app at `http://localhost:3000`).\n\n**Lint (both stacks):** `trunk fmt && trunk check`.\n",".cursor/mcp.json":"# Model Context Protocol (MCP) Configuration\n\nPath: `.cursor/mcp.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/rommapp/romm/HEAD/.cursor/mcp.json)",".claude-plugin/marketplace.json":"# Claude Plugin Marketplace Catalog\n\nPath: `.claude-plugin/marketplace.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/rommapp/romm/HEAD/.claude-plugin/marketplace.json)",".claude-plugin/plugin.json":"# claude-plugin Plugin Manifest\n\nPath: `.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/rommapp/romm/HEAD/.claude-plugin/plugin.json)"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/rommapp/romm/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# RomM - Repository Guide for Contributors & Agents\n\nRomM is a self-hosted ROM manager and player: scan a game library off disk, enrich it with metadata from 10+ providers, browse it in a web UI, and play in the browser.\n\n---\n\nThe frontend talks to the backend over `/api/*` (REST) and `/ws` (Socket.IO). TypeScript types are **generated** from the backend's OpenAPI schema into `frontend/src/__generated__/` - the backend is the single source of truth for API shapes.\n\n## Deep-dive references\n\n- **`docs/BACKEND_ARCHITECTURE.md`** - directory map, ER diagram, every endpoint, auth/scopes, tasks.\n- **`docs/FRONTEND_ARCHITECTURE.md`** - routing, stores, services, theming, build tooling.\n- **`DEVELOPER_SETUP.md`** - Docker and manual local setup (mock library, `.env`, services).\n- **`CONTRIBUTING.md`** - contribution flow, **AI-assistance disclosure**, translations.\n\n---\n\n## Stack-specific guidance\n\n`frontend/AGENTS.md` (v1 vs v2, frontend commands) and `backend/AGENTS.md` (backend commands) load when you work in those directories. New frontend work goes in v2 (`frontend/src/v2/`); v1 is frozen.\n\n---\n\n## Skills - load the focused guide for your task\n\nThese live in `.claude/skills/` and carry the detailed rules. Invoke the one that matches what you're doing. `pr-ready`, `address-bot-reviews`, and `draft-announcement` are run by the user, not auto-invoked.\n\n---\n\n## Repo-wide rules\n\n**Disclose AI assistance in the PR.** RomM requires it (see `CONTRIBUTING.md`): state that AI was used and to what extent. This is mandatory and non-negotiable for agent-written contributions.\n**Branch off `master`; open PRs against `master`.** Fork → feature branch → PR. Don't push to `master`.\n**Linting is via [Trunk](https://trunk.io)** (`trunk fmt && trunk check`), which wraps ruff, black, isort, ESLint, Prettier, and more, and runs in CI on every PR. **Never commit with `--no-verify`.**\n**The backend owns the API contract.** Changed a response schema or route? Regenerate frontend types (`npm run generate`) and re-typecheck.\n**Tests travel with code.** New logic gets a test; new endpoints get endpoint tests; new v2 primitives get a Storybook story (+ `play()` if interactive).\n**Verify before handoff.** Don't say \"done\" on UI work without testing it in the browser in both themes and all input modalities. See `review-polish`.\n**English first.** Outside of language files, all code, comments, identifiers, `.md` files, and commit/PR messages are in English.\n**No em-dashes.** Never use em-dashes (U+2014) when writing comments or text. Use commas, parentheses, or separate sentences instead. An em-dash string literal is code (an empty-value glyph) and stays allowed.\n**Prefer a check to a model review.** A mechanical rule (an import, a character, a CSS pattern, an SFC shape) belongs in ESLint, `tsconfig`, or Trunk. When a review finding repeats, propose a check as a named follow-up; see `review-polish`.\n**Keep comments short.** Comments should be concise, and focus on the \"why\" rather than the \"what\" (the code itself is the \"what\"). A comment is one or two lines; a docstring is one sentence plus `Args:`/`Returns:` when the signature needs it. Three or more lines of prose means you are explaining, not commenting. See `review-polish` for what to cut.\n**Don't restate the code.** The code is self-documenting, so skip comments that narrate what a reader can already see (which button sits where, that something is disabled when empty, obvious ordering). Comment only non-obvious \"why\" that the code can't convey on its own.\n**One home per value.** Before declaring a constant, type, limit, regex, or store getter, search for an existing one and import it. Validation limits live on the model and are imported by endpoints; a type lives in the component that owns it and is exported. Don't add a near-duplicate that differs only by sorting, and don't invent an identity scheme where a foreign key already exists.\n**Never commit secrets.** Never commit secrets (API keys, passwords, tokens, etc.) to the repo. Use environment variables or secret management tools instead.\n**Don't explain a change.** Avoid comments that explain why a change was made to the code, or that record what the code used to do. Focus instead on the current behaviour of the code and how it works. Reasons for a change go in the commit message and the PR body.\n**Python tools live in `backend/tools/`.** Standalone dev/test utilities and scripts (not part of the app runtime) go in `backend/tools/`, not scattered across `backend/`.\n**Link PRs to issues.** In the PR description, use `Fixes #XXXX` for issue/bug fixes and `Closes #XXXX` for feature implementations.\n**Use the PR template.** Base every PR description on `.github/PULL_REQUEST_TEMPLATE.md`.\n**Show UI changes in the PR.** A PR that touches anything visible ships with at least one screenshot under the template's `Screenshots` heading, captured from the running app during the `review-polish` browser pass. Enough shots to convey what changed, not a catalogue of every state. Save the files outside the repo and never commit them, and upload them with `gh pr create --attach` (or `gh pr edit --attach` on an existing PR) rather than handing the paths to the user.\n**Diagram architectural changes in the PR.** When a change moves a boundary (a new service, task, or provider in a path, a model relationship, a different call path across layers, an auth or socket flow), the PR description carries a `mermaid` block showing it. GitHub renders them. Draw what changed, not the whole system. See `review-polish`.\n\n---\n\n## Never run the full backend test suite locally\n\nA bare `uv run pytest` (or `pytest -vv`) over `backend/` runs serially, takes 20+ minutes, and\nburns a huge number of tokens on output. Don't do it, even to \"double check\" at the end.\n\nInstead, select the tests affected by the change and run only those. Add `-n auto` when the\nselection spans a directory or more: the suite is set up for `pytest-xdist` (one database per\nworker).\n\n```bash\ncd backend\nuv run pytest tests/path/to/test_file.py                # one file\nuv run pytest tests/path/to/test_file.py::test_name     # one test\nuv run pytest -n auto tests/handler/ tests/endpoints/   # affected areas, in parallel\nuv run pytest -k \"scan or queue\"                        # by name pattern\n```\n\nIt gains nothing on a single file or test, and `--pdb` and `-s` don't work under it, so drop it\nwhen debugging.\n\nPick the targets from the diff: the test file mirroring each changed module\n(`backend/<area>/x.py` → `backend/tests/<area>/test_x.py`), plus the tests of the\ncallers of anything whose signature or behavior you changed (`grep` for the symbol).\n\nCI runs the whole suite on the PR (`pytest.yml`, MariaDB + PostgreSQL). That is the\nplace for full-suite coverage; local runs stay scoped.\n\n**In a git worktree, run tests against a temporary database.** Every checkout shares\n`romm_test`, and one on another branch can migrate it to a revision yours lacks, so\nevery test errors in setup with `Can't locate revision`. Set `ROMM_TEST_DB_TAG` to a\ntag unique to the worktree: the run creates and migrates `romm_test_tmp_<tag>` (one per\nxdist worker), then drops it at the end. Never `stamp` or downgrade the shared `romm_test`.\n\n```bash\nROMM_TEST_DB_TAG=my_worktree uv run pytest -n auto tests/handler/\n```\n\n---\n\n## Environment setup\n\nEach tool version is pinned in one file: Python in `.python-version`, uv as `ARG UV_VERSION` in `docker/Dockerfile`, and Node in `frontend/.nvmrc`. Don't install these by hand. Run `scripts/dev-setup.sh`, which installs the pinned toolchain, the backend and frontend dependencies, and the Trunk launcher, and skips anything already in place. Add `--db` to also install and start MariaDB with the pytest database (Debian/Ubuntu only). Rerun it whenever a version is wrong or a dependency is missing.\n\nIn Claude Code cloud sessions, `.claude/hooks/cloud-setup.sh` runs `scripts/dev-setup.sh --db` at session start. Setting the environment's setup script to `bash /home/user/romm/scripts/dev-setup.sh --db || true` gets the install cached in the environment snapshot, so the hook only has to restart MariaDB. The setup script doesn't run from the repo root and `CLAUDE_PROJECT_DIR` isn't set yet, so the path must be absolute. The cloud clone lives at `/home/user/<repo-name>`; adjust the path for a renamed fork. `|| true` keeps a failed install from blocking the session (the hook retries it). Other agents should run `scripts/dev-setup.sh --db` from the repo root as their setup step.\n\n---\n\n## Quick command reference\n\n**Setup:** see `DEVELOPER_SETUP.md`. Docker path is `cp env.template .env` → `docker compose build` → `docker compose up -d` (app at `http://localhost:3000`).\n\n**Lint (both stacks):** `trunk fmt && trunk check`.\n","isInternal":false,"tokens":2142,"sizeBytes":8799},{"name":"marketplace.json","path":".claude-plugin/marketplace.json","rawUrl":"https://raw.githubusercontent.com/rommapp/romm/HEAD/.claude-plugin/marketplace.json","title":"Claude Plugin Marketplace Catalog","category":"marketplace","format":"json","content":"# Claude Plugin Marketplace Catalog\n\nPath: `.claude-plugin/marketplace.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/rommapp/romm/HEAD/.claude-plugin/marketplace.json)","tokens":300,"sizeBytes":191},{"name":"plugin.json","path":".claude-plugin/plugin.json","rawUrl":"https://raw.githubusercontent.com/rommapp/romm/HEAD/.claude-plugin/plugin.json","title":"claude-plugin Plugin Manifest","category":"plugin-manifest","format":"json","content":"# claude-plugin Plugin Manifest\n\nPath: `.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/rommapp/romm/HEAD/.claude-plugin/plugin.json)","tokens":300,"sizeBytes":177},{"name":"mcp.json","path":".cursor/mcp.json","rawUrl":"https://raw.githubusercontent.com/rommapp/romm/HEAD/.cursor/mcp.json","title":"Model Context Protocol (MCP) Configuration","category":"mcp-config","format":"json","content":"# Model Context Protocol (MCP) Configuration\n\nPath: `.cursor/mcp.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/rommapp/romm/HEAD/.cursor/mcp.json)","tokens":300,"sizeBytes":170}],"systemPromptSnippet":"<yakaai_skills repo=\"rommapp/romm\">\n<!-- File: AGENTS.md (Tokens: ~2142 | Category: root-instruction) -->\n# RomM - Repository Guide for Contributors & Agents\n\nRomM is a self-hosted ROM manager and player: scan a game library off disk, enrich it with metadata from 10+ providers, browse it in a web UI, and play in the browser.\n\n---\n\nThe frontend talks to the backend over `/api/*` (REST) and `/ws` (Socket.IO). TypeScript types are **generated** from the backend's OpenAPI schema into `frontend/src/__generated__/` - the backend is the single source of truth for API shapes.\n\n## Deep-dive references\n\n- **`docs/BACKEND_ARCHITECTURE.md`** - directory map, ER diagram, every endpoint, auth/scopes, tasks.\n- **`docs/FRONTEND_ARCHITECTURE.md`** - routing, stores, services, theming, build tooling.\n- **`DEVELOPER_SETUP.md`** - Docker and manual local setup (mock library, `.env`, services).\n- **`CONTRIBUTING.md`** - contribution flow, **AI-assistance disclosure**, translations.\n\n---\n\n## Stack-specific guidance\n\n`frontend/AGENTS.md` (v1 vs v2, frontend commands) and `backend/AGENTS.md` (backend commands) load when you work in those directories. New frontend work goes in v2 (`frontend/src/v2/`); v1 is frozen.\n\n---\n\n## Skills - load the focused guide for your task\n\nThese live in `.claude/skills/` and carry the detailed rules. Invoke the one that matches what you're doing. `pr-ready`, `address-bot-reviews`, and `draft-announcement` are run by the user, not auto-invoked.\n\n---\n\n## Repo-wide rules\n\n**Disclose AI assistance in the PR.** RomM requires it (see `CONTRIBUTING.md`): state that AI was used and to what extent. This is mandatory and non-negotiable for agent-written contributions.\n**Branch off `master`; open PRs against `master`.** Fork → feature branch → PR. Don't push to `master`.\n**Linting is via [Trunk](https://trunk.io)** (`trunk fmt && trunk check`), which wraps ruff, black, isort, ESLint, Prettier, and more, and runs in CI on every PR. **Never commit with `--no-verify`.**\n**The backend owns the API contract.** Changed a response schema or route? Regenerate frontend types (`npm run generate`) and re-typecheck.\n**Tests travel with code.** New logic gets a test; new endpoints get endpoint tests; new v2 primitives get a Storybook story (+ `play()` if interactive).\n**Verify before handoff.** Don't say \"done\" on UI work without testing it in the browser in both themes and all input modalities. See `review-polish`.\n**English first.** Outside of language files, all code, comments, identifiers, `.md` files, and commit/PR messages are in English.\n**No em-dashes.** Never use em-dashes (U+2014) when writing comments or text. Use commas, parentheses, or separate sentences instead. An em-dash string literal is code (an empty-value glyph) and stays allowed.\n**Prefer a check to a model review.** A mechanical rule (an import, a character, a CSS pattern, an SFC shape) belongs in ESLint, `tsconfig`, or Trunk. When a review finding repeats, propose a check as a named follow-up; see `review-polish`.\n**Keep comments short.** Comments should be concise, and focus on the \"why\" rather than the \"what\" (the code itself is the \"what\"). A comment is one or two lines; a docstring is one sentence plus `Args:`/`Returns:` when the signature needs it. Three or more lines of prose means you are explaining, not commenting. See `review-polish` for what to cut.\n**Don't restate the code.** The code is self-documenting, so skip comments that narrate what a reader can already see (which button sits where, that something is disabled when empty, obvious ordering). Comment only non-obvious \"why\" that the code can't convey on its own.\n**One home per value.** Before declaring a constant, type, limit, regex, or store getter, search for an existing one and import it. Validation limits live on the model and are imported by endpoints; a type lives in the component that owns it and is exported. Don't add a near-duplicate that differs only by sorting, and don't invent an identity scheme where a foreign key already exists.\n**Never commit secrets.** Never commit secrets (API keys, passwords, tokens, etc.) to the repo. Use environment variables or secret management tools instead.\n**Don't explain a change.** Avoid comments that explain why a change was made to the code, or that record what the code used to do. Focus instead on the current behaviour of the code and how it works. Reasons for a change go in the commit message and the PR body.\n**Python tools live in `backend/tools/`.** Standalone dev/test utilities and scripts (not part of the app runtime) go in `backend/tools/`, not scattered across `backend/`.\n**Link PRs to issues.** In the PR description, use `Fixes #XXXX` for issue/bug fixes and `Closes #XXXX` for feature implementations.\n**Use the PR template.** Base every PR description on `.github/PULL_REQUEST_TEMPLATE.md`.\n**Show UI changes in the PR.** A PR that touches anything visible ships with at least one screenshot under the template's `Screenshots` heading, captured from the running app during the `review-polish` browser pass. Enough shots to convey what changed, not a catalogue of every state. Save the files outside the repo and never commit them, and upload them with `gh pr create --attach` (or `gh pr edit --attach` on an existing PR) rather than handing the paths to the user.\n**Diagram architectural changes in the PR.** When a change moves a boundary (a new service, task, or provider in a path, a model relationship, a different call path across layers, an auth or socket flow), the PR description carries a `mermaid` block showing it. GitHub renders them. Draw what changed, not the whole system. See `review-polish`.\n\n---\n\n## Never run the full backend test suite locally\n\nA bare `uv run pytest` (or `pytest -vv`) over `backend/` runs serially, takes 20+ minutes, and\nburns a huge number of tokens on output. Don't do it, even to \"double check\" at the end.\n\nInstead, select the tests affected by the change and run only those. Add `-n auto` when the\nselection spans a directory or more: the suite is set up for `pytest-xdist` (one database per\nworker).\n\n```bash\ncd backend\nuv run pytest tests/path/to/test_file.py                # one file\nuv run pytest tests/path/to/test_file.py::test_name     # one test\nuv run pytest -n auto tests/handler/ tests/endpoints/   # affected areas, in parallel\nuv run pytest -k \"scan or queue\"                        # by name pattern\n```\n\nIt gains nothing on a single file or test, and `--pdb` and `-s` don't work under it, so drop it\nwhen debugging.\n\nPick the targets from the diff: the test file mirroring each changed module\n(`backend/<area>/x.py` → `backend/tests/<area>/test_x.py`), plus the tests of the\ncallers of anything whose signature or behavior you changed (`grep` for the symbol).\n\nCI runs the whole suite on the PR (`pytest.yml`, MariaDB + PostgreSQL). That is the\nplace for full-suite coverage; local runs stay scoped.\n\n**In a git worktree, run tests against a temporary database.** Every checkout shares\n`romm_test`, and one on another branch can migrate it to a revision yours lacks, so\nevery test errors in setup with `Can't locate revision`. Set `ROMM_TEST_DB_TAG` to a\ntag unique to the worktree: the run creates and migrates `romm_test_tmp_<tag>` (one per\nxdist worker), then drops it at the end. Never `stamp` or downgrade the shared `romm_test`.\n\n```bash\nROMM_TEST_DB_TAG=my_worktree uv run pytest -n auto tests/handler/\n```\n\n---\n\n## Environment setup\n\nEach tool version is pinned in one file: Python in `.python-version`, uv as `ARG UV_VERSION` in `docker/Dockerfile`, and Node in `frontend/.nvmrc`. Don't install these by hand. Run `scripts/dev-setup.sh`, which installs the pinned toolchain, the backend and frontend dependencies, and the Trunk launcher, and skips anything already in place. Add `--db` to also install and start MariaDB with the pytest database (Debian/Ubuntu only). Rerun it whenever a version is wrong or a dependency is missing.\n\nIn Claude Code cloud sessions, `.claude/hooks/cloud-setup.sh` runs `scripts/dev-setup.sh --db` at session start. Setting the environment's setup script to `bash /home/user/romm/scripts/dev-setup.sh --db || true` gets the install cached in the environment snapshot, so the hook only has to restart MariaDB. The setup script doesn't run from the repo root and `CLAUDE_PROJECT_DIR` isn't set yet, so the path must be absolute. The cloud clone lives at `/home/user/<repo-name>`; adjust the path for a renamed fork. `|| true` keeps a failed install from blocking the session (the hook retries it). Other agents should run `scripts/dev-setup.sh --db` from the repo root as their setup step.\n\n---\n\n## Quick command reference\n\n**Setup:** see `DEVELOPER_SETUP.md`. Docker path is `cp env.template .env` → `docker compose build` → `docker compose up -d` (app at `http://localhost:3000`).\n\n**Lint (both stacks):** `trunk fmt && trunk check`.\n\n<!-- File: .claude-plugin/marketplace.json (Tokens: ~300 | Category: marketplace) -->\n# Claude Plugin Marketplace Catalog\n\nPath: `.claude-plugin/marketplace.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/rommapp/romm/HEAD/.claude-plugin/marketplace.json)\n\n<!-- File: .claude-plugin/plugin.json (Tokens: ~300 | Category: plugin-manifest) -->\n# claude-plugin Plugin Manifest\n\nPath: `.claude-plugin/plugin.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/rommapp/romm/HEAD/.claude-plugin/plugin.json)\n\n<!-- File: .cursor/mcp.json (Tokens: ~300 | Category: mcp-config) -->\n# Model Context Protocol (MCP) Configuration\n\nPath: `.cursor/mcp.json`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/rommapp/romm/HEAD/.cursor/mcp.json)\n</yakaai_skills>"}