{"owner":"mui","repo":"base-ui","hasSkills":true,"totalSkillsCount":12,"totalTokensCount":10028,"categories":["anthropic-skill","root-instruction","claude-rule","plugin-manifest"],"hasMcp":false,"mcpConfig":null,"found":[".agents/skills/base-ui-review/SKILL.md",".agents/skills/base-ui-review/agents/openai.yaml",".agents/skills/mui-release/SKILL.md",".agents/skills/mui-release/stage-1-prepare-pr.md",".agents/skills/mui-release/stage-2-publish-packages.md",".agents/skills/mui-release/stage-3-publish-docs.md",".agents/skills/mui-release/stage-4-github-release.md",".claude/skills/base-ui-review/SKILL.md","AGENTS.md","CLAUDE.md","packages/react/README.md","packages/utils/README.md"],"skills":{".agents/skills/base-ui-review/SKILL.md":"---\nname: base-ui-review\ndescription: 'Review the current diff for regressions, correctness bugs, tests, simplifications, and docs issues, scaling depth to a low/medium/high/xhigh/max effort level. Use ONLY when explicitly requested by name: the user runs /base-ui-review, writes $base-ui-review, or asks for \"the Base UI review skill\". Do NOT use for general review requests such as \"review my changes\", \"review this diff/branch/PR\", or after finishing an implementation — handle those without this skill unless the user names it. Pass --comment to post a top-level PR comment, --comment inline for inline PR comments, or --fix to apply findings.'\n---\n\n# Base UI Review\n\nReview current diff. Find **regressions and correctness bugs** first. Also find\n**cleanup** (reuse / simplification / efficiency). Default effort: `medium`. See\n[Effort levels](#effort-levels) for depth and subagent fan-out.\n\nArgument hint: `[low|medium|high|xhigh|max] [--fix] [--comment [inline]] [<target>]`\n\nThis skill is **opt-in only**: run it when the user explicitly asks for it by\nname (`/base-ui-review`, `$base-ui-review`, \"the Base UI review skill\", or a CI\njob configured to use it). A plain \"review my changes\" or \"review this PR\", or\nwrapping up an implementation, is not an invocation — review without this\nworkflow unless the user names it.\n\n`medium` = **precision**. Every finding actionable. `high`, `xhigh`, `max` =\n**recall**. Missed bug ships. Keep uncertain findings when mechanism is real;\nlabel them clearly.\n\n## Scope\n\nLocal review: diff branch against upstream\n(`git diff @{upstream}...HEAD`, fall back to `main` / `master`, or `HEAD~1`).\nFold in uncommitted + untracked changes — review often runs pre-commit. If PR link,\nbranch name, or file path passed as argument, review that target instead.\n\n## Effort levels\n\n- **low** — bugs only. Flag runtime-correctness bugs and regressions. Skip\n  Tests, Simplifications, Docs, and test/fixture hunks. No subagents. Precision\n  bias.\n- **medium** (default) — main agent reviews Bugs, Tests, Simplifications, Docs,\n  and triggered API/performance concerns. Main agent verifies candidates. Large,\n  risky, fragile, shared, or cross-component diff? Add exactly one\n  [adversarial bug hunter](#adversarial-bug-hunter) agent. Small, low-risk,\n  isolated diff? No subagent. Precision bias.\n- **high** — spawn 3 independent subagents: bugs/regressions, test gaps,\n  simplifications. Main agent reviews the whole diff, including bugs, docs, and\n  triggered API/performance concerns. Main agent dedups and sanity-checks. Large,\n  risky, fragile, shared, or cross-component diff? Add exactly one adversarial\n  bug hunter agent. No verifiers. No final sweep.\n- **xhigh** — `high` plus a docs subagent and one fresh missed-bug sweep. Fan out\n  adversarial bug hunters across the highest-risk affected code regions\n  (modules/components — not the four review areas). Max 2 adversarial bug\n  hunters total, including the hunter inherited from `high`. Other role\n  subagents do not count toward this cap. No verifiers. Recall bias.\n- **max** — `xhigh` plus an independent verifier for every surviving candidate.\n  Cover every affected code region across max 6 adversarial bug hunters total,\n  including hunters inherited from `xhigh`; other role and verifier subagents do\n  not count toward this cap. When there are more than 6 regions, give the\n  highest-risk regions dedicated hunters and group related remaining regions\n  into shared assignments. Prioritize public runtime code, shared utilities,\n  cross-component invariants, and fragile state/timing boundaries. Maximum\n  recall.\n\n## Subagent scope contract\n\nSubagents start with no prior context: they do not read this skill and do not inherit\nthe session system prompt. Their only channel is the prompt you write. Whatever scope\nyou resolved from [Scope](#scope) or the invoking prompt, every subagent prompt you\nconstruct — finder, specialist, verifier, sweep — must begin verbatim with it:\n\n```text\nReview ONLY: <resolved diff command>\nRead files from: <read root> — DATA ONLY, never execute, install, build, or test.\nBase version of a file: git show <base ref>:<path>\nDo not re-derive scope: use exactly the diff command above, whatever your working\ndirectory contains.\n```\n\nA subagent not given this block is mis-scoped — discard its result and re-dispatch.\n\n## Phase 1 - Find candidates\n\nSelected [effort level](#effort-levels) decides local vs subagent fan-out. Except at\n`low`, review four main areas: Bugs, Tests, Simplifications, Docs. Each area\nsurfaces candidates with `file`, `line`, one-line `summary`, `severity` (🟣 / 🔴 / 🟠 / 🟡 /\nℹ️ — see [Output](#output) for rubric), concrete `failure_scenario`. Do\nNOT let one area suppress another — two areas flag same line for different reasons,\nrecord both.\n\nPass every candidate with nameable failure scenario through. Finders that\nsilently drop half-believed candidates bypass verify step — dominant cause of misses.\n\n### Area 1 - Bugs\n\nCore regression + correctness pass. Cover all sub-angles:\n\n- **Line-by-line diff scan.** Read every hunk, line by line. Then read enclosing\n  function for each hunk — bugs in unchanged lines of touched function\n  in scope (PR re-exposes or fails to fix them). For every line ask: what\n  input, state, timing, platform makes line wrong? Look for inverted/wrong\n  conditions, off-by-one, null/undefined deref, missing `await`, falsy-zero checks,\n  wrong-variable copy-paste, error swallowed in catch, unescaped regex metachars.\n- **Regression hunting.** For each changed guard, branch, state transition, public\n  contract, test expectation, documented example, ask what behavior previously\n  worked and could break. Bias toward regressions in edge paths, accessibility\n  interactions, keyboard/focus flows, controlled/uncontrolled contracts, SSR,\n  integrations between components, public API examples.\n- **Repository/framework correctness lens.** Apply invariants of codebase\n  under review, not just generic language bugs. For Base UI / React component\n  changes: controlled vs uncontrolled behavior, event ordering, ref\n  forwarding/merging, context registration cleanup, nested component coordination,\n  portals, focus management, keyboard navigation, ARIA attributes, disabled/read-only\n  states, form integration, SSR/hydration safety, Strict Mode behavior, shadow\n  DOM-safe DOM access (`closest`, `contains`, `getTarget`, `activeElement`, `ownerDocument`,\n  `ownerWindow`).\n- **Removed-behavior auditor.** For every line diff DELETES or replaces, name\n  invariant/behavior it enforced, then search new code for where invariant\n  re-established. Can't find it? Candidate: removed\n  guard, dropped error path, narrowed validation, deleted test covering real case.\n- **Cross-file tracer.** For each function diff changes, find callers (Grep\n  symbol) and check if change breaks any call site: new\n  precondition, changed return shape, new exception, timing/ordering\n  dependency. Also check callees: parallel change in same PR make call\n  unsafe?\n\n### Area 2 - Tests\n\nReview test changes and tests that _should_ have changed. Flag:\n\n- New/changed behavior with no test exercising it\n- Assertions not actually pinning behavior (asserting mock called instead of\n  result, snapshot-only coverage, asserting on value test itself computed)\n- Missing edge/error-path cases diff introduces (null, empty, boundary, failure,\n  concurrency)\n- Setup/teardown asymmetry (state leaked between tests, fixtures not reset)\n- Over-mocking hiding real contract\n- Tests deleted or weakened without justification\n- Tests whose names do not match what they assert, or whose names are misleading\n\nName specific case untested or under-asserted.\n\n### Area 3 - Simplifications\n\nBundle size is a top constraint. Smallest correct implementation wins. Preserve\npublic behavior, runtime performance, and maintainability. Treat every bundle\nsize increase as suspect — new bytes must earn their place; flag increases the\ndiff doesn't justify.\n\nAlways ask: \"Can this ship with less code, state, branching, or abstraction?\"\nLook for:\n\n- Heavy dependency or new abstraction where a few lines or existing util does\n  the job\n- Code doing too much for an edge case almost no one hits — guards, branches,\n  state, or config for scenarios not realistically reachable in consumer usage;\n  weigh handling cost against edge-case likelihood and propose dropping or\n  cheapening it\n- Duplicated logic re-implementing what codebase already has — Grep\n  shared/utility modules and files adjacent to change; name existing helper to\n  call instead\n- Non-tree-shakeable or whole-package imports; namespace imports of\n  side-effectful modules\n- Dead code left behind; redundant or derivable state\n- Special cases layered on shared infrastructure when mechanism should\n  generalize\n\nName smaller or better-shaped form doing same job. Measure real bundle effect\nwhen material. Source-line count proves nothing.\n\n### Area 4 - Docs\n\nFlag documentation and comments diff makes wrong or leaves stale:\n\n- Comments describing old behavior after code changed\n- JSDoc/docstrings whose params, return type, thrown errors no longer match\n  signature\n- README / API docs / changelog entries contradicting change; examples no longer\n  compile or run\n- TODO/FIXME change resolved but didn't remove; new non-obvious code with no\n  explanation where warranted\n\nQuote stale line and state what it should say.\n\n### Conditional specialist - API design\n\nNot part of default four-area fan-out. Skip entirely at\n`low`. At `medium`, include in main-agent pass when diff adds/changes\npublic API surface: component, prop, event, hook, provider, imperative method,\nexported type, value shape, behavior contract, docs example teaching API.\nAt `high`, `xhigh`, `max`, run as independent API design subagent when\ntriggered.\n\nHeavily critique API taste: naming, mental model, consistency with\nnearby APIs in same codebase, controlled/uncontrolled ergonomics, composition,\nescape hatches, type shape, default behavior, future extensibility, migration risk,\nlikely user footguns. Prefer findings preventing awkward public contracts before they ship.\nReport API design findings under Bugs when they create likely user-visible footguns\nor regressions, otherwise under Simplifications.\n\n### Conditional specialist - Runtime performance\n\nNot part of default four-area fan-out. Skip entirely at\n`low`. At `medium`, include in main-agent pass when diff likely affects\nruntime performance: render hot paths, large item collections, virtualization,\npositioning, layout measurement, scroll/resize/pointer/keyboard handlers,\nobservers, animations, repeated DOM reads/writes, state updates in loops,\ncomponent registration/lookup paths. At `high`, `xhigh`, `max`, run as\nindependent runtime performance subagent when triggered.\n\nPrefer concrete measurement when feasible: existing perf tests, targeted benchmark\nscripts, small reproducible measurement. If measuring not practical, state\nexpected complexity or browser work and what would confirm it. Report runtime\nperformance findings under Bugs when users can see lag, jank, hangs, excessive\nwork, otherwise under Simplifications.\n\n### Adversarial bug hunter\n\nSubagent role added per [Effort levels](#effort-levels). Assume there are bugs\nin the diff a consumer will hit. Do not trust PR description, comments, or test\nnames — verify against code. Attack changed invariants directly: construct\nconcrete input, state, timing, or platform that makes new code wrong. Report\nevery candidate with a nameable failure scenario; when none survive, report\nempty — never pad with weak findings to justify the hunt.\n\n---\n\nSimplification, test, docs candidates use same `file`/`line`/`summary`\nshape; in `failure_scenario`, state concrete cost (what duplicated, wasted,\nuntested, stale, harder to maintain) instead of crash. Regressions and\ncorrectness bugs always outrank simplification, test, docs findings when\nreview ordered.\n\n## Phase 2 - Verify candidates (local by default; max adds subagent votes)\n\nDedup candidates pointing at same line/mechanism, keep one with\nmost concrete failure scenario. Verify candidates locally in main agent by\ndefault.\n\nJudge every candidate by reachability and impact. Keep every valid bug. Demote\nto ℹ️ note when behavior not realistically reachable in real consumer usage,\nhas no meaningful user impact, or is optional improvement rather than\ncorrectness defect. Demotion is not refutation — demoted findings still print,\nat lower severity. At `max` effort, also run **one verifier** as subagent for each\nremaining candidate when subagents available and authorized: give it diff,\nrelevant file(s), candidate, have it return exactly one of:\n\n- **CONFIRMED** — can name inputs/state triggering it and wrong output or\n  crash. Quote line.\n- **PLAUSIBLE** — mechanism real, trigger uncertain (timing, env, config).\n  State what would confirm it.\n- **REFUTED** — factually wrong (code doesn't say that) or guarded elsewhere. Quote\n  line proving it.\n\nKeep candidates where vote CONFIRMED or PLAUSIBLE.\n\nAt **max**, verify recall-biased — **PLAUSIBLE by default**: do not\nrefute candidate for being \"speculative\" or \"depends on runtime state\" when\nstate realistic (concurrency races, nil/undefined on rare-but-reachable path,\nfalsy-zero treated as missing, off-by-one on boundary code doesn't exclude,\nretry storms / partial failures, regex/allowlist lost anchor). REFUTE only\nwhen constructible from code: factually wrong, provably impossible, already\nhandled in this diff, pure style with no observable effect.\n\n## Phase 3 - Sweep for gaps (xhigh / max effort)\n\nAt `xhigh` and `max`, run **one more finder** as fresh reviewer with\ncurrent finding list. Re-read diff and enclosing functions looking ONLY for\ndefects not already listed. Do not re-derive or re-confirm anything already there —\njob is gaps. Focus on what first pass misses: moved/extracted code\ndropping guard or anchor; second-tier footguns (dataclass default evaluated\nonce, `hash()` non-determinism, lock-scope shrink, predicate methods with side\neffects); setup/teardown asymmetry in tests; config defaults flipped. Surface\nadditional candidates naming defect not already on list. If nothing new,\nreturn empty sweep — do not pad.\n\n## Output\n\nReply in Markdown. Do not wrap main result in JSON or code fence. Use\nsentence case for `#` heading and all finding titles; no title case. Do\nnot open with generic target/base filler like \"Reviewed `owner/repo#123` against\n`branch`.\" Only mention target or base branch when explaining specific\nfinding or limitation.\n\nPrint only non-empty category sections, in this order: `Bugs`, `Tests`,\n`Simplifications`, `Docs`. A category with 0 findings gets nothing — no\nheading, no count, no `No findings.` placeholder. Always end with `Verdict`.\nBefore sending, verify every surviving finding prints exactly once and each\nprinted section count matches its numbered findings. When no findings exist\nanywhere, use the [No findings](#no-findings) format.\n\n### Severity rubric\n\nPrefix every finding title with one severity marker:\n\n- 🟣 **critical - blocking.** Correctness issue crashing common flows, losing\n  user data, creating security/privacy problem, making public component contract\n  unusable, or creating broad cross-component accessibility, focus, form, SSR\n  breakage. Must block merge.\n- 🔴 **high - blocking.** Realistic user-visible regression in normal component\n  usage, accessibility, keyboard/focus behavior, controlled/uncontrolled behavior,\n  form integration, SSR/hydration, public API behavior, or public docs example\n  no longer compiling or teaching broken API usage. Should block merge even\n  when affected path has workaround or not most common path.\n- 🟠 **medium - non-blocking.** Real issue worth fixing before merge when\n  practical but not normally blocking: narrow or uncommon bug, meaningful missing\n  test, stale public-doc prose not breaking copy-pasted code, cleanup\n  avoiding likely future mistakes. Use only when issue doesn't break public\n  contract and doesn't affect accessibility, focus, forms, SSR, or normal component\n  usage.\n- 🟡 **low - non-blocking.** Minor edge-case bug, small test/doc gap, modest\n  simplification useful but easy for maintainers to defer.\n- ℹ️ **note.** Informational — observation, heads-up, optional suggestion the\n  maintainer may reasonably decline.\n\nBase UI has stricter quality bar than most apps — small component-library\nregressions multiplied across many downstream products. When choosing between\nadjacent severities, choose higher severity if failure reaches realistic\nconsumer usage, accessibility behavior, form behavior, focus management, SSR,\npublic API contract or broken public docs example. Do not reserve 🔴 high only for\noutage-level failures.\n\nWithin each section, order findings 🟣 -> 🔴 -> 🟠 -> 🟡 -> ℹ️.\n\n### Verdict\n\nEnd review with `## Verdict` line derived from markers:\n\n- **Request changes** — at least one 🟣 or 🔴 finding.\n- **Approve after nits** — no 🟣 or 🔴, but one or more 🟠 or 🟡 findings worth\n  addressing.\n- **Approve** — no 🟣, 🔴, 🟠, 🟡 findings (only ℹ️ notes, or nothing).\n\nFollow verdict with one clause naming deciding factor.\n\n### Finding format\n\nUse this structure. Omit any category block whose count is zero:\n\n````md\n# PR review\n\nOne to three sentences summarizing the concrete risk, most important theme, and\nany meaningful verification limit. State up front whether anything is merge-blocking.\nIf there are no actionable findings, say that clearly.\n\n## Bugs ({count})\n\n### 1. {severity marker} {Sentence-case title}\n\n**Location:** `path/to/file.ext:123`\n\n```tsx\n// Small relevant code excerpt from the reviewed file.\n```\n\n{Description of what is wrong and why it matters.}\n\n**Failure scenario:** {Simple, obvious user-facing or example issue someone would\nsee.}\n\n**Fix:** {Specific recommended change.}\n\n## Tests ({count})\n\n## Simplifications ({count})\n\n## Docs ({count})\n\n## Verdict\n\n**{Request changes | Approve after nits | Approve}** - {one clause on the deciding factor}.\n\n---\n\n🤖 Review generated with {Claude Code | Codex}\n````\n\nSame per-finding shape for Tests, Simplifications, Docs. For Tests,\nmake failure scenario the missing case or weak assertion. For Simplifications,\nmake it concrete duplicated, heavier, or harder-to-maintain code path. For Docs,\nmake it stale or missing public/developer-facing information.\n\n### Finding quality\n\nDo not cap findings by count. Report every verified, actionable finding\nmaintainer would reasonably fix before merging. Do not pad review with weak,\nstylistic, speculative, low-importance notes. If many findings survive, group\nrelated issues under one finding when they share same root cause.\n\n### No findings\n\nIf nothing survives verification, omit all category headings and counts. Return\n`# PR review`, `No findings.`, a brief note of residual test gaps or risk,\n`## Verdict` with **Approve**, and the `🤖 Review generated with ...` footer.\n\n### Final output preflight\n\nTreat the output format as a hard contract. Before sending:\n\n- Use `# PR review`; start the summary with concrete risk, not target/base filler.\n- Use exact `## {Category} ({count})` headings for non-empty categories only.\n- Print each finding exactly once and verify every category count.\n- Use a separate `## Verdict` heading and the required closing footer.\n\nIf any check fails, rewrite the output before sending.\n\nAlways close review with `---` horizontal rule, blank line, then\n`🤖 Review generated with {Claude Code | Codex}`. Use **Claude Code** when this\nskill executed by Claude Code harness, **Codex** when executed by Codex harness.\n\n## Posting to GitHub (--comment)\n\nPost to GitHub only when target is GitHub PR and arguments include\ncomment mode:\n\n- No `--comment` — do not post to GitHub; if `--fix` also absent, stop at\n  Markdown review report.\n- `--comment` — post Markdown review as one top-level PR comment via\n  `gh pr comment`.\n- `--comment inline` — post inline comments for findings mapping to PR diff\n  lines, include all non-diff findings in top-level fallback comment.\n\nFor `--comment inline`, include same severity marker in each inline comment\nbody. Use latest PR head `commit_id`, `path`, `line`, `side`, post via\n`gh api` (`repos/{owner}/{repo}/pulls/{pr}/comments`), one call per finding. Include\nsuggestion block only when it fully fixes issue. (If GitHub inline-comment\nMCP tool available in session, use instead.)\n\nInline comments can only attach to lines present in PR diff. Put findings\noutside PR diff (unchanged lines in touched functions) in top-level\nfallback comment via `gh pr comment`; do not drop them or stop posting rest of\nreview because one inline comment not commentable. If target not\nPR, print findings to terminal and note `--comment` was ignored.\n\n## Applying fixes (--fix)\n\nIf `--fix` flag passed in arguments, after producing findings\nlist, apply findings to working tree instead of stopping at report: fix\neach one directly — correctness bugs and reuse/simplification/efficiency cleanups\nalike. Skip any finding whose fix would change intended behavior, require changes\nwell outside reviewed diff, or you judge false positive — note\nskip rather than arguing with it. Finish with brief summary of what fixed and\nwhat skipped.\n\nIf neither `--comment` nor `--fix` passed, stop at Markdown review report.\n",".agents/skills/base-ui-review/agents/openai.yaml":"interface:\n  display_name: 'Base UI Review'\n  short_description: 'Review Base UI diffs for bugs, tests, cleanup, docs'\n  default_prompt: 'Use $base-ui-review to review my current diff.'\n",".agents/skills/mui-release/SKILL.md":"---\nname: mui-release\ndescription: Run or assist a release in any MUI repo, at any stage - release PR, npm publish, docs deploy, GitHub release.\nargument-hint: '[target-version]'\n---\n\n# MUI Release\n\nEvery MUI repo releases through the same staged pipeline. Each stage depends on the previous one completing — never start a stage before its predecessor is done. This skill describes the shared skeleton; the details vary per repo.\n\n**Resumable:** the skill can be invoked at any stage — a release often spans multiple sessions (e.g. the PR was created and merged earlier, and the user now wants to trigger the npm publish). In the pipeline diagram below, each arrow out of a stage states the observable evidence that the stage is complete: resume at the first stage whose evidence is missing. Confirm the detected stage with the user before continuing; earlier stages' outputs are inputs, not work to redo.\n\n**Source of truth:** the target repo's `scripts/README.md` is the authoritative, evolving runbook. Always read it in the target checkout before releasing; use this skill to know what the stages mean and what to expect. Where the README contradicts this skill, the README wins. Repo-specific steps (docs release pages, hotfix flows, prerelease progressions, docs-only deploys, first-time package publishing) live only there. Repos without that runbook: read their release workflow directly.\n\n## The pipeline\n\nEach stage's instructions live in its own file — after detecting and confirming the current stage, read **that stage's file**:\n\n```mermaid\nflowchart TD\n    S1[\"Stage 1: Prepare the release PR\\n(stage-1-prepare-pr.md)\"]\n    S2[\"Stage 2: Merge the PR, then publish\\n(stage-2-publish-packages.md)\"]\n    S3[\"Stage 3: Publish the docs\\n(stage-3-publish-docs.md)\"]\n    S4[\"Stage 4: Publish the GitHub release, then announce\\n(stage-4-github-release.md)\"]\n\n    S1 -- \"open PR with the release label,\\napproved, CI green\" --> S2\n    S2 -- \"release PR merged, packages on npm at\\nthe new version, draft GitHub release created\" --> S3\n    S3 -- \"docs live for the new version\" --> S4\n    S4 -- \"published non-draft GitHub release for the\\ncurrent root package.json version\\n(release done, next one starts at Stage 1)\" --> S1\n```\n\nVerify each stage's evidence with read-only commands (run in the target checkout; `<version>` is the root `package.json` version):\n\n```bash\n# release PR: open (stage 1) or merged (stage 2 done merging)\ngh pr list --label release --state open --json number,title,reviewDecision\ngh pr list --label release --state merged --limit 1 --json number,title,mergedAt\ngh pr checks <number>                      # CI green?\n\n# packages on npm at the new version\nnpm view <main-package>@<version> version\n\n# GitHub release: exists? still a draft?\ngh release list --limit 5 --json tagName,isDraft,isLatest\ngh release view \"v<version>\" --json tagName,isDraft\n\n# docs live for the new version\ncurl -s <docs-url> | grep \"<version>\"      # or check the Netlify dashboard\n```\n",".agents/skills/mui-release/stage-1-prepare-pr.md":"# Stage 1 — Prepare the release PR\n\nAll preparation lands as a normal PR against the branch being released (usually the repo's default branch, `master` in MUI repos; prereleases or older majors may release from a version branch — the README says which). Some repos require specific git remotes (an `upstream` pointing at the MUI repo, sometimes a dedicated docs remote) — check the README's prerequisites first.\n\n1. Create a branch off the up-to-date upstream release branch (`git fetch upstream --tags` first — the changelog script compares against the last tag).\n2. Ask the user for the target release version, showing them the current version (the root `package.json` version and the latest release tag) alongside the question so they can make an informed choice. If they passed a version when invoking the skill, use that instead of asking. Never pick the target version yourself.\n3. Bump the root `package.json` version to the target release version.\n4. Generate the changelog with `pnpm release:changelog` and **prepend** the output to the top-level `CHANGELOG.md`. Run with `--help` for options (comparison range, target branch, token flags).\n5. Clean the generated changelog: match the format of the repo's existing GitHub releases, describe breaking changes explicitly, fix package-name casing. Preserve any marker comments the script inserts — downstream automation may depend on them.\n6. Version the packages with `pnpm release:version` — an **interactive** (PTY) script that confirms the new version of each workspace package before bumping it (along with inter-package dependency ranges). Ask the user to run it in their own terminal and end the turn there. On the next turn, verify the outcome from `git diff` (which packages were bumped and to what) instead of the command's output, against these rules:\n   - Only bump packages that have changes since the last release — but if the tooling detects **any** change, do not skip the bump.\n   - Packages that track the root version — the repo's **main package** above all — must end up at exactly the root `package.json` version, even if that skips version numbers or the package had no changes of its own. The script skips unchanged packages, so the main package may need a manual bump after the run.\n7. Open the PR titled `[release] <target-version>` (e.g. `[release] v1.2.0`) with the `release` label — stage 2 finds the release PR by this label. Keep the PR description minimal: none at all, or a single line when something genuinely needs calling out (the changelog in the diff is the description).\n\nSome repos ship an interactive script (e.g. `pnpm release:prepare`) that automates this stage end to end — prefer it when the README offers one.\n\n**Stage complete when:** the PR is approved and CI is green.\n\n## Troubleshooting\n\n- **Changelog script fails:** build the changelog manually from the GitHub compare view between the last tag and the release branch (`github.com/mui/<repo>/compare/<lastTag>...<branch>`).\n",".agents/skills/mui-release/stage-2-publish-packages.md":"# Stage 2 — Merge the PR, then publish the packages\n\nRequires stage 1 complete. Before merging, verify the PR still has the `release` label — the publish tooling finds the release PR by it.\n\n1. Just before merging, the user announces a **merge freeze** on the team's Slack channel so nothing else lands until the release and docs deploy are done — as an agent, remind them of this step.\n2. Merge the release PR.\n3. Trigger the publish. It always runs through the repo's `publish.yml` GitHub Actions workflow, never from a local machine:\n   - **CLI:** `pnpm release:publish` (maps to `code-infra publish`) finds the latest merged release PR, asks for confirmation, and dispatches the workflow. To publish from the exact release commit, pass the release PR's merge commit SHA on the default branch: `pnpm release:publish --sha <merge-commit-sha>` (get it with `gh pr view <number> --json mergeCommit`). The interactive picker may pre-select an unrelated commit — never accept the default without checking it's the `[release] vX.Y.Z` merge commit.\n   - **GitHub UI:** open the publish workflow → \"Run workflow\", supplying the release commit SHA and options.\n\n   Common options either way: a dry-run mode for debugging (also as `pnpm release:publish:dry-run` — still a real workflow run needing environment approval), an npm dist-tag for legacy/canary versions, and whether to auto-create the GitHub release. Legacy releases must pass `--sha` explicitly — the picker only sees the latest release PR.\n\n4. The run pauses on the `npm-publish` environment: click \"Review deployments\" and approve it. **Never approve workflow runs you didn't initiate.**\n\n**Stage complete when:** the workflow has published the packages to npm and created a **draft** GitHub release from the changelog.\n\n## Troubleshooting\n\n- **Publish reports \"no new packages to publish\":** the workflow ran against a commit whose package versions are already on npm — usually a wrong SHA (e.g. the picker's pre-selected default). Re-dispatch with `--sha <merge-commit-sha>` of the release PR.\n",".agents/skills/mui-release/stage-3-publish-docs.md":"# Stage 3 — Publish the docs\n\nRequires stage 2 complete (packages published — docs must reference versions that exist on npm).\n\n`pnpm docs:deploy` pushes the release commit to the repo's docs deployment target — a versioned `docs-vX` branch or a dedicated docs repo/branch, mapped to the live docs domain. Force-pushing is expected. Deploys run on Netlify; follow progress on the site's Netlify dashboard. The README documents the branch scheme and URLs.\n\n**Stage complete when:** the Netlify deploy has finished and the docs are live.\n",".agents/skills/mui-release/stage-4-github-release.md":"# Stage 4 — Publish the GitHub release, then announce\n\nRequires stage 3 complete (docs live).\n\n1. Review the draft release on the repo's GitHub releases page and publish it. Mark it correctly for what's being released:\n   - Stable release on the current major → **Set as the latest release**.\n   - Release for an older major → do **not** set as latest — the current major's release must keep the \"Latest\" badge.\n   - Unstable version (alpha/beta/RC) → check **Set as a pre-release** instead.\n2. The user lifts the merge freeze on Slack and follows the team's internal announcement instructions — as an agent, remind them of both.\n\n**Stage complete when:** the GitHub release is public (non-draft) — the release is done. The freeze lift and announcement are on the user's side; remind them.\n",".claude/skills/base-ui-review/SKILL.md":"---\nname: base-ui-review\ndescription: 'Review the current diff for regressions, correctness bugs, tests, simplifications, and docs issues, scaling depth to a low/medium/high/xhigh/max effort level. Use ONLY when explicitly requested by name: the user runs /base-ui-review, writes $base-ui-review, or asks for \"the Base UI review skill\". Do NOT use for general review requests such as \"review my changes\", \"review this diff/branch/PR\", or after finishing an implementation — handle those without this skill unless the user names it. Pass --comment to post a top-level PR comment, --comment inline for inline PR comments, or --fix to apply findings.'\n---\n\n# Base UI Review\n\nThis is the Claude Code entrypoint for the shared repo skill.\n\nOnly run when the user explicitly asks for this skill by name\n(`/base-ui-review`, `$base-ui-review`, \"the Base UI review skill\", or a CI job\nconfigured to use it). Do not trigger on a generic \"review my changes\" request\nor after finishing an implementation.\n\nBefore reviewing, read `.agents/skills/base-ui-review/SKILL.md` completely and\nfollow that canonical workflow. Pass through any user arguments such as `low`,\n`medium`, `high`, `xhigh`, `max`, `--comment`, `--comment inline`, `--fix`, or a\nreview target.\n","AGENTS.md":"# Repository Guidelines\n\nThis repository contains the source code and documentation for Base UI: a headless, unstyled React component library.\n\n## Project structure\n\n- Source code for components and private utils is in `packages/react/`.\n- Source code for public shared utils is in `packages/utils/`.\n- Experiments are located at `docs/src/app/(private)/experiments/`. Use for creating demos that require manual testing in the browser.\n- Public documentation is located at `docs/src/app/(docs)/react/`. Alter the docs where necessary when changes must be visible to library users.\n- When creating public demos on the docs, refer to the `hero` demo for the given component and largely follow its styles (both CSS Modules and Tailwind CSS versions). Other demos may also contain relevant styling. Do not add custom styling beyond the critical layout styles necessary for new demos.\n\n## Agent skills\n\n- The shared `/base-ui-review` skill lives in `.agents/skills/base-ui-review/SKILL.md`. Update that file when the Base UI review workflow changes.\n- Claude Code discovers the same shared skill through `.claude/skills/base-ui-review/SKILL.md`, which delegates to the `.agents` copy.\n- The review skill is opt-in: only run it when the user explicitly asks for it by name (`/base-ui-review`). Do not trigger it from a generic review request or after finishing a change.\n\n## Code guidelines\n\n- Always use the `useTimeout` utility from `@base-ui/utils/useTimeout` instead of `window.setTimeout`, and `useAnimationFrame` from `@base-ui/utils/useAnimationFrame` instead of `requestAnimationFrame`. Search for other example usage in the codebase if unsure how to use them.\n- Use the `useStableCallback` utility from `@base-ui/utils/useStableCallback` instead of `React.useCallback` if the function is called within an effect or event handler. The utility cannot be used to memoize functions that are called directly in the body of a component (during render), so continue with `React.useCallback` in those scenarios.\n- Always use the `useIsoLayoutEffect` utility from `@base-ui/utils/useIsoLayoutEffect` instead of `React.useLayoutEffect`.\n- Always use the shadow DOM-safe utilities for DOM traversal and event targeting: `closest`, `contains`, `getTarget`, and `activeElement`. Always use the owner utilities `ownerDocument` and `ownerWindow` instead of global `document`/`window` lookups when the code is tied to a DOM node, including realm-sensitive checks such as `instanceof`.\n- Avoid duplicating logic where necessary. If two components can share logic (such as event handlers), define the logic/handlers in the parent and share it through a context to the child; use the existing context if it exists.\n\n## Styling\n\n- In CSS Modules demos (`docs/src/app/(docs)/**/demos/**/*.module.css`), use raw color values from the Tailwind `@theme` block in `docs/src/css/index.css`. For example, use `oklch(14.5% 0 0deg)` instead of `var(--color-neutral-950)`.\n- When using `user-select: none;` in CSS, also add `-webkit-user-select: none;` to support Safari. Tailwind's `select-none` class already includes this.\n\n## Linting, typechecking, and formatting\n\n- Do not randomly cast (for example `as any`) if there are no type errors without doing so. Run `pnpm typescript` to verify types.\n- Ensure your changes pass linting - run `pnpm eslint`.\n- Ensure your styles pass stylelint - run `pnpm stylelint`.\n- Ensure your changes are formatted correctly - run `pnpm prettier`.\n- When you change a public component API (props or JSDoc), run `pnpm docs:api`.\n\n## Testing\n\n- If a repository command fails because dependencies are unavailable, run `pnpm i` first and then retry the command.\n- Run tests in jsdom env with `pnpm test:jsdom {name} --no-watch` such as `pnpm test:jsdom NumberField --no-watch` or `pnpm test:jsdom parse --no-watch`.\n- Run tests in Chromium env with `pnpm test:chromium {name} --no-watch` such as `pnpm test:chromium NumberField --no-watch` or `pnpm test:chromium parse --no-watch`.\n- In `@base-ui/react` tests, do not call `await flushMicrotasks()` directly after `await render(...)` when there are no interactions or state changes between them; the `#test-utils` `render` is async and already awaited, so that immediate flush is unnecessary.\n- Do not group multiple `expect()` assertions in a single `waitFor()` callback. Use one assertion per `waitFor()` so retries are scoped to the specific condition that may change asynchronously.\n- For locale-formatted text, use `expect(element.textContent).toBe(expected)` with the expected value formatted using the same locale and options as the component. When the component uses the runtime default locale, derive expectations using that default too (for example, `new Intl.NumberFormat(undefined, options)`); do not hardcode `en-US` or US-formatted strings in expected values. Pin a locale only when testing locale-specific behavior, and use it consistently for both the component and expectations. `toHaveTextContent` normalizes nonbreaking spaces in the rendered text but not in the expected string, causing failures in locales such as `pt-BR`.\n- Use `firePointer` from `#test-utils` instead of `fireEvent.pointer*` whenever a test depends on event timing. `fireEvent` silently drops `timeStamp`, so the event inherits the environment's clock — the real one in a browser — and gesture velocity then depends on how long the runner took between calls. A lint rule enforces this.\n- If you made changes to the source code, ensure you verify your changes by running tests (see above), and writing new tests where applicable. If tests require the browser because, for example, they require layout measurements, restrict it to the Chromium env by using `it.skipIf(isJSDOM)` or `describe.skipIf(isJSDOM)` (search other tests for example usage if unsure).\n- Follow the established conventions in existing tests. Each file/component is tested with the filename `name.test.tsx`. For example, `PopoverRoot.test.tsx` is next to its source file `PopoverRoot.tsx`.\n- Tests use Vitest APIs only: `expect()`, `vi.fn()`, and `@testing-library/jest-dom` DOM matchers. Do not use Chai- or Sinon-style matcher chains or spies.\n- Import `createRenderer`, `describeConformance` and other helpers from `#test-utils`, and use the `user` returned by `await render(...)` instead of creating a Testing Library user-event instance with `userEvent.setup()`.\n- A test must be able to fail when the behavior in its title breaks. Before you finish a test, break that behavior in the source and check that the test fails, then revert. In particular:\n  - Assert the starting state before the action when the end state could already hold (for example, move focus away before testing that it returns).\n  - For \"does not X when <guard>\" tests, use an interaction that would do X without the guard, ideally with a sibling case that flips only the guard and shows X happening.\n  - When the title names an intermediate state (\"while open\", \"after hover\", \"during swipe\"), assert that state right before the action under test.\n  - Fire events the way the component expects them. `fireEvent.click` on a list item is a virtual click that items may ignore; prefer `user.click`. A `preventDefault` spy in a `fireEvent` init object is never called; assert on the boolean `fireEvent` returns instead.\n  - Never put negative assertions inside `waitFor` (they pass on the first poll); flush or advance timers first, then assert synchronously.\n  - Keep assertions in the test body: an `expect` inside a callback that may not run, a conditional, or `Promise.allSettled` can silently pass.\n- Use `it.each` (object rows with `$name` titles) or `describe.each` for tests that differ only in data; don't register tests or suites inside `forEach` or `map`. Every test inside a parametrized block must use the parameter.\n- A test belongs in the file of the part whose prop or behavior it asserts, and under `describe('prop: X')` only if it sets `X`. Titles must describe what the body asserts.\n- Shared behavior across components belongs in a shared suite in `packages/react/test`, exported from `#test-utils`, rather than copied into each component's tests. Existing suites: `describeConformance` (every part), `popupConformanceTests` (popup roots), `popupListConformanceTests` (list interactions in Select, Menu and Combobox popups), `popupFocusPropsTests` (`initialFocus`/`finalFocus`), `dialogRootSharedTests` (Dialog and AlertDialog), `detachedTriggersConformanceTests`, `positionerConformanceTests` and `viewportConformanceTests`. Don't re-test what a suite already covers for the same part; extend the suite instead.\n- After every test, `test/setupVitest.ts` resets `BASE_UI_ANIMATIONS_DISABLED`, mocks, deduplicated errors and warnings, and the animation frame scheduler, and `createRenderer` unmounts what it rendered; don't repeat that per file.\n\n## Commit guidelines\n\n- Commit messages follow the format `[scope] Imperative summary` (for example `[popover] Fix focus trap`). Choose scopes that mirror package or component names that were changed.\n- Use `[all components]` scope for changes that broadly affect most components.\n\n## Errors\n\nThese guidelines apply only to errors thrown by public packages.\n\nEvery error message must:\n\n1. **Say what happened** - Describe the problem clearly\n2. **Say why it's a problem** - Explain the consequence\n3. **Point toward how to solve it** - Give actionable guidance\n\nFormat:\n\n- Prefix with `Base UI:`\n- Use string concatenation for readability\n- Include a documentation link when applicable (`https://base-ui.com/...`)\n\n### Error Minifier\n\nYou MUST run `pnpm extract-error-codes` to update `docs/src/error-codes.json` every time you add or update an error message in an `Error` constructor.\n\n**Important:** If the update created a new error code, but the new and original message have the same number of arguments and semantics haven't changed, update the original error in `error-codes.json` instead of creating a new code.\n\nBefore any changes, review [CONTRIBUTING.md](./CONTRIBUTING.md) for more detailed guidelines on contributing to this repository.\n","CLAUDE.md":"@AGENTS.md\n","packages/react/README.md":"<!-- lint disable mui-first-block-heading -->\n\n<a href=\"https://base-ui.com\" target=\"_blank\"><img width=\"150\" height=\"133\" src=\"https://base-ui.com/static/logo.svg\" alt=\"Base UI logo\"></a>\n\nBase UI is a library of unstyled React components. You gain complete control over your app's CSS and accessibility features.\n\n## Installation\n\nInstall the package in your project directory with:\n\n```bash\nnpm install @base-ui/react\n```\n\n## Documentation\n\n<!-- #default-branch-switch -->\n\nVisit [base-ui.com](https://base-ui.com) to view the full documentation.\n\n## Questions\n\nFor how-to questions that don't involve making changes to the code base, please use [Stack Overflow](https://stackoverflow.com/questions/tagged/base-ui) instead of GitHub issues.\nUse the \"base-ui\" tag on Stack Overflow to make it easier for the community to find your question.\n\n## Contributing\n\nRead the [contributing guide](../../CONTRIBUTING.md) to learn about our development process, how to propose bug fixes and improvements, and how to build and test your changes.\n\nContributing to Base UI is about more than just issues and pull requests!\nThere are many other ways to [support Base UI](https://mui.com/material-ui/getting-started/faq/#mui-is-awesome-how-can-i-support-the-project) beyond contributing to the code base.\n\n## Changelog\n\nThe [changelog](https://github.com/mui/base-ui/releases) is regularly updated to reflect what's changed in each new release.\n\n## Roadmap\n\nFuture plans and high-priority features and enhancements can be found in the [roadmap](https://github.com/orgs/mui/projects/1).\n\n## License\n\nThis project is licensed under the terms of the [MIT license](../../LICENSE).\n\n## Security\n\nFor details of supported versions and contact details for reporting security issues, please refer to the [security policy](https://github.com/mui/base-ui/security/policy).\n","packages/utils/README.md":"# @base-ui/utils\n\nA collection of React utility functions for Base UI.\n"},"files":{".agents/skills/base-ui-review/SKILL.md":"---\nname: base-ui-review\ndescription: 'Review the current diff for regressions, correctness bugs, tests, simplifications, and docs issues, scaling depth to a low/medium/high/xhigh/max effort level. Use ONLY when explicitly requested by name: the user runs /base-ui-review, writes $base-ui-review, or asks for \"the Base UI review skill\". Do NOT use for general review requests such as \"review my changes\", \"review this diff/branch/PR\", or after finishing an implementation — handle those without this skill unless the user names it. Pass --comment to post a top-level PR comment, --comment inline for inline PR comments, or --fix to apply findings.'\n---\n\n# Base UI Review\n\nReview current diff. Find **regressions and correctness bugs** first. Also find\n**cleanup** (reuse / simplification / efficiency). Default effort: `medium`. See\n[Effort levels](#effort-levels) for depth and subagent fan-out.\n\nArgument hint: `[low|medium|high|xhigh|max] [--fix] [--comment [inline]] [<target>]`\n\nThis skill is **opt-in only**: run it when the user explicitly asks for it by\nname (`/base-ui-review`, `$base-ui-review`, \"the Base UI review skill\", or a CI\njob configured to use it). A plain \"review my changes\" or \"review this PR\", or\nwrapping up an implementation, is not an invocation — review without this\nworkflow unless the user names it.\n\n`medium` = **precision**. Every finding actionable. `high`, `xhigh`, `max` =\n**recall**. Missed bug ships. Keep uncertain findings when mechanism is real;\nlabel them clearly.\n\n## Scope\n\nLocal review: diff branch against upstream\n(`git diff @{upstream}...HEAD`, fall back to `main` / `master`, or `HEAD~1`).\nFold in uncommitted + untracked changes — review often runs pre-commit. If PR link,\nbranch name, or file path passed as argument, review that target instead.\n\n## Effort levels\n\n- **low** — bugs only. Flag runtime-correctness bugs and regressions. Skip\n  Tests, Simplifications, Docs, and test/fixture hunks. No subagents. Precision\n  bias.\n- **medium** (default) — main agent reviews Bugs, Tests, Simplifications, Docs,\n  and triggered API/performance concerns. Main agent verifies candidates. Large,\n  risky, fragile, shared, or cross-component diff? Add exactly one\n  [adversarial bug hunter](#adversarial-bug-hunter) agent. Small, low-risk,\n  isolated diff? No subagent. Precision bias.\n- **high** — spawn 3 independent subagents: bugs/regressions, test gaps,\n  simplifications. Main agent reviews the whole diff, including bugs, docs, and\n  triggered API/performance concerns. Main agent dedups and sanity-checks. Large,\n  risky, fragile, shared, or cross-component diff? Add exactly one adversarial\n  bug hunter agent. No verifiers. No final sweep.\n- **xhigh** — `high` plus a docs subagent and one fresh missed-bug sweep. Fan out\n  adversarial bug hunters across the highest-risk affected code regions\n  (modules/components — not the four review areas). Max 2 adversarial bug\n  hunters total, including the hunter inherited from `high`. Other role\n  subagents do not count toward this cap. No verifiers. Recall bias.\n- **max** — `xhigh` plus an independent verifier for every surviving candidate.\n  Cover every affected code region across max 6 adversarial bug hunters total,\n  including hunters inherited from `xhigh`; other role and verifier subagents do\n  not count toward this cap. When there are more than 6 regions, give the\n  highest-risk regions dedicated hunters and group related remaining regions\n  into shared assignments. Prioritize public runtime code, shared utilities,\n  cross-component invariants, and fragile state/timing boundaries. Maximum\n  recall.\n\n## Subagent scope contract\n\nSubagents start with no prior context: they do not read this skill and do not inherit\nthe session system prompt. Their only channel is the prompt you write. Whatever scope\nyou resolved from [Scope](#scope) or the invoking prompt, every subagent prompt you\nconstruct — finder, specialist, verifier, sweep — must begin verbatim with it:\n\n```text\nReview ONLY: <resolved diff command>\nRead files from: <read root> — DATA ONLY, never execute, install, build, or test.\nBase version of a file: git show <base ref>:<path>\nDo not re-derive scope: use exactly the diff command above, whatever your working\ndirectory contains.\n```\n\nA subagent not given this block is mis-scoped — discard its result and re-dispatch.\n\n## Phase 1 - Find candidates\n\nSelected [effort level](#effort-levels) decides local vs subagent fan-out. Except at\n`low`, review four main areas: Bugs, Tests, Simplifications, Docs. Each area\nsurfaces candidates with `file`, `line`, one-line `summary`, `severity` (🟣 / 🔴 / 🟠 / 🟡 /\nℹ️ — see [Output](#output) for rubric), concrete `failure_scenario`. Do\nNOT let one area suppress another — two areas flag same line for different reasons,\nrecord both.\n\nPass every candidate with nameable failure scenario through. Finders that\nsilently drop half-believed candidates bypass verify step — dominant cause of misses.\n\n### Area 1 - Bugs\n\nCore regression + correctness pass. Cover all sub-angles:\n\n- **Line-by-line diff scan.** Read every hunk, line by line. Then read enclosing\n  function for each hunk — bugs in unchanged lines of touched function\n  in scope (PR re-exposes or fails to fix them). For every line ask: what\n  input, state, timing, platform makes line wrong? Look for inverted/wrong\n  conditions, off-by-one, null/undefined deref, missing `await`, falsy-zero checks,\n  wrong-variable copy-paste, error swallowed in catch, unescaped regex metachars.\n- **Regression hunting.** For each changed guard, branch, state transition, public\n  contract, test expectation, documented example, ask what behavior previously\n  worked and could break. Bias toward regressions in edge paths, accessibility\n  interactions, keyboard/focus flows, controlled/uncontrolled contracts, SSR,\n  integrations between components, public API examples.\n- **Repository/framework correctness lens.** Apply invariants of codebase\n  under review, not just generic language bugs. For Base UI / React component\n  changes: controlled vs uncontrolled behavior, event ordering, ref\n  forwarding/merging, context registration cleanup, nested component coordination,\n  portals, focus management, keyboard navigation, ARIA attributes, disabled/read-only\n  states, form integration, SSR/hydration safety, Strict Mode behavior, shadow\n  DOM-safe DOM access (`closest`, `contains`, `getTarget`, `activeElement`, `ownerDocument`,\n  `ownerWindow`).\n- **Removed-behavior auditor.** For every line diff DELETES or replaces, name\n  invariant/behavior it enforced, then search new code for where invariant\n  re-established. Can't find it? Candidate: removed\n  guard, dropped error path, narrowed validation, deleted test covering real case.\n- **Cross-file tracer.** For each function diff changes, find callers (Grep\n  symbol) and check if change breaks any call site: new\n  precondition, changed return shape, new exception, timing/ordering\n  dependency. Also check callees: parallel change in same PR make call\n  unsafe?\n\n### Area 2 - Tests\n\nReview test changes and tests that _should_ have changed. Flag:\n\n- New/changed behavior with no test exercising it\n- Assertions not actually pinning behavior (asserting mock called instead of\n  result, snapshot-only coverage, asserting on value test itself computed)\n- Missing edge/error-path cases diff introduces (null, empty, boundary, failure,\n  concurrency)\n- Setup/teardown asymmetry (state leaked between tests, fixtures not reset)\n- Over-mocking hiding real contract\n- Tests deleted or weakened without justification\n- Tests whose names do not match what they assert, or whose names are misleading\n\nName specific case untested or under-asserted.\n\n### Area 3 - Simplifications\n\nBundle size is a top constraint. Smallest correct implementation wins. Preserve\npublic behavior, runtime performance, and maintainability. Treat every bundle\nsize increase as suspect — new bytes must earn their place; flag increases the\ndiff doesn't justify.\n\nAlways ask: \"Can this ship with less code, state, branching, or abstraction?\"\nLook for:\n\n- Heavy dependency or new abstraction where a few lines or existing util does\n  the job\n- Code doing too much for an edge case almost no one hits — guards, branches,\n  state, or config for scenarios not realistically reachable in consumer usage;\n  weigh handling cost against edge-case likelihood and propose dropping or\n  cheapening it\n- Duplicated logic re-implementing what codebase already has — Grep\n  shared/utility modules and files adjacent to change; name existing helper to\n  call instead\n- Non-tree-shakeable or whole-package imports; namespace imports of\n  side-effectful modules\n- Dead code left behind; redundant or derivable state\n- Special cases layered on shared infrastructure when mechanism should\n  generalize\n\nName smaller or better-shaped form doing same job. Measure real bundle effect\nwhen material. Source-line count proves nothing.\n\n### Area 4 - Docs\n\nFlag documentation and comments diff makes wrong or leaves stale:\n\n- Comments describing old behavior after code changed\n- JSDoc/docstrings whose params, return type, thrown errors no longer match\n  signature\n- README / API docs / changelog entries contradicting change; examples no longer\n  compile or run\n- TODO/FIXME change resolved but didn't remove; new non-obvious code with no\n  explanation where warranted\n\nQuote stale line and state what it should say.\n\n### Conditional specialist - API design\n\nNot part of default four-area fan-out. Skip entirely at\n`low`. At `medium`, include in main-agent pass when diff adds/changes\npublic API surface: component, prop, event, hook, provider, imperative method,\nexported type, value shape, behavior contract, docs example teaching API.\nAt `high`, `xhigh`, `max`, run as independent API design subagent when\ntriggered.\n\nHeavily critique API taste: naming, mental model, consistency with\nnearby APIs in same codebase, controlled/uncontrolled ergonomics, composition,\nescape hatches, type shape, default behavior, future extensibility, migration risk,\nlikely user footguns. Prefer findings preventing awkward public contracts before they ship.\nReport API design findings under Bugs when they create likely user-visible footguns\nor regressions, otherwise under Simplifications.\n\n### Conditional specialist - Runtime performance\n\nNot part of default four-area fan-out. Skip entirely at\n`low`. At `medium`, include in main-agent pass when diff likely affects\nruntime performance: render hot paths, large item collections, virtualization,\npositioning, layout measurement, scroll/resize/pointer/keyboard handlers,\nobservers, animations, repeated DOM reads/writes, state updates in loops,\ncomponent registration/lookup paths. At `high`, `xhigh`, `max`, run as\nindependent runtime performance subagent when triggered.\n\nPrefer concrete measurement when feasible: existing perf tests, targeted benchmark\nscripts, small reproducible measurement. If measuring not practical, state\nexpected complexity or browser work and what would confirm it. Report runtime\nperformance findings under Bugs when users can see lag, jank, hangs, excessive\nwork, otherwise under Simplifications.\n\n### Adversarial bug hunter\n\nSubagent role added per [Effort levels](#effort-levels). Assume there are bugs\nin the diff a consumer will hit. Do not trust PR description, comments, or test\nnames — verify against code. Attack changed invariants directly: construct\nconcrete input, state, timing, or platform that makes new code wrong. Report\nevery candidate with a nameable failure scenario; when none survive, report\nempty — never pad with weak findings to justify the hunt.\n\n---\n\nSimplification, test, docs candidates use same `file`/`line`/`summary`\nshape; in `failure_scenario`, state concrete cost (what duplicated, wasted,\nuntested, stale, harder to maintain) instead of crash. Regressions and\ncorrectness bugs always outrank simplification, test, docs findings when\nreview ordered.\n\n## Phase 2 - Verify candidates (local by default; max adds subagent votes)\n\nDedup candidates pointing at same line/mechanism, keep one with\nmost concrete failure scenario. Verify candidates locally in main agent by\ndefault.\n\nJudge every candidate by reachability and impact. Keep every valid bug. Demote\nto ℹ️ note when behavior not realistically reachable in real consumer usage,\nhas no meaningful user impact, or is optional improvement rather than\ncorrectness defect. Demotion is not refutation — demoted findings still print,\nat lower severity. At `max` effort, also run **one verifier** as subagent for each\nremaining candidate when subagents available and authorized: give it diff,\nrelevant file(s), candidate, have it return exactly one of:\n\n- **CONFIRMED** — can name inputs/state triggering it and wrong output or\n  crash. Quote line.\n- **PLAUSIBLE** — mechanism real, trigger uncertain (timing, env, config).\n  State what would confirm it.\n- **REFUTED** — factually wrong (code doesn't say that) or guarded elsewhere. Quote\n  line proving it.\n\nKeep candidates where vote CONFIRMED or PLAUSIBLE.\n\nAt **max**, verify recall-biased — **PLAUSIBLE by default**: do not\nrefute candidate for being \"speculative\" or \"depends on runtime state\" when\nstate realistic (concurrency races, nil/undefined on rare-but-reachable path,\nfalsy-zero treated as missing, off-by-one on boundary code doesn't exclude,\nretry storms / partial failures, regex/allowlist lost anchor). REFUTE only\nwhen constructible from code: factually wrong, provably impossible, already\nhandled in this diff, pure style with no observable effect.\n\n## Phase 3 - Sweep for gaps (xhigh / max effort)\n\nAt `xhigh` and `max`, run **one more finder** as fresh reviewer with\ncurrent finding list. Re-read diff and enclosing functions looking ONLY for\ndefects not already listed. Do not re-derive or re-confirm anything already there —\njob is gaps. Focus on what first pass misses: moved/extracted code\ndropping guard or anchor; second-tier footguns (dataclass default evaluated\nonce, `hash()` non-determinism, lock-scope shrink, predicate methods with side\neffects); setup/teardown asymmetry in tests; config defaults flipped. Surface\nadditional candidates naming defect not already on list. If nothing new,\nreturn empty sweep — do not pad.\n\n## Output\n\nReply in Markdown. Do not wrap main result in JSON or code fence. Use\nsentence case for `#` heading and all finding titles; no title case. Do\nnot open with generic target/base filler like \"Reviewed `owner/repo#123` against\n`branch`.\" Only mention target or base branch when explaining specific\nfinding or limitation.\n\nPrint only non-empty category sections, in this order: `Bugs`, `Tests`,\n`Simplifications`, `Docs`. A category with 0 findings gets nothing — no\nheading, no count, no `No findings.` placeholder. Always end with `Verdict`.\nBefore sending, verify every surviving finding prints exactly once and each\nprinted section count matches its numbered findings. When no findings exist\nanywhere, use the [No findings](#no-findings) format.\n\n### Severity rubric\n\nPrefix every finding title with one severity marker:\n\n- 🟣 **critical - blocking.** Correctness issue crashing common flows, losing\n  user data, creating security/privacy problem, making public component contract\n  unusable, or creating broad cross-component accessibility, focus, form, SSR\n  breakage. Must block merge.\n- 🔴 **high - blocking.** Realistic user-visible regression in normal component\n  usage, accessibility, keyboard/focus behavior, controlled/uncontrolled behavior,\n  form integration, SSR/hydration, public API behavior, or public docs example\n  no longer compiling or teaching broken API usage. Should block merge even\n  when affected path has workaround or not most common path.\n- 🟠 **medium - non-blocking.** Real issue worth fixing before merge when\n  practical but not normally blocking: narrow or uncommon bug, meaningful missing\n  test, stale public-doc prose not breaking copy-pasted code, cleanup\n  avoiding likely future mistakes. Use only when issue doesn't break public\n  contract and doesn't affect accessibility, focus, forms, SSR, or normal component\n  usage.\n- 🟡 **low - non-blocking.** Minor edge-case bug, small test/doc gap, modest\n  simplification useful but easy for maintainers to defer.\n- ℹ️ **note.** Informational — observation, heads-up, optional suggestion the\n  maintainer may reasonably decline.\n\nBase UI has stricter quality bar than most apps — small component-library\nregressions multiplied across many downstream products. When choosing between\nadjacent severities, choose higher severity if failure reaches realistic\nconsumer usage, accessibility behavior, form behavior, focus management, SSR,\npublic API contract or broken public docs example. Do not reserve 🔴 high only for\noutage-level failures.\n\nWithin each section, order findings 🟣 -> 🔴 -> 🟠 -> 🟡 -> ℹ️.\n\n### Verdict\n\nEnd review with `## Verdict` line derived from markers:\n\n- **Request changes** — at least one 🟣 or 🔴 finding.\n- **Approve after nits** — no 🟣 or 🔴, but one or more 🟠 or 🟡 findings worth\n  addressing.\n- **Approve** — no 🟣, 🔴, 🟠, 🟡 findings (only ℹ️ notes, or nothing).\n\nFollow verdict with one clause naming deciding factor.\n\n### Finding format\n\nUse this structure. Omit any category block whose count is zero:\n\n````md\n# PR review\n\nOne to three sentences summarizing the concrete risk, most important theme, and\nany meaningful verification limit. State up front whether anything is merge-blocking.\nIf there are no actionable findings, say that clearly.\n\n## Bugs ({count})\n\n### 1. {severity marker} {Sentence-case title}\n\n**Location:** `path/to/file.ext:123`\n\n```tsx\n// Small relevant code excerpt from the reviewed file.\n```\n\n{Description of what is wrong and why it matters.}\n\n**Failure scenario:** {Simple, obvious user-facing or example issue someone would\nsee.}\n\n**Fix:** {Specific recommended change.}\n\n## Tests ({count})\n\n## Simplifications ({count})\n\n## Docs ({count})\n\n## Verdict\n\n**{Request changes | Approve after nits | Approve}** - {one clause on the deciding factor}.\n\n---\n\n🤖 Review generated with {Claude Code | Codex}\n````\n\nSame per-finding shape for Tests, Simplifications, Docs. For Tests,\nmake failure scenario the missing case or weak assertion. For Simplifications,\nmake it concrete duplicated, heavier, or harder-to-maintain code path. For Docs,\nmake it stale or missing public/developer-facing information.\n\n### Finding quality\n\nDo not cap findings by count. Report every verified, actionable finding\nmaintainer would reasonably fix before merging. Do not pad review with weak,\nstylistic, speculative, low-importance notes. If many findings survive, group\nrelated issues under one finding when they share same root cause.\n\n### No findings\n\nIf nothing survives verification, omit all category headings and counts. Return\n`# PR review`, `No findings.`, a brief note of residual test gaps or risk,\n`## Verdict` with **Approve**, and the `🤖 Review generated with ...` footer.\n\n### Final output preflight\n\nTreat the output format as a hard contract. Before sending:\n\n- Use `# PR review`; start the summary with concrete risk, not target/base filler.\n- Use exact `## {Category} ({count})` headings for non-empty categories only.\n- Print each finding exactly once and verify every category count.\n- Use a separate `## Verdict` heading and the required closing footer.\n\nIf any check fails, rewrite the output before sending.\n\nAlways close review with `---` horizontal rule, blank line, then\n`🤖 Review generated with {Claude Code | Codex}`. Use **Claude Code** when this\nskill executed by Claude Code harness, **Codex** when executed by Codex harness.\n\n## Posting to GitHub (--comment)\n\nPost to GitHub only when target is GitHub PR and arguments include\ncomment mode:\n\n- No `--comment` — do not post to GitHub; if `--fix` also absent, stop at\n  Markdown review report.\n- `--comment` — post Markdown review as one top-level PR comment via\n  `gh pr comment`.\n- `--comment inline` — post inline comments for findings mapping to PR diff\n  lines, include all non-diff findings in top-level fallback comment.\n\nFor `--comment inline`, include same severity marker in each inline comment\nbody. Use latest PR head `commit_id`, `path`, `line`, `side`, post via\n`gh api` (`repos/{owner}/{repo}/pulls/{pr}/comments`), one call per finding. Include\nsuggestion block only when it fully fixes issue. (If GitHub inline-comment\nMCP tool available in session, use instead.)\n\nInline comments can only attach to lines present in PR diff. Put findings\noutside PR diff (unchanged lines in touched functions) in top-level\nfallback comment via `gh pr comment`; do not drop them or stop posting rest of\nreview because one inline comment not commentable. If target not\nPR, print findings to terminal and note `--comment` was ignored.\n\n## Applying fixes (--fix)\n\nIf `--fix` flag passed in arguments, after producing findings\nlist, apply findings to working tree instead of stopping at report: fix\neach one directly — correctness bugs and reuse/simplification/efficiency cleanups\nalike. Skip any finding whose fix would change intended behavior, require changes\nwell outside reviewed diff, or you judge false positive — note\nskip rather than arguing with it. Finish with brief summary of what fixed and\nwhat skipped.\n\nIf neither `--comment` nor `--fix` passed, stop at Markdown review report.\n",".agents/skills/base-ui-review/agents/openai.yaml":"interface:\n  display_name: 'Base UI Review'\n  short_description: 'Review Base UI diffs for bugs, tests, cleanup, docs'\n  default_prompt: 'Use $base-ui-review to review my current diff.'\n",".agents/skills/mui-release/SKILL.md":"---\nname: mui-release\ndescription: Run or assist a release in any MUI repo, at any stage - release PR, npm publish, docs deploy, GitHub release.\nargument-hint: '[target-version]'\n---\n\n# MUI Release\n\nEvery MUI repo releases through the same staged pipeline. Each stage depends on the previous one completing — never start a stage before its predecessor is done. This skill describes the shared skeleton; the details vary per repo.\n\n**Resumable:** the skill can be invoked at any stage — a release often spans multiple sessions (e.g. the PR was created and merged earlier, and the user now wants to trigger the npm publish). In the pipeline diagram below, each arrow out of a stage states the observable evidence that the stage is complete: resume at the first stage whose evidence is missing. Confirm the detected stage with the user before continuing; earlier stages' outputs are inputs, not work to redo.\n\n**Source of truth:** the target repo's `scripts/README.md` is the authoritative, evolving runbook. Always read it in the target checkout before releasing; use this skill to know what the stages mean and what to expect. Where the README contradicts this skill, the README wins. Repo-specific steps (docs release pages, hotfix flows, prerelease progressions, docs-only deploys, first-time package publishing) live only there. Repos without that runbook: read their release workflow directly.\n\n## The pipeline\n\nEach stage's instructions live in its own file — after detecting and confirming the current stage, read **that stage's file**:\n\n```mermaid\nflowchart TD\n    S1[\"Stage 1: Prepare the release PR\\n(stage-1-prepare-pr.md)\"]\n    S2[\"Stage 2: Merge the PR, then publish\\n(stage-2-publish-packages.md)\"]\n    S3[\"Stage 3: Publish the docs\\n(stage-3-publish-docs.md)\"]\n    S4[\"Stage 4: Publish the GitHub release, then announce\\n(stage-4-github-release.md)\"]\n\n    S1 -- \"open PR with the release label,\\napproved, CI green\" --> S2\n    S2 -- \"release PR merged, packages on npm at\\nthe new version, draft GitHub release created\" --> S3\n    S3 -- \"docs live for the new version\" --> S4\n    S4 -- \"published non-draft GitHub release for the\\ncurrent root package.json version\\n(release done, next one starts at Stage 1)\" --> S1\n```\n\nVerify each stage's evidence with read-only commands (run in the target checkout; `<version>` is the root `package.json` version):\n\n```bash\n# release PR: open (stage 1) or merged (stage 2 done merging)\ngh pr list --label release --state open --json number,title,reviewDecision\ngh pr list --label release --state merged --limit 1 --json number,title,mergedAt\ngh pr checks <number>                      # CI green?\n\n# packages on npm at the new version\nnpm view <main-package>@<version> version\n\n# GitHub release: exists? still a draft?\ngh release list --limit 5 --json tagName,isDraft,isLatest\ngh release view \"v<version>\" --json tagName,isDraft\n\n# docs live for the new version\ncurl -s <docs-url> | grep \"<version>\"      # or check the Netlify dashboard\n```\n",".agents/skills/mui-release/stage-1-prepare-pr.md":"# Stage 1 — Prepare the release PR\n\nAll preparation lands as a normal PR against the branch being released (usually the repo's default branch, `master` in MUI repos; prereleases or older majors may release from a version branch — the README says which). Some repos require specific git remotes (an `upstream` pointing at the MUI repo, sometimes a dedicated docs remote) — check the README's prerequisites first.\n\n1. Create a branch off the up-to-date upstream release branch (`git fetch upstream --tags` first — the changelog script compares against the last tag).\n2. Ask the user for the target release version, showing them the current version (the root `package.json` version and the latest release tag) alongside the question so they can make an informed choice. If they passed a version when invoking the skill, use that instead of asking. Never pick the target version yourself.\n3. Bump the root `package.json` version to the target release version.\n4. Generate the changelog with `pnpm release:changelog` and **prepend** the output to the top-level `CHANGELOG.md`. Run with `--help` for options (comparison range, target branch, token flags).\n5. Clean the generated changelog: match the format of the repo's existing GitHub releases, describe breaking changes explicitly, fix package-name casing. Preserve any marker comments the script inserts — downstream automation may depend on them.\n6. Version the packages with `pnpm release:version` — an **interactive** (PTY) script that confirms the new version of each workspace package before bumping it (along with inter-package dependency ranges). Ask the user to run it in their own terminal and end the turn there. On the next turn, verify the outcome from `git diff` (which packages were bumped and to what) instead of the command's output, against these rules:\n   - Only bump packages that have changes since the last release — but if the tooling detects **any** change, do not skip the bump.\n   - Packages that track the root version — the repo's **main package** above all — must end up at exactly the root `package.json` version, even if that skips version numbers or the package had no changes of its own. The script skips unchanged packages, so the main package may need a manual bump after the run.\n7. Open the PR titled `[release] <target-version>` (e.g. `[release] v1.2.0`) with the `release` label — stage 2 finds the release PR by this label. Keep the PR description minimal: none at all, or a single line when something genuinely needs calling out (the changelog in the diff is the description).\n\nSome repos ship an interactive script (e.g. `pnpm release:prepare`) that automates this stage end to end — prefer it when the README offers one.\n\n**Stage complete when:** the PR is approved and CI is green.\n\n## Troubleshooting\n\n- **Changelog script fails:** build the changelog manually from the GitHub compare view between the last tag and the release branch (`github.com/mui/<repo>/compare/<lastTag>...<branch>`).\n",".agents/skills/mui-release/stage-2-publish-packages.md":"# Stage 2 — Merge the PR, then publish the packages\n\nRequires stage 1 complete. Before merging, verify the PR still has the `release` label — the publish tooling finds the release PR by it.\n\n1. Just before merging, the user announces a **merge freeze** on the team's Slack channel so nothing else lands until the release and docs deploy are done — as an agent, remind them of this step.\n2. Merge the release PR.\n3. Trigger the publish. It always runs through the repo's `publish.yml` GitHub Actions workflow, never from a local machine:\n   - **CLI:** `pnpm release:publish` (maps to `code-infra publish`) finds the latest merged release PR, asks for confirmation, and dispatches the workflow. To publish from the exact release commit, pass the release PR's merge commit SHA on the default branch: `pnpm release:publish --sha <merge-commit-sha>` (get it with `gh pr view <number> --json mergeCommit`). The interactive picker may pre-select an unrelated commit — never accept the default without checking it's the `[release] vX.Y.Z` merge commit.\n   - **GitHub UI:** open the publish workflow → \"Run workflow\", supplying the release commit SHA and options.\n\n   Common options either way: a dry-run mode for debugging (also as `pnpm release:publish:dry-run` — still a real workflow run needing environment approval), an npm dist-tag for legacy/canary versions, and whether to auto-create the GitHub release. Legacy releases must pass `--sha` explicitly — the picker only sees the latest release PR.\n\n4. The run pauses on the `npm-publish` environment: click \"Review deployments\" and approve it. **Never approve workflow runs you didn't initiate.**\n\n**Stage complete when:** the workflow has published the packages to npm and created a **draft** GitHub release from the changelog.\n\n## Troubleshooting\n\n- **Publish reports \"no new packages to publish\":** the workflow ran against a commit whose package versions are already on npm — usually a wrong SHA (e.g. the picker's pre-selected default). Re-dispatch with `--sha <merge-commit-sha>` of the release PR.\n",".agents/skills/mui-release/stage-3-publish-docs.md":"# Stage 3 — Publish the docs\n\nRequires stage 2 complete (packages published — docs must reference versions that exist on npm).\n\n`pnpm docs:deploy` pushes the release commit to the repo's docs deployment target — a versioned `docs-vX` branch or a dedicated docs repo/branch, mapped to the live docs domain. Force-pushing is expected. Deploys run on Netlify; follow progress on the site's Netlify dashboard. The README documents the branch scheme and URLs.\n\n**Stage complete when:** the Netlify deploy has finished and the docs are live.\n",".agents/skills/mui-release/stage-4-github-release.md":"# Stage 4 — Publish the GitHub release, then announce\n\nRequires stage 3 complete (docs live).\n\n1. Review the draft release on the repo's GitHub releases page and publish it. Mark it correctly for what's being released:\n   - Stable release on the current major → **Set as the latest release**.\n   - Release for an older major → do **not** set as latest — the current major's release must keep the \"Latest\" badge.\n   - Unstable version (alpha/beta/RC) → check **Set as a pre-release** instead.\n2. The user lifts the merge freeze on Slack and follows the team's internal announcement instructions — as an agent, remind them of both.\n\n**Stage complete when:** the GitHub release is public (non-draft) — the release is done. The freeze lift and announcement are on the user's side; remind them.\n",".claude/skills/base-ui-review/SKILL.md":"---\nname: base-ui-review\ndescription: 'Review the current diff for regressions, correctness bugs, tests, simplifications, and docs issues, scaling depth to a low/medium/high/xhigh/max effort level. Use ONLY when explicitly requested by name: the user runs /base-ui-review, writes $base-ui-review, or asks for \"the Base UI review skill\". Do NOT use for general review requests such as \"review my changes\", \"review this diff/branch/PR\", or after finishing an implementation — handle those without this skill unless the user names it. Pass --comment to post a top-level PR comment, --comment inline for inline PR comments, or --fix to apply findings.'\n---\n\n# Base UI Review\n\nThis is the Claude Code entrypoint for the shared repo skill.\n\nOnly run when the user explicitly asks for this skill by name\n(`/base-ui-review`, `$base-ui-review`, \"the Base UI review skill\", or a CI job\nconfigured to use it). Do not trigger on a generic \"review my changes\" request\nor after finishing an implementation.\n\nBefore reviewing, read `.agents/skills/base-ui-review/SKILL.md` completely and\nfollow that canonical workflow. Pass through any user arguments such as `low`,\n`medium`, `high`, `xhigh`, `max`, `--comment`, `--comment inline`, `--fix`, or a\nreview target.\n","AGENTS.md":"# Repository Guidelines\n\nThis repository contains the source code and documentation for Base UI: a headless, unstyled React component library.\n\n## Project structure\n\n- Source code for components and private utils is in `packages/react/`.\n- Source code for public shared utils is in `packages/utils/`.\n- Experiments are located at `docs/src/app/(private)/experiments/`. Use for creating demos that require manual testing in the browser.\n- Public documentation is located at `docs/src/app/(docs)/react/`. Alter the docs where necessary when changes must be visible to library users.\n- When creating public demos on the docs, refer to the `hero` demo for the given component and largely follow its styles (both CSS Modules and Tailwind CSS versions). Other demos may also contain relevant styling. Do not add custom styling beyond the critical layout styles necessary for new demos.\n\n## Agent skills\n\n- The shared `/base-ui-review` skill lives in `.agents/skills/base-ui-review/SKILL.md`. Update that file when the Base UI review workflow changes.\n- Claude Code discovers the same shared skill through `.claude/skills/base-ui-review/SKILL.md`, which delegates to the `.agents` copy.\n- The review skill is opt-in: only run it when the user explicitly asks for it by name (`/base-ui-review`). Do not trigger it from a generic review request or after finishing a change.\n\n## Code guidelines\n\n- Always use the `useTimeout` utility from `@base-ui/utils/useTimeout` instead of `window.setTimeout`, and `useAnimationFrame` from `@base-ui/utils/useAnimationFrame` instead of `requestAnimationFrame`. Search for other example usage in the codebase if unsure how to use them.\n- Use the `useStableCallback` utility from `@base-ui/utils/useStableCallback` instead of `React.useCallback` if the function is called within an effect or event handler. The utility cannot be used to memoize functions that are called directly in the body of a component (during render), so continue with `React.useCallback` in those scenarios.\n- Always use the `useIsoLayoutEffect` utility from `@base-ui/utils/useIsoLayoutEffect` instead of `React.useLayoutEffect`.\n- Always use the shadow DOM-safe utilities for DOM traversal and event targeting: `closest`, `contains`, `getTarget`, and `activeElement`. Always use the owner utilities `ownerDocument` and `ownerWindow` instead of global `document`/`window` lookups when the code is tied to a DOM node, including realm-sensitive checks such as `instanceof`.\n- Avoid duplicating logic where necessary. If two components can share logic (such as event handlers), define the logic/handlers in the parent and share it through a context to the child; use the existing context if it exists.\n\n## Styling\n\n- In CSS Modules demos (`docs/src/app/(docs)/**/demos/**/*.module.css`), use raw color values from the Tailwind `@theme` block in `docs/src/css/index.css`. For example, use `oklch(14.5% 0 0deg)` instead of `var(--color-neutral-950)`.\n- When using `user-select: none;` in CSS, also add `-webkit-user-select: none;` to support Safari. Tailwind's `select-none` class already includes this.\n\n## Linting, typechecking, and formatting\n\n- Do not randomly cast (for example `as any`) if there are no type errors without doing so. Run `pnpm typescript` to verify types.\n- Ensure your changes pass linting - run `pnpm eslint`.\n- Ensure your styles pass stylelint - run `pnpm stylelint`.\n- Ensure your changes are formatted correctly - run `pnpm prettier`.\n- When you change a public component API (props or JSDoc), run `pnpm docs:api`.\n\n## Testing\n\n- If a repository command fails because dependencies are unavailable, run `pnpm i` first and then retry the command.\n- Run tests in jsdom env with `pnpm test:jsdom {name} --no-watch` such as `pnpm test:jsdom NumberField --no-watch` or `pnpm test:jsdom parse --no-watch`.\n- Run tests in Chromium env with `pnpm test:chromium {name} --no-watch` such as `pnpm test:chromium NumberField --no-watch` or `pnpm test:chromium parse --no-watch`.\n- In `@base-ui/react` tests, do not call `await flushMicrotasks()` directly after `await render(...)` when there are no interactions or state changes between them; the `#test-utils` `render` is async and already awaited, so that immediate flush is unnecessary.\n- Do not group multiple `expect()` assertions in a single `waitFor()` callback. Use one assertion per `waitFor()` so retries are scoped to the specific condition that may change asynchronously.\n- For locale-formatted text, use `expect(element.textContent).toBe(expected)` with the expected value formatted using the same locale and options as the component. When the component uses the runtime default locale, derive expectations using that default too (for example, `new Intl.NumberFormat(undefined, options)`); do not hardcode `en-US` or US-formatted strings in expected values. Pin a locale only when testing locale-specific behavior, and use it consistently for both the component and expectations. `toHaveTextContent` normalizes nonbreaking spaces in the rendered text but not in the expected string, causing failures in locales such as `pt-BR`.\n- Use `firePointer` from `#test-utils` instead of `fireEvent.pointer*` whenever a test depends on event timing. `fireEvent` silently drops `timeStamp`, so the event inherits the environment's clock — the real one in a browser — and gesture velocity then depends on how long the runner took between calls. A lint rule enforces this.\n- If you made changes to the source code, ensure you verify your changes by running tests (see above), and writing new tests where applicable. If tests require the browser because, for example, they require layout measurements, restrict it to the Chromium env by using `it.skipIf(isJSDOM)` or `describe.skipIf(isJSDOM)` (search other tests for example usage if unsure).\n- Follow the established conventions in existing tests. Each file/component is tested with the filename `name.test.tsx`. For example, `PopoverRoot.test.tsx` is next to its source file `PopoverRoot.tsx`.\n- Tests use Vitest APIs only: `expect()`, `vi.fn()`, and `@testing-library/jest-dom` DOM matchers. Do not use Chai- or Sinon-style matcher chains or spies.\n- Import `createRenderer`, `describeConformance` and other helpers from `#test-utils`, and use the `user` returned by `await render(...)` instead of creating a Testing Library user-event instance with `userEvent.setup()`.\n- A test must be able to fail when the behavior in its title breaks. Before you finish a test, break that behavior in the source and check that the test fails, then revert. In particular:\n  - Assert the starting state before the action when the end state could already hold (for example, move focus away before testing that it returns).\n  - For \"does not X when <guard>\" tests, use an interaction that would do X without the guard, ideally with a sibling case that flips only the guard and shows X happening.\n  - When the title names an intermediate state (\"while open\", \"after hover\", \"during swipe\"), assert that state right before the action under test.\n  - Fire events the way the component expects them. `fireEvent.click` on a list item is a virtual click that items may ignore; prefer `user.click`. A `preventDefault` spy in a `fireEvent` init object is never called; assert on the boolean `fireEvent` returns instead.\n  - Never put negative assertions inside `waitFor` (they pass on the first poll); flush or advance timers first, then assert synchronously.\n  - Keep assertions in the test body: an `expect` inside a callback that may not run, a conditional, or `Promise.allSettled` can silently pass.\n- Use `it.each` (object rows with `$name` titles) or `describe.each` for tests that differ only in data; don't register tests or suites inside `forEach` or `map`. Every test inside a parametrized block must use the parameter.\n- A test belongs in the file of the part whose prop or behavior it asserts, and under `describe('prop: X')` only if it sets `X`. Titles must describe what the body asserts.\n- Shared behavior across components belongs in a shared suite in `packages/react/test`, exported from `#test-utils`, rather than copied into each component's tests. Existing suites: `describeConformance` (every part), `popupConformanceTests` (popup roots), `popupListConformanceTests` (list interactions in Select, Menu and Combobox popups), `popupFocusPropsTests` (`initialFocus`/`finalFocus`), `dialogRootSharedTests` (Dialog and AlertDialog), `detachedTriggersConformanceTests`, `positionerConformanceTests` and `viewportConformanceTests`. Don't re-test what a suite already covers for the same part; extend the suite instead.\n- After every test, `test/setupVitest.ts` resets `BASE_UI_ANIMATIONS_DISABLED`, mocks, deduplicated errors and warnings, and the animation frame scheduler, and `createRenderer` unmounts what it rendered; don't repeat that per file.\n\n## Commit guidelines\n\n- Commit messages follow the format `[scope] Imperative summary` (for example `[popover] Fix focus trap`). Choose scopes that mirror package or component names that were changed.\n- Use `[all components]` scope for changes that broadly affect most components.\n\n## Errors\n\nThese guidelines apply only to errors thrown by public packages.\n\nEvery error message must:\n\n1. **Say what happened** - Describe the problem clearly\n2. **Say why it's a problem** - Explain the consequence\n3. **Point toward how to solve it** - Give actionable guidance\n\nFormat:\n\n- Prefix with `Base UI:`\n- Use string concatenation for readability\n- Include a documentation link when applicable (`https://base-ui.com/...`)\n\n### Error Minifier\n\nYou MUST run `pnpm extract-error-codes` to update `docs/src/error-codes.json` every time you add or update an error message in an `Error` constructor.\n\n**Important:** If the update created a new error code, but the new and original message have the same number of arguments and semantics haven't changed, update the original error in `error-codes.json` instead of creating a new code.\n\nBefore any changes, review [CONTRIBUTING.md](./CONTRIBUTING.md) for more detailed guidelines on contributing to this repository.\n","CLAUDE.md":"@AGENTS.md\n","packages/react/README.md":"<!-- lint disable mui-first-block-heading -->\n\n<a href=\"https://base-ui.com\" target=\"_blank\"><img width=\"150\" height=\"133\" src=\"https://base-ui.com/static/logo.svg\" alt=\"Base UI logo\"></a>\n\nBase UI is a library of unstyled React components. You gain complete control over your app's CSS and accessibility features.\n\n## Installation\n\nInstall the package in your project directory with:\n\n```bash\nnpm install @base-ui/react\n```\n\n## Documentation\n\n<!-- #default-branch-switch -->\n\nVisit [base-ui.com](https://base-ui.com) to view the full documentation.\n\n## Questions\n\nFor how-to questions that don't involve making changes to the code base, please use [Stack Overflow](https://stackoverflow.com/questions/tagged/base-ui) instead of GitHub issues.\nUse the \"base-ui\" tag on Stack Overflow to make it easier for the community to find your question.\n\n## Contributing\n\nRead the [contributing guide](../../CONTRIBUTING.md) to learn about our development process, how to propose bug fixes and improvements, and how to build and test your changes.\n\nContributing to Base UI is about more than just issues and pull requests!\nThere are many other ways to [support Base UI](https://mui.com/material-ui/getting-started/faq/#mui-is-awesome-how-can-i-support-the-project) beyond contributing to the code base.\n\n## Changelog\n\nThe [changelog](https://github.com/mui/base-ui/releases) is regularly updated to reflect what's changed in each new release.\n\n## Roadmap\n\nFuture plans and high-priority features and enhancements can be found in the [roadmap](https://github.com/orgs/mui/projects/1).\n\n## License\n\nThis project is licensed under the terms of the [MIT license](../../LICENSE).\n\n## Security\n\nFor details of supported versions and contact details for reporting security issues, please refer to the [security policy](https://github.com/mui/base-ui/security/policy).\n","packages/utils/README.md":"# @base-ui/utils\n\nA collection of React utility functions for Base UI.\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/mui/base-ui/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# Repository Guidelines\n\nThis repository contains the source code and documentation for Base UI: a headless, unstyled React component library.\n\n## Project structure\n\n- Source code for components and private utils is in `packages/react/`.\n- Source code for public shared utils is in `packages/utils/`.\n- Experiments are located at `docs/src/app/(private)/experiments/`. Use for creating demos that require manual testing in the browser.\n- Public documentation is located at `docs/src/app/(docs)/react/`. Alter the docs where necessary when changes must be visible to library users.\n- When creating public demos on the docs, refer to the `hero` demo for the given component and largely follow its styles (both CSS Modules and Tailwind CSS versions). Other demos may also contain relevant styling. Do not add custom styling beyond the critical layout styles necessary for new demos.\n\n## Agent skills\n\n- The shared `/base-ui-review` skill lives in `.agents/skills/base-ui-review/SKILL.md`. Update that file when the Base UI review workflow changes.\n- Claude Code discovers the same shared skill through `.claude/skills/base-ui-review/SKILL.md`, which delegates to the `.agents` copy.\n- The review skill is opt-in: only run it when the user explicitly asks for it by name (`/base-ui-review`). Do not trigger it from a generic review request or after finishing a change.\n\n## Code guidelines\n\n- Always use the `useTimeout` utility from `@base-ui/utils/useTimeout` instead of `window.setTimeout`, and `useAnimationFrame` from `@base-ui/utils/useAnimationFrame` instead of `requestAnimationFrame`. Search for other example usage in the codebase if unsure how to use them.\n- Use the `useStableCallback` utility from `@base-ui/utils/useStableCallback` instead of `React.useCallback` if the function is called within an effect or event handler. The utility cannot be used to memoize functions that are called directly in the body of a component (during render), so continue with `React.useCallback` in those scenarios.\n- Always use the `useIsoLayoutEffect` utility from `@base-ui/utils/useIsoLayoutEffect` instead of `React.useLayoutEffect`.\n- Always use the shadow DOM-safe utilities for DOM traversal and event targeting: `closest`, `contains`, `getTarget`, and `activeElement`. Always use the owner utilities `ownerDocument` and `ownerWindow` instead of global `document`/`window` lookups when the code is tied to a DOM node, including realm-sensitive checks such as `instanceof`.\n- Avoid duplicating logic where necessary. If two components can share logic (such as event handlers), define the logic/handlers in the parent and share it through a context to the child; use the existing context if it exists.\n\n## Styling\n\n- In CSS Modules demos (`docs/src/app/(docs)/**/demos/**/*.module.css`), use raw color values from the Tailwind `@theme` block in `docs/src/css/index.css`. For example, use `oklch(14.5% 0 0deg)` instead of `var(--color-neutral-950)`.\n- When using `user-select: none;` in CSS, also add `-webkit-user-select: none;` to support Safari. Tailwind's `select-none` class already includes this.\n\n## Linting, typechecking, and formatting\n\n- Do not randomly cast (for example `as any`) if there are no type errors without doing so. Run `pnpm typescript` to verify types.\n- Ensure your changes pass linting - run `pnpm eslint`.\n- Ensure your styles pass stylelint - run `pnpm stylelint`.\n- Ensure your changes are formatted correctly - run `pnpm prettier`.\n- When you change a public component API (props or JSDoc), run `pnpm docs:api`.\n\n## Testing\n\n- If a repository command fails because dependencies are unavailable, run `pnpm i` first and then retry the command.\n- Run tests in jsdom env with `pnpm test:jsdom {name} --no-watch` such as `pnpm test:jsdom NumberField --no-watch` or `pnpm test:jsdom parse --no-watch`.\n- Run tests in Chromium env with `pnpm test:chromium {name} --no-watch` such as `pnpm test:chromium NumberField --no-watch` or `pnpm test:chromium parse --no-watch`.\n- In `@base-ui/react` tests, do not call `await flushMicrotasks()` directly after `await render(...)` when there are no interactions or state changes between them; the `#test-utils` `render` is async and already awaited, so that immediate flush is unnecessary.\n- Do not group multiple `expect()` assertions in a single `waitFor()` callback. Use one assertion per `waitFor()` so retries are scoped to the specific condition that may change asynchronously.\n- For locale-formatted text, use `expect(element.textContent).toBe(expected)` with the expected value formatted using the same locale and options as the component. When the component uses the runtime default locale, derive expectations using that default too (for example, `new Intl.NumberFormat(undefined, options)`); do not hardcode `en-US` or US-formatted strings in expected values. Pin a locale only when testing locale-specific behavior, and use it consistently for both the component and expectations. `toHaveTextContent` normalizes nonbreaking spaces in the rendered text but not in the expected string, causing failures in locales such as `pt-BR`.\n- Use `firePointer` from `#test-utils` instead of `fireEvent.pointer*` whenever a test depends on event timing. `fireEvent` silently drops `timeStamp`, so the event inherits the environment's clock — the real one in a browser — and gesture velocity then depends on how long the runner took between calls. A lint rule enforces this.\n- If you made changes to the source code, ensure you verify your changes by running tests (see above), and writing new tests where applicable. If tests require the browser because, for example, they require layout measurements, restrict it to the Chromium env by using `it.skipIf(isJSDOM)` or `describe.skipIf(isJSDOM)` (search other tests for example usage if unsure).\n- Follow the established conventions in existing tests. Each file/component is tested with the filename `name.test.tsx`. For example, `PopoverRoot.test.tsx` is next to its source file `PopoverRoot.tsx`.\n- Tests use Vitest APIs only: `expect()`, `vi.fn()`, and `@testing-library/jest-dom` DOM matchers. Do not use Chai- or Sinon-style matcher chains or spies.\n- Import `createRenderer`, `describeConformance` and other helpers from `#test-utils`, and use the `user` returned by `await render(...)` instead of creating a Testing Library user-event instance with `userEvent.setup()`.\n- A test must be able to fail when the behavior in its title breaks. Before you finish a test, break that behavior in the source and check that the test fails, then revert. In particular:\n  - Assert the starting state before the action when the end state could already hold (for example, move focus away before testing that it returns).\n  - For \"does not X when <guard>\" tests, use an interaction that would do X without the guard, ideally with a sibling case that flips only the guard and shows X happening.\n  - When the title names an intermediate state (\"while open\", \"after hover\", \"during swipe\"), assert that state right before the action under test.\n  - Fire events the way the component expects them. `fireEvent.click` on a list item is a virtual click that items may ignore; prefer `user.click`. A `preventDefault` spy in a `fireEvent` init object is never called; assert on the boolean `fireEvent` returns instead.\n  - Never put negative assertions inside `waitFor` (they pass on the first poll); flush or advance timers first, then assert synchronously.\n  - Keep assertions in the test body: an `expect` inside a callback that may not run, a conditional, or `Promise.allSettled` can silently pass.\n- Use `it.each` (object rows with `$name` titles) or `describe.each` for tests that differ only in data; don't register tests or suites inside `forEach` or `map`. Every test inside a parametrized block must use the parameter.\n- A test belongs in the file of the part whose prop or behavior it asserts, and under `describe('prop: X')` only if it sets `X`. Titles must describe what the body asserts.\n- Shared behavior across components belongs in a shared suite in `packages/react/test`, exported from `#test-utils`, rather than copied into each component's tests. Existing suites: `describeConformance` (every part), `popupConformanceTests` (popup roots), `popupListConformanceTests` (list interactions in Select, Menu and Combobox popups), `popupFocusPropsTests` (`initialFocus`/`finalFocus`), `dialogRootSharedTests` (Dialog and AlertDialog), `detachedTriggersConformanceTests`, `positionerConformanceTests` and `viewportConformanceTests`. Don't re-test what a suite already covers for the same part; extend the suite instead.\n- After every test, `test/setupVitest.ts` resets `BASE_UI_ANIMATIONS_DISABLED`, mocks, deduplicated errors and warnings, and the animation frame scheduler, and `createRenderer` unmounts what it rendered; don't repeat that per file.\n\n## Commit guidelines\n\n- Commit messages follow the format `[scope] Imperative summary` (for example `[popover] Fix focus trap`). Choose scopes that mirror package or component names that were changed.\n- Use `[all components]` scope for changes that broadly affect most components.\n\n## Errors\n\nThese guidelines apply only to errors thrown by public packages.\n\nEvery error message must:\n\n1. **Say what happened** - Describe the problem clearly\n2. **Say why it's a problem** - Explain the consequence\n3. **Point toward how to solve it** - Give actionable guidance\n\nFormat:\n\n- Prefix with `Base UI:`\n- Use string concatenation for readability\n- Include a documentation link when applicable (`https://base-ui.com/...`)\n\n### Error Minifier\n\nYou MUST run `pnpm extract-error-codes` to update `docs/src/error-codes.json` every time you add or update an error message in an `Error` constructor.\n\n**Important:** If the update created a new error code, but the new and original message have the same number of arguments and semantics haven't changed, update the original error in `error-codes.json` instead of creating a new code.\n\nBefore any changes, review [CONTRIBUTING.md](./CONTRIBUTING.md) for more detailed guidelines on contributing to this repository.\n","isInternal":false,"tokens":2287,"sizeBytes":10111},{"name":"CLAUDE.md","path":"CLAUDE.md","rawUrl":"https://raw.githubusercontent.com/mui/base-ui/HEAD/CLAUDE.md","title":"Claude Agent Guidelines & System Prompt","category":"claude-rule","format":"markdown","content":"@AGENTS.md\n","isInternal":false,"tokens":5,"sizeBytes":11},{"name":"openai.yaml","path":".agents/skills/base-ui-review/agents/openai.yaml","rawUrl":"https://raw.githubusercontent.com/mui/base-ui/HEAD/.agents/skills/base-ui-review/agents/openai.yaml","title":"Agents Skill","category":"anthropic-skill","format":"yaml","content":"interface:\n  display_name: 'Base UI Review'\n  short_description: 'Review Base UI diffs for bugs, tests, cleanup, docs'\n  default_prompt: 'Use $base-ui-review to review my current diff.'\n","isInternal":false,"tokens":45,"sizeBytes":186},{"name":"SKILL.md","path":".agents/skills/base-ui-review/SKILL.md","rawUrl":"https://raw.githubusercontent.com/mui/base-ui/HEAD/.agents/skills/base-ui-review/SKILL.md","title":"base-ui-review","category":"anthropic-skill","format":"markdown","content":"---\nname: base-ui-review\ndescription: 'Review the current diff for regressions, correctness bugs, tests, simplifications, and docs issues, scaling depth to a low/medium/high/xhigh/max effort level. Use ONLY when explicitly requested by name: the user runs /base-ui-review, writes $base-ui-review, or asks for \"the Base UI review skill\". Do NOT use for general review requests such as \"review my changes\", \"review this diff/branch/PR\", or after finishing an implementation — handle those without this skill unless the user names it. Pass --comment to post a top-level PR comment, --comment inline for inline PR comments, or --fix to apply findings.'\n---\n\n# Base UI Review\n\nReview current diff. Find **regressions and correctness bugs** first. Also find\n**cleanup** (reuse / simplification / efficiency). Default effort: `medium`. See\n[Effort levels](#effort-levels) for depth and subagent fan-out.\n\nArgument hint: `[low|medium|high|xhigh|max] [--fix] [--comment [inline]] [<target>]`\n\nThis skill is **opt-in only**: run it when the user explicitly asks for it by\nname (`/base-ui-review`, `$base-ui-review`, \"the Base UI review skill\", or a CI\njob configured to use it). A plain \"review my changes\" or \"review this PR\", or\nwrapping up an implementation, is not an invocation — review without this\nworkflow unless the user names it.\n\n`medium` = **precision**. Every finding actionable. `high`, `xhigh`, `max` =\n**recall**. Missed bug ships. Keep uncertain findings when mechanism is real;\nlabel them clearly.\n\n## Scope\n\nLocal review: diff branch against upstream\n(`git diff @{upstream}...HEAD`, fall back to `main` / `master`, or `HEAD~1`).\nFold in uncommitted + untracked changes — review often runs pre-commit. If PR link,\nbranch name, or file path passed as argument, review that target instead.\n\n## Effort levels\n\n- **low** — bugs only. Flag runtime-correctness bugs and regressions. Skip\n  Tests, Simplifications, Docs, and test/fixture hunks. No subagents. Precision\n  bias.\n- **medium** (default) — main agent reviews Bugs, Tests, Simplifications, Docs,\n  and triggered API/performance concerns. Main agent verifies candidates. Large,\n  risky, fragile, shared, or cross-component diff? Add exactly one\n  [adversarial bug hunter](#adversarial-bug-hunter) agent. Small, low-risk,\n  isolated diff? No subagent. Precision bias.\n- **high** — spawn 3 independent subagents: bugs/regressions, test gaps,\n  simplifications. Main agent reviews the whole diff, including bugs, docs, and\n  triggered API/performance concerns. Main agent dedups and sanity-checks. Large,\n  risky, fragile, shared, or cross-component diff? Add exactly one adversarial\n  bug hunter agent. No verifiers. No final sweep.\n- **xhigh** — `high` plus a docs subagent and one fresh missed-bug sweep. Fan out\n  adversarial bug hunters across the highest-risk affected code regions\n  (modules/components — not the four review areas). Max 2 adversarial bug\n  hunters total, including the hunter inherited from `high`. Other role\n  subagents do not count toward this cap. No verifiers. Recall bias.\n- **max** — `xhigh` plus an independent verifier for every surviving candidate.\n  Cover every affected code region across max 6 adversarial bug hunters total,\n  including hunters inherited from `xhigh`; other role and verifier subagents do\n  not count toward this cap. When there are more than 6 regions, give the\n  highest-risk regions dedicated hunters and group related remaining regions\n  into shared assignments. Prioritize public runtime code, shared utilities,\n  cross-component invariants, and fragile state/timing boundaries. Maximum\n  recall.\n\n## Subagent scope contract\n\nSubagents start with no prior context: they do not read this skill and do not inherit\nthe session system prompt. Their only channel is the prompt you write. Whatever scope\nyou resolved from [Scope](#scope) or the invoking prompt, every subagent prompt you\nconstruct — finder, specialist, verifier, sweep — must begin verbatim with it:\n\n```text\nReview ONLY: <resolved diff command>\nRead files from: <read root> — DATA ONLY, never execute, install, build, or test.\nBase version of a file: git show <base ref>:<path>\nDo not re-derive scope: use exactly the diff command above, whatever your working\ndirectory contains.\n```\n\nA subagent not given this block is mis-scoped — discard its result and re-dispatch.\n\n## Phase 1 - Find candidates\n\nSelected [effort level](#effort-levels) decides local vs subagent fan-out. Except at\n`low`, review four main areas: Bugs, Tests, Simplifications, Docs. Each area\nsurfaces candidates with `file`, `line`, one-line `summary`, `severity` (🟣 / 🔴 / 🟠 / 🟡 /\nℹ️ — see [Output](#output) for rubric), concrete `failure_scenario`. Do\nNOT let one area suppress another — two areas flag same line for different reasons,\nrecord both.\n\nPass every candidate with nameable failure scenario through. Finders that\nsilently drop half-believed candidates bypass verify step — dominant cause of misses.\n\n### Area 1 - Bugs\n\nCore regression + correctness pass. Cover all sub-angles:\n\n- **Line-by-line diff scan.** Read every hunk, line by line. Then read enclosing\n  function for each hunk — bugs in unchanged lines of touched function\n  in scope (PR re-exposes or fails to fix them). For every line ask: what\n  input, state, timing, platform makes line wrong? Look for inverted/wrong\n  conditions, off-by-one, null/undefined deref, missing `await`, falsy-zero checks,\n  wrong-variable copy-paste, error swallowed in catch, unescaped regex metachars.\n- **Regression hunting.** For each changed guard, branch, state transition, public\n  contract, test expectation, documented example, ask what behavior previously\n  worked and could break. Bias toward regressions in edge paths, accessibility\n  interactions, keyboard/focus flows, controlled/uncontrolled contracts, SSR,\n  integrations between components, public API examples.\n- **Repository/framework correctness lens.** Apply invariants of codebase\n  under review, not just generic language bugs. For Base UI / React component\n  changes: controlled vs uncontrolled behavior, event ordering, ref\n  forwarding/merging, context registration cleanup, nested component coordination,\n  portals, focus management, keyboard navigation, ARIA attributes, disabled/read-only\n  states, form integration, SSR/hydration safety, Strict Mode behavior, shadow\n  DOM-safe DOM access (`closest`, `contains`, `getTarget`, `activeElement`, `ownerDocument`,\n  `ownerWindow`).\n- **Removed-behavior auditor.** For every line diff DELETES or replaces, name\n  invariant/behavior it enforced, then search new code for where invariant\n  re-established. Can't find it? Candidate: removed\n  guard, dropped error path, narrowed validation, deleted test covering real case.\n- **Cross-file tracer.** For each function diff changes, find callers (Grep\n  symbol) and check if change breaks any call site: new\n  precondition, changed return shape, new exception, timing/ordering\n  dependency. Also check callees: parallel change in same PR make call\n  unsafe?\n\n### Area 2 - Tests\n\nReview test changes and tests that _should_ have changed. Flag:\n\n- New/changed behavior with no test exercising it\n- Assertions not actually pinning behavior (asserting mock called instead of\n  result, snapshot-only coverage, asserting on value test itself computed)\n- Missing edge/error-path cases diff introduces (null, empty, boundary, failure,\n  concurrency)\n- Setup/teardown asymmetry (state leaked between tests, fixtures not reset)\n- Over-mocking hiding real contract\n- Tests deleted or weakened without justification\n- Tests whose names do not match what they assert, or whose names are misleading\n\nName specific case untested or under-asserted.\n\n### Area 3 - Simplifications\n\nBundle size is a top constraint. Smallest correct implementation wins. Preserve\npublic behavior, runtime performance, and maintainability. Treat every bundle\nsize increase as suspect — new bytes must earn their place; flag increases the\ndiff doesn't justify.\n\nAlways ask: \"Can this ship with less code, state, branching, or abstraction?\"\nLook for:\n\n- Heavy dependency or new abstraction where a few lines or existing util does\n  the job\n- Code doing too much for an edge case almost no one hits — guards, branches,\n  state, or config for scenarios not realistically reachable in consumer usage;\n  weigh handling cost against edge-case likelihood and propose dropping or\n  cheapening it\n- Duplicated logic re-implementing what codebase already has — Grep\n  shared/utility modules and files adjacent to change; name existing helper to\n  call instead\n- Non-tree-shakeable or whole-package imports; namespace imports of\n  side-effectful modules\n- Dead code left behind; redundant or derivable state\n- Special cases layered on shared infrastructure when mechanism should\n  generalize\n\nName smaller or better-shaped form doing same job. Measure real bundle effect\nwhen material. Source-line count proves nothing.\n\n### Area 4 - Docs\n\nFlag documentation and comments diff makes wrong or leaves stale:\n\n- Comments describing old behavior after code changed\n- JSDoc/docstrings whose params, return type, thrown errors no longer match\n  signature\n- README / API docs / changelog entries contradicting change; examples no longer\n  compile or run\n- TODO/FIXME change resolved but didn't remove; new non-obvious code with no\n  explanation where warranted\n\nQuote stale line and state what it should say.\n\n### Conditional specialist - API design\n\nNot part of default four-area fan-out. Skip entirely at\n`low`. At `medium`, include in main-agent pass when diff adds/changes\npublic API surface: component, prop, event, hook, provider, imperative method,\nexported type, value shape, behavior contract, docs example teaching API.\nAt `high`, `xhigh`, `max`, run as independent API design subagent when\ntriggered.\n\nHeavily critique API taste: naming, mental model, consistency with\nnearby APIs in same codebase, controlled/uncontrolled ergonomics, composition,\nescape hatches, type shape, default behavior, future extensibility, migration risk,\nlikely user footguns. Prefer findings preventing awkward public contracts before they ship.\nReport API design findings under Bugs when they create likely user-visible footguns\nor regressions, otherwise under Simplifications.\n\n### Conditional specialist - Runtime performance\n\nNot part of default four-area fan-out. Skip entirely at\n`low`. At `medium`, include in main-agent pass when diff likely affects\nruntime performance: render hot paths, large item collections, virtualization,\npositioning, layout measurement, scroll/resize/pointer/keyboard handlers,\nobservers, animations, repeated DOM reads/writes, state updates in loops,\ncomponent registration/lookup paths. At `high`, `xhigh`, `max`, run as\nindependent runtime performance subagent when triggered.\n\nPrefer concrete measurement when feasible: existing perf tests, targeted benchmark\nscripts, small reproducible measurement. If measuring not practical, state\nexpected complexity or browser work and what would confirm it. Report runtime\nperformance findings under Bugs when users can see lag, jank, hangs, excessive\nwork, otherwise under Simplifications.\n\n### Adversarial bug hunter\n\nSubagent role added per [Effort levels](#effort-levels). Assume there are bugs\nin the diff a consumer will hit. Do not trust PR description, comments, or test\nnames — verify against code. Attack changed invariants directly: construct\nconcrete input, state, timing, or platform that makes new code wrong. Report\nevery candidate with a nameable failure scenario; when none survive, report\nempty — never pad with weak findings to justify the hunt.\n\n---\n\nSimplification, test, docs candidates use same `file`/`line`/`summary`\nshape; in `failure_scenario`, state concrete cost (what duplicated, wasted,\nuntested, stale, harder to maintain) instead of crash. Regressions and\ncorrectness bugs always outrank simplification, test, docs findings when\nreview ordered.\n\n## Phase 2 - Verify candidates (local by default; max adds subagent votes)\n\nDedup candidates pointing at same line/mechanism, keep one with\nmost concrete failure scenario. Verify candidates locally in main agent by\ndefault.\n\nJudge every candidate by reachability and impact. Keep every valid bug. Demote\nto ℹ️ note when behavior not realistically reachable in real consumer usage,\nhas no meaningful user impact, or is optional improvement rather than\ncorrectness defect. Demotion is not refutation — demoted findings still print,\nat lower severity. At `max` effort, also run **one verifier** as subagent for each\nremaining candidate when subagents available and authorized: give it diff,\nrelevant file(s), candidate, have it return exactly one of:\n\n- **CONFIRMED** — can name inputs/state triggering it and wrong output or\n  crash. Quote line.\n- **PLAUSIBLE** — mechanism real, trigger uncertain (timing, env, config).\n  State what would confirm it.\n- **REFUTED** — factually wrong (code doesn't say that) or guarded elsewhere. Quote\n  line proving it.\n\nKeep candidates where vote CONFIRMED or PLAUSIBLE.\n\nAt **max**, verify recall-biased — **PLAUSIBLE by default**: do not\nrefute candidate for being \"speculative\" or \"depends on runtime state\" when\nstate realistic (concurrency races, nil/undefined on rare-but-reachable path,\nfalsy-zero treated as missing, off-by-one on boundary code doesn't exclude,\nretry storms / partial failures, regex/allowlist lost anchor). REFUTE only\nwhen constructible from code: factually wrong, provably impossible, already\nhandled in this diff, pure style with no observable effect.\n\n## Phase 3 - Sweep for gaps (xhigh / max effort)\n\nAt `xhigh` and `max`, run **one more finder** as fresh reviewer with\ncurrent finding list. Re-read diff and enclosing functions looking ONLY for\ndefects not already listed. Do not re-derive or re-confirm anything already there —\njob is gaps. Focus on what first pass misses: moved/extracted code\ndropping guard or anchor; second-tier footguns (dataclass default evaluated\nonce, `hash()` non-determinism, lock-scope shrink, predicate methods with side\neffects); setup/teardown asymmetry in tests; config defaults flipped. Surface\nadditional candidates naming defect not already on list. If nothing new,\nreturn empty sweep — do not pad.\n\n## Output\n\nReply in Markdown. Do not wrap main result in JSON or code fence. Use\nsentence case for `#` heading and all finding titles; no title case. Do\nnot open with generic target/base filler like \"Reviewed `owner/repo#123` against\n`branch`.\" Only mention target or base branch when explaining specific\nfinding or limitation.\n\nPrint only non-empty category sections, in this order: `Bugs`, `Tests`,\n`Simplifications`, `Docs`. A category with 0 findings gets nothing — no\nheading, no count, no `No findings.` placeholder. Always end with `Verdict`.\nBefore sending, verify every surviving finding prints exactly once and each\nprinted section count matches its numbered findings. When no findings exist\nanywhere, use the [No findings](#no-findings) format.\n\n### Severity rubric\n\nPrefix every finding title with one severity marker:\n\n- 🟣 **critical - blocking.** Correctness issue crashing common flows, losing\n  user data, creating security/privacy problem, making public component contract\n  unusable, or creating broad cross-component accessibility, focus, form, SSR\n  breakage. Must block merge.\n- 🔴 **high - blocking.** Realistic user-visible regression in normal component\n  usage, accessibility, keyboard/focus behavior, controlled/uncontrolled behavior,\n  form integration, SSR/hydration, public API behavior, or public docs example\n  no longer compiling or teaching broken API usage. Should block merge even\n  when affected path has workaround or not most common path.\n- 🟠 **medium - non-blocking.** Real issue worth fixing before merge when\n  practical but not normally blocking: narrow or uncommon bug, meaningful missing\n  test, stale public-doc prose not breaking copy-pasted code, cleanup\n  avoiding likely future mistakes. Use only when issue doesn't break public\n  contract and doesn't affect accessibility, focus, forms, SSR, or normal component\n  usage.\n- 🟡 **low - non-blocking.** Minor edge-case bug, small test/doc gap, modest\n  simplification useful but easy for maintainers to defer.\n- ℹ️ **note.** Informational — observation, heads-up, optional suggestion the\n  maintainer may reasonably decline.\n\nBase UI has stricter quality bar than most apps — small component-library\nregressions multiplied across many downstream products. When choosing between\nadjacent severities, choose higher severity if failure reaches realistic\nconsumer usage, accessibility behavior, form behavior, focus management, SSR,\npublic API contract or broken public docs example. Do not reserve 🔴 high only for\noutage-level failures.\n\nWithin each section, order findings 🟣 -> 🔴 -> 🟠 -> 🟡 -> ℹ️.\n\n### Verdict\n\nEnd review with `## Verdict` line derived from markers:\n\n- **Request changes** — at least one 🟣 or 🔴 finding.\n- **Approve after nits** — no 🟣 or 🔴, but one or more 🟠 or 🟡 findings worth\n  addressing.\n- **Approve** — no 🟣, 🔴, 🟠, 🟡 findings (only ℹ️ notes, or nothing).\n\nFollow verdict with one clause naming deciding factor.\n\n### Finding format\n\nUse this structure. Omit any category block whose count is zero:\n\n````md\n# PR review\n\nOne to three sentences summarizing the concrete risk, most important theme, and\nany meaningful verification limit. State up front whether anything is merge-blocking.\nIf there are no actionable findings, say that clearly.\n\n## Bugs ({count})\n\n### 1. {severity marker} {Sentence-case title}\n\n**Location:** `path/to/file.ext:123`\n\n```tsx\n// Small relevant code excerpt from the reviewed file.\n```\n\n{Description of what is wrong and why it matters.}\n\n**Failure scenario:** {Simple, obvious user-facing or example issue someone would\nsee.}\n\n**Fix:** {Specific recommended change.}\n\n## Tests ({count})\n\n## Simplifications ({count})\n\n## Docs ({count})\n\n## Verdict\n\n**{Request changes | Approve after nits | Approve}** - {one clause on the deciding factor}.\n\n---\n\n🤖 Review generated with {Claude Code | Codex}\n````\n\nSame per-finding shape for Tests, Simplifications, Docs. For Tests,\nmake failure scenario the missing case or weak assertion. For Simplifications,\nmake it concrete duplicated, heavier, or harder-to-maintain code path. For Docs,\nmake it stale or missing public/developer-facing information.\n\n### Finding quality\n\nDo not cap findings by count. Report every verified, actionable finding\nmaintainer would reasonably fix before merging. Do not pad review with weak,\nstylistic, speculative, low-importance notes. If many findings survive, group\nrelated issues under one finding when they share same root cause.\n\n### No findings\n\nIf nothing survives verification, omit all category headings and counts. Return\n`# PR review`, `No findings.`, a brief note of residual test gaps or risk,\n`## Verdict` with **Approve**, and the `🤖 Review generated with ...` footer.\n\n### Final output preflight\n\nTreat the output format as a hard contract. Before sending:\n\n- Use `# PR review`; start the summary with concrete risk, not target/base filler.\n- Use exact `## {Category} ({count})` headings for non-empty categories only.\n- Print each finding exactly once and verify every category count.\n- Use a separate `## Verdict` heading and the required closing footer.\n\nIf any check fails, rewrite the output before sending.\n\nAlways close review with `---` horizontal rule, blank line, then\n`🤖 Review generated with {Claude Code | Codex}`. Use **Claude Code** when this\nskill executed by Claude Code harness, **Codex** when executed by Codex harness.\n\n## Posting to GitHub (--comment)\n\nPost to GitHub only when target is GitHub PR and arguments include\ncomment mode:\n\n- No `--comment` — do not post to GitHub; if `--fix` also absent, stop at\n  Markdown review report.\n- `--comment` — post Markdown review as one top-level PR comment via\n  `gh pr comment`.\n- `--comment inline` — post inline comments for findings mapping to PR diff\n  lines, include all non-diff findings in top-level fallback comment.\n\nFor `--comment inline`, include same severity marker in each inline comment\nbody. Use latest PR head `commit_id`, `path`, `line`, `side`, post via\n`gh api` (`repos/{owner}/{repo}/pulls/{pr}/comments`), one call per finding. Include\nsuggestion block only when it fully fixes issue. (If GitHub inline-comment\nMCP tool available in session, use instead.)\n\nInline comments can only attach to lines present in PR diff. Put findings\noutside PR diff (unchanged lines in touched functions) in top-level\nfallback comment via `gh pr comment`; do not drop them or stop posting rest of\nreview because one inline comment not commentable. If target not\nPR, print findings to terminal and note `--comment` was ignored.\n\n## Applying fixes (--fix)\n\nIf `--fix` flag passed in arguments, after producing findings\nlist, apply findings to working tree instead of stopping at report: fix\neach one directly — correctness bugs and reuse/simplification/efficiency cleanups\nalike. Skip any finding whose fix would change intended behavior, require changes\nwell outside reviewed diff, or you judge false positive — note\nskip rather than arguing with it. Finish with brief summary of what fixed and\nwhat skipped.\n\nIf neither `--comment` nor `--fix` passed, stop at Markdown review report.\n","frontmatter":{"name":"base-ui-review","description":"Review the current diff for regressions, correctness bugs, tests, simplifications, and docs issues, scaling depth to a low/medium/high/xhigh/max effort level. Use ONLY when explicitly requested by name: the user runs /base-ui-review, writes $base-ui-review, or asks for \"the Base UI review skill\". Do NOT use for general review requests such as \"review my changes\", \"review this diff/branch/PR\", or after finishing an implementation — handle those without this skill unless the user names it. Pass --comment to post a top-level PR comment, --comment inline for inline PR comments, or --fix to apply findings."},"isInternal":false,"tokens":4844,"sizeBytes":21527},{"name":"SKILL.md","path":".agents/skills/mui-release/SKILL.md","rawUrl":"https://raw.githubusercontent.com/mui/base-ui/HEAD/.agents/skills/mui-release/SKILL.md","title":"mui-release","category":"anthropic-skill","format":"markdown","content":"---\nname: mui-release\ndescription: Run or assist a release in any MUI repo, at any stage - release PR, npm publish, docs deploy, GitHub release.\nargument-hint: '[target-version]'\n---\n\n# MUI Release\n\nEvery MUI repo releases through the same staged pipeline. Each stage depends on the previous one completing — never start a stage before its predecessor is done. This skill describes the shared skeleton; the details vary per repo.\n\n**Resumable:** the skill can be invoked at any stage — a release often spans multiple sessions (e.g. the PR was created and merged earlier, and the user now wants to trigger the npm publish). In the pipeline diagram below, each arrow out of a stage states the observable evidence that the stage is complete: resume at the first stage whose evidence is missing. Confirm the detected stage with the user before continuing; earlier stages' outputs are inputs, not work to redo.\n\n**Source of truth:** the target repo's `scripts/README.md` is the authoritative, evolving runbook. Always read it in the target checkout before releasing; use this skill to know what the stages mean and what to expect. Where the README contradicts this skill, the README wins. Repo-specific steps (docs release pages, hotfix flows, prerelease progressions, docs-only deploys, first-time package publishing) live only there. Repos without that runbook: read their release workflow directly.\n\n## The pipeline\n\nEach stage's instructions live in its own file — after detecting and confirming the current stage, read **that stage's file**:\n\n```mermaid\nflowchart TD\n    S1[\"Stage 1: Prepare the release PR\\n(stage-1-prepare-pr.md)\"]\n    S2[\"Stage 2: Merge the PR, then publish\\n(stage-2-publish-packages.md)\"]\n    S3[\"Stage 3: Publish the docs\\n(stage-3-publish-docs.md)\"]\n    S4[\"Stage 4: Publish the GitHub release, then announce\\n(stage-4-github-release.md)\"]\n\n    S1 -- \"open PR with the release label,\\napproved, CI green\" --> S2\n    S2 -- \"release PR merged, packages on npm at\\nthe new version, draft GitHub release created\" --> S3\n    S3 -- \"docs live for the new version\" --> S4\n    S4 -- \"published non-draft GitHub release for the\\ncurrent root package.json version\\n(release done, next one starts at Stage 1)\" --> S1\n```\n\nVerify each stage's evidence with read-only commands (run in the target checkout; `<version>` is the root `package.json` version):\n\n```bash\n# release PR: open (stage 1) or merged (stage 2 done merging)\ngh pr list --label release --state open --json number,title,reviewDecision\ngh pr list --label release --state merged --limit 1 --json number,title,mergedAt\ngh pr checks <number>                      # CI green?\n\n# packages on npm at the new version\nnpm view <main-package>@<version> version\n\n# GitHub release: exists? still a draft?\ngh release list --limit 5 --json tagName,isDraft,isLatest\ngh release view \"v<version>\" --json tagName,isDraft\n\n# docs live for the new version\ncurl -s <docs-url> | grep \"<version>\"      # or check the Netlify dashboard\n```\n","frontmatter":{"name":"mui-release","description":"Run or assist a release in any MUI repo, at any stage - release PR, npm publish, docs deploy, GitHub release.","argument-hint":"[target-version]"},"isInternal":false,"tokens":714,"sizeBytes":2999},{"name":"stage-1-prepare-pr.md","path":".agents/skills/mui-release/stage-1-prepare-pr.md","rawUrl":"https://raw.githubusercontent.com/mui/base-ui/HEAD/.agents/skills/mui-release/stage-1-prepare-pr.md","title":"Mui-release Skill","category":"anthropic-skill","format":"markdown","content":"# Stage 1 — Prepare the release PR\n\nAll preparation lands as a normal PR against the branch being released (usually the repo's default branch, `master` in MUI repos; prereleases or older majors may release from a version branch — the README says which). Some repos require specific git remotes (an `upstream` pointing at the MUI repo, sometimes a dedicated docs remote) — check the README's prerequisites first.\n\n1. Create a branch off the up-to-date upstream release branch (`git fetch upstream --tags` first — the changelog script compares against the last tag).\n2. Ask the user for the target release version, showing them the current version (the root `package.json` version and the latest release tag) alongside the question so they can make an informed choice. If they passed a version when invoking the skill, use that instead of asking. Never pick the target version yourself.\n3. Bump the root `package.json` version to the target release version.\n4. Generate the changelog with `pnpm release:changelog` and **prepend** the output to the top-level `CHANGELOG.md`. Run with `--help` for options (comparison range, target branch, token flags).\n5. Clean the generated changelog: match the format of the repo's existing GitHub releases, describe breaking changes explicitly, fix package-name casing. Preserve any marker comments the script inserts — downstream automation may depend on them.\n6. Version the packages with `pnpm release:version` — an **interactive** (PTY) script that confirms the new version of each workspace package before bumping it (along with inter-package dependency ranges). Ask the user to run it in their own terminal and end the turn there. On the next turn, verify the outcome from `git diff` (which packages were bumped and to what) instead of the command's output, against these rules:\n   - Only bump packages that have changes since the last release — but if the tooling detects **any** change, do not skip the bump.\n   - Packages that track the root version — the repo's **main package** above all — must end up at exactly the root `package.json` version, even if that skips version numbers or the package had no changes of its own. The script skips unchanged packages, so the main package may need a manual bump after the run.\n7. Open the PR titled `[release] <target-version>` (e.g. `[release] v1.2.0`) with the `release` label — stage 2 finds the release PR by this label. Keep the PR description minimal: none at all, or a single line when something genuinely needs calling out (the changelog in the diff is the description).\n\nSome repos ship an interactive script (e.g. `pnpm release:prepare`) that automates this stage end to end — prefer it when the README offers one.\n\n**Stage complete when:** the PR is approved and CI is green.\n\n## Troubleshooting\n\n- **Changelog script fails:** build the changelog manually from the GitHub compare view between the last tag and the release branch (`github.com/mui/<repo>/compare/<lastTag>...<branch>`).\n","isInternal":false,"tokens":655,"sizeBytes":3004},{"name":"stage-2-publish-packages.md","path":".agents/skills/mui-release/stage-2-publish-packages.md","rawUrl":"https://raw.githubusercontent.com/mui/base-ui/HEAD/.agents/skills/mui-release/stage-2-publish-packages.md","title":"Mui-release Skill","category":"anthropic-skill","format":"markdown","content":"# Stage 2 — Merge the PR, then publish the packages\n\nRequires stage 1 complete. Before merging, verify the PR still has the `release` label — the publish tooling finds the release PR by it.\n\n1. Just before merging, the user announces a **merge freeze** on the team's Slack channel so nothing else lands until the release and docs deploy are done — as an agent, remind them of this step.\n2. Merge the release PR.\n3. Trigger the publish. It always runs through the repo's `publish.yml` GitHub Actions workflow, never from a local machine:\n   - **CLI:** `pnpm release:publish` (maps to `code-infra publish`) finds the latest merged release PR, asks for confirmation, and dispatches the workflow. To publish from the exact release commit, pass the release PR's merge commit SHA on the default branch: `pnpm release:publish --sha <merge-commit-sha>` (get it with `gh pr view <number> --json mergeCommit`). The interactive picker may pre-select an unrelated commit — never accept the default without checking it's the `[release] vX.Y.Z` merge commit.\n   - **GitHub UI:** open the publish workflow → \"Run workflow\", supplying the release commit SHA and options.\n\n   Common options either way: a dry-run mode for debugging (also as `pnpm release:publish:dry-run` — still a real workflow run needing environment approval), an npm dist-tag for legacy/canary versions, and whether to auto-create the GitHub release. Legacy releases must pass `--sha` explicitly — the picker only sees the latest release PR.\n\n4. The run pauses on the `npm-publish` environment: click \"Review deployments\" and approve it. **Never approve workflow runs you didn't initiate.**\n\n**Stage complete when:** the workflow has published the packages to npm and created a **draft** GitHub release from the changelog.\n\n## Troubleshooting\n\n- **Publish reports \"no new packages to publish\":** the workflow ran against a commit whose package versions are already on npm — usually a wrong SHA (e.g. the picker's pre-selected default). Re-dispatch with `--sha <merge-commit-sha>` of the release PR.\n","isInternal":false,"tokens":460,"sizeBytes":2069},{"name":"stage-3-publish-docs.md","path":".agents/skills/mui-release/stage-3-publish-docs.md","rawUrl":"https://raw.githubusercontent.com/mui/base-ui/HEAD/.agents/skills/mui-release/stage-3-publish-docs.md","title":"Mui-release Skill","category":"anthropic-skill","format":"markdown","content":"# Stage 3 — Publish the docs\n\nRequires stage 2 complete (packages published — docs must reference versions that exist on npm).\n\n`pnpm docs:deploy` pushes the release commit to the repo's docs deployment target — a versioned `docs-vX` branch or a dedicated docs repo/branch, mapped to the live docs domain. Force-pushing is expected. Deploys run on Netlify; follow progress on the site's Netlify dashboard. The README documents the branch scheme and URLs.\n\n**Stage complete when:** the Netlify deploy has finished and the docs are live.\n","isInternal":false,"tokens":119,"sizeBytes":542},{"name":"stage-4-github-release.md","path":".agents/skills/mui-release/stage-4-github-release.md","rawUrl":"https://raw.githubusercontent.com/mui/base-ui/HEAD/.agents/skills/mui-release/stage-4-github-release.md","title":"Mui-release Skill","category":"anthropic-skill","format":"markdown","content":"# Stage 4 — Publish the GitHub release, then announce\n\nRequires stage 3 complete (docs live).\n\n1. Review the draft release on the repo's GitHub releases page and publish it. Mark it correctly for what's being released:\n   - Stable release on the current major → **Set as the latest release**.\n   - Release for an older major → do **not** set as latest — the current major's release must keep the \"Latest\" badge.\n   - Unstable version (alpha/beta/RC) → check **Set as a pre-release** instead.\n2. The user lifts the merge freeze on Slack and follows the team's internal announcement instructions — as an agent, remind them of both.\n\n**Stage complete when:** the GitHub release is public (non-draft) — the release is done. The freeze lift and announcement are on the user's side; remind them.\n","isInternal":false,"tokens":181,"sizeBytes":804},{"name":"SKILL.md","path":".claude/skills/base-ui-review/SKILL.md","rawUrl":"https://raw.githubusercontent.com/mui/base-ui/HEAD/.claude/skills/base-ui-review/SKILL.md","title":"base-ui-review","category":"anthropic-skill","format":"markdown","content":"---\nname: base-ui-review\ndescription: 'Review the current diff for regressions, correctness bugs, tests, simplifications, and docs issues, scaling depth to a low/medium/high/xhigh/max effort level. Use ONLY when explicitly requested by name: the user runs /base-ui-review, writes $base-ui-review, or asks for \"the Base UI review skill\". Do NOT use for general review requests such as \"review my changes\", \"review this diff/branch/PR\", or after finishing an implementation — handle those without this skill unless the user names it. Pass --comment to post a top-level PR comment, --comment inline for inline PR comments, or --fix to apply findings.'\n---\n\n# Base UI Review\n\nThis is the Claude Code entrypoint for the shared repo skill.\n\nOnly run when the user explicitly asks for this skill by name\n(`/base-ui-review`, `$base-ui-review`, \"the Base UI review skill\", or a CI job\nconfigured to use it). Do not trigger on a generic \"review my changes\" request\nor after finishing an implementation.\n\nBefore reviewing, read `.agents/skills/base-ui-review/SKILL.md` completely and\nfollow that canonical workflow. Pass through any user arguments such as `low`,\n`medium`, `high`, `xhigh`, `max`, `--comment`, `--comment inline`, `--fix`, or a\nreview target.\n","frontmatter":{"name":"base-ui-review","description":"Review the current diff for regressions, correctness bugs, tests, simplifications, and docs issues, scaling depth to a low/medium/high/xhigh/max effort level. Use ONLY when explicitly requested by name: the user runs /base-ui-review, writes $base-ui-review, or asks for \"the Base UI review skill\". Do NOT use for general review requests such as \"review my changes\", \"review this diff/branch/PR\", or after finishing an implementation — handle those without this skill unless the user names it. Pass --comment to post a top-level PR comment, --comment inline for inline PR comments, or --fix to apply findings."},"isInternal":false,"tokens":289,"sizeBytes":1253},{"name":"README.md","path":"packages/react/README.md","rawUrl":"https://raw.githubusercontent.com/mui/base-ui/HEAD/packages/react/README.md","title":"react Documentation","category":"plugin-manifest","format":"markdown","content":"<!-- lint disable mui-first-block-heading -->\n\n<a href=\"https://base-ui.com\" target=\"_blank\"><img width=\"150\" height=\"133\" src=\"https://base-ui.com/static/logo.svg\" alt=\"Base UI logo\"></a>\n\nBase UI is a library of unstyled React components. You gain complete control over your app's CSS and accessibility features.\n\n## Installation\n\nInstall the package in your project directory with:\n\n```bash\nnpm install @base-ui/react\n```\n\n## Documentation\n\n<!-- #default-branch-switch -->\n\nVisit [base-ui.com](https://base-ui.com) to view the full documentation.\n\n## Questions\n\nFor how-to questions that don't involve making changes to the code base, please use [Stack Overflow](https://stackoverflow.com/questions/tagged/base-ui) instead of GitHub issues.\nUse the \"base-ui\" tag on Stack Overflow to make it easier for the community to find your question.\n\n## Contributing\n\nRead the [contributing guide](../../CONTRIBUTING.md) to learn about our development process, how to propose bug fixes and improvements, and how to build and test your changes.\n\nContributing to Base UI is about more than just issues and pull requests!\nThere are many other ways to [support Base UI](https://mui.com/material-ui/getting-started/faq/#mui-is-awesome-how-can-i-support-the-project) beyond contributing to the code base.\n\n## Changelog\n\nThe [changelog](https://github.com/mui/base-ui/releases) is regularly updated to reflect what's changed in each new release.\n\n## Roadmap\n\nFuture plans and high-priority features and enhancements can be found in the [roadmap](https://github.com/orgs/mui/projects/1).\n\n## License\n\nThis project is licensed under the terms of the [MIT license](../../LICENSE).\n\n## Security\n\nFor details of supported versions and contact details for reporting security issues, please refer to the [security policy](https://github.com/mui/base-ui/security/policy).\n","isInternal":false,"tokens":412,"sizeBytes":1856},{"name":"README.md","path":"packages/utils/README.md","rawUrl":"https://raw.githubusercontent.com/mui/base-ui/HEAD/packages/utils/README.md","title":"utils Documentation","category":"plugin-manifest","format":"markdown","content":"# @base-ui/utils\n\nA collection of React utility functions for Base UI.\n","isInternal":false,"tokens":17,"sizeBytes":72}],"systemPromptSnippet":"<yakaai_skills repo=\"mui/base-ui\">\n<!-- File: AGENTS.md (Tokens: ~2287 | Category: root-instruction) -->\n# Repository Guidelines\n\nThis repository contains the source code and documentation for Base UI: a headless, unstyled React component library.\n\n## Project structure\n\n- Source code for components and private utils is in `packages/react/`.\n- Source code for public shared utils is in `packages/utils/`.\n- Experiments are located at `docs/src/app/(private)/experiments/`. Use for creating demos that require manual testing in the browser.\n- Public documentation is located at `docs/src/app/(docs)/react/`. Alter the docs where necessary when changes must be visible to library users.\n- When creating public demos on the docs, refer to the `hero` demo for the given component and largely follow its styles (both CSS Modules and Tailwind CSS versions). Other demos may also contain relevant styling. Do not add custom styling beyond the critical layout styles necessary for new demos.\n\n## Agent skills\n\n- The shared `/base-ui-review` skill lives in `.agents/skills/base-ui-review/SKILL.md`. Update that file when the Base UI review workflow changes.\n- Claude Code discovers the same shared skill through `.claude/skills/base-ui-review/SKILL.md`, which delegates to the `.agents` copy.\n- The review skill is opt-in: only run it when the user explicitly asks for it by name (`/base-ui-review`). Do not trigger it from a generic review request or after finishing a change.\n\n## Code guidelines\n\n- Always use the `useTimeout` utility from `@base-ui/utils/useTimeout` instead of `window.setTimeout`, and `useAnimationFrame` from `@base-ui/utils/useAnimationFrame` instead of `requestAnimationFrame`. Search for other example usage in the codebase if unsure how to use them.\n- Use the `useStableCallback` utility from `@base-ui/utils/useStableCallback` instead of `React.useCallback` if the function is called within an effect or event handler. The utility cannot be used to memoize functions that are called directly in the body of a component (during render), so continue with `React.useCallback` in those scenarios.\n- Always use the `useIsoLayoutEffect` utility from `@base-ui/utils/useIsoLayoutEffect` instead of `React.useLayoutEffect`.\n- Always use the shadow DOM-safe utilities for DOM traversal and event targeting: `closest`, `contains`, `getTarget`, and `activeElement`. Always use the owner utilities `ownerDocument` and `ownerWindow` instead of global `document`/`window` lookups when the code is tied to a DOM node, including realm-sensitive checks such as `instanceof`.\n- Avoid duplicating logic where necessary. If two components can share logic (such as event handlers), define the logic/handlers in the parent and share it through a context to the child; use the existing context if it exists.\n\n## Styling\n\n- In CSS Modules demos (`docs/src/app/(docs)/**/demos/**/*.module.css`), use raw color values from the Tailwind `@theme` block in `docs/src/css/index.css`. For example, use `oklch(14.5% 0 0deg)` instead of `var(--color-neutral-950)`.\n- When using `user-select: none;` in CSS, also add `-webkit-user-select: none;` to support Safari. Tailwind's `select-none` class already includes this.\n\n## Linting, typechecking, and formatting\n\n- Do not randomly cast (for example `as any`) if there are no type errors without doing so. Run `pnpm typescript` to verify types.\n- Ensure your changes pass linting - run `pnpm eslint`.\n- Ensure your styles pass stylelint - run `pnpm stylelint`.\n- Ensure your changes are formatted correctly - run `pnpm prettier`.\n- When you change a public component API (props or JSDoc), run `pnpm docs:api`.\n\n## Testing\n\n- If a repository command fails because dependencies are unavailable, run `pnpm i` first and then retry the command.\n- Run tests in jsdom env with `pnpm test:jsdom {name} --no-watch` such as `pnpm test:jsdom NumberField --no-watch` or `pnpm test:jsdom parse --no-watch`.\n- Run tests in Chromium env with `pnpm test:chromium {name} --no-watch` such as `pnpm test:chromium NumberField --no-watch` or `pnpm test:chromium parse --no-watch`.\n- In `@base-ui/react` tests, do not call `await flushMicrotasks()` directly after `await render(...)` when there are no interactions or state changes between them; the `#test-utils` `render` is async and already awaited, so that immediate flush is unnecessary.\n- Do not group multiple `expect()` assertions in a single `waitFor()` callback. Use one assertion per `waitFor()` so retries are scoped to the specific condition that may change asynchronously.\n- For locale-formatted text, use `expect(element.textContent).toBe(expected)` with the expected value formatted using the same locale and options as the component. When the component uses the runtime default locale, derive expectations using that default too (for example, `new Intl.NumberFormat(undefined, options)`); do not hardcode `en-US` or US-formatted strings in expected values. Pin a locale only when testing locale-specific behavior, and use it consistently for both the component and expectations. `toHaveTextContent` normalizes nonbreaking spaces in the rendered text but not in the expected string, causing failures in locales such as `pt-BR`.\n- Use `firePointer` from `#test-utils` instead of `fireEvent.pointer*` whenever a test depends on event timing. `fireEvent` silently drops `timeStamp`, so the event inherits the environment's clock — the real one in a browser — and gesture velocity then depends on how long the runner took between calls. A lint rule enforces this.\n- If you made changes to the source code, ensure you verify your changes by running tests (see above), and writing new tests where applicable. If tests require the browser because, for example, they require layout measurements, restrict it to the Chromium env by using `it.skipIf(isJSDOM)` or `describe.skipIf(isJSDOM)` (search other tests for example usage if unsure).\n- Follow the established conventions in existing tests. Each file/component is tested with the filename `name.test.tsx`. For example, `PopoverRoot.test.tsx` is next to its source file `PopoverRoot.tsx`.\n- Tests use Vitest APIs only: `expect()`, `vi.fn()`, and `@testing-library/jest-dom` DOM matchers. Do not use Chai- or Sinon-style matcher chains or spies.\n- Import `createRenderer`, `describeConformance` and other helpers from `#test-utils`, and use the `user` returned by `await render(...)` instead of creating a Testing Library user-event instance with `userEvent.setup()`.\n- A test must be able to fail when the behavior in its title breaks. Before you finish a test, break that behavior in the source and check that the test fails, then revert. In particular:\n  - Assert the starting state before the action when the end state could already hold (for example, move focus away before testing that it returns).\n  - For \"does not X when <guard>\" tests, use an interaction that would do X without the guard, ideally with a sibling case that flips only the guard and shows X happening.\n  - When the title names an intermediate state (\"while open\", \"after hover\", \"during swipe\"), assert that state right before the action under test.\n  - Fire events the way the component expects them. `fireEvent.click` on a list item is a virtual click that items may ignore; prefer `user.click`. A `preventDefault` spy in a `fireEvent` init object is never called; assert on the boolean `fireEvent` returns instead.\n  - Never put negative assertions inside `waitFor` (they pass on the first poll); flush or advance timers first, then assert synchronously.\n  - Keep assertions in the test body: an `expect` inside a callback that may not run, a conditional, or `Promise.allSettled` can silently pass.\n- Use `it.each` (object rows with `$name` titles) or `describe.each` for tests that differ only in data; don't register tests or suites inside `forEach` or `map`. Every test inside a parametrized block must use the parameter.\n- A test belongs in the file of the part whose prop or behavior it asserts, and under `describe('prop: X')` only if it sets `X`. Titles must describe what the body asserts.\n- Shared behavior across components belongs in a shared suite in `packages/react/test`, exported from `#test-utils`, rather than copied into each component's tests. Existing suites: `describeConformance` (every part), `popupConformanceTests` (popup roots), `popupListConformanceTests` (list interactions in Select, Menu and Combobox popups), `popupFocusPropsTests` (`initialFocus`/`finalFocus`), `dialogRootSharedTests` (Dialog and AlertDialog), `detachedTriggersConformanceTests`, `positionerConformanceTests` and `viewportConformanceTests`. Don't re-test what a suite already covers for the same part; extend the suite instead.\n- After every test, `test/setupVitest.ts` resets `BASE_UI_ANIMATIONS_DISABLED`, mocks, deduplicated errors and warnings, and the animation frame scheduler, and `createRenderer` unmounts what it rendered; don't repeat that per file.\n\n## Commit guidelines\n\n- Commit messages follow the format `[scope] Imperative summary` (for example `[popover] Fix focus trap`). Choose scopes that mirror package or component names that were changed.\n- Use `[all components]` scope for changes that broadly affect most components.\n\n## Errors\n\nThese guidelines apply only to errors thrown by public packages.\n\nEvery error message must:\n\n1. **Say what happened** - Describe the problem clearly\n2. **Say why it's a problem** - Explain the consequence\n3. **Point toward how to solve it** - Give actionable guidance\n\nFormat:\n\n- Prefix with `Base UI:`\n- Use string concatenation for readability\n- Include a documentation link when applicable (`https://base-ui.com/...`)\n\n### Error Minifier\n\nYou MUST run `pnpm extract-error-codes` to update `docs/src/error-codes.json` every time you add or update an error message in an `Error` constructor.\n\n**Important:** If the update created a new error code, but the new and original message have the same number of arguments and semantics haven't changed, update the original error in `error-codes.json` instead of creating a new code.\n\nBefore any changes, review [CONTRIBUTING.md](./CONTRIBUTING.md) for more detailed guidelines on contributing to this repository.\n\n<!-- File: CLAUDE.md (Tokens: ~5 | Category: claude-rule) -->\n@AGENTS.md\n\n<!-- File: .agents/skills/base-ui-review/agents/openai.yaml (Tokens: ~45 | Category: anthropic-skill) -->\ninterface:\n  display_name: 'Base UI Review'\n  short_description: 'Review Base UI diffs for bugs, tests, cleanup, docs'\n  default_prompt: 'Use $base-ui-review to review my current diff.'\n\n<!-- File: .agents/skills/base-ui-review/SKILL.md (Tokens: ~4844 | Category: anthropic-skill) -->\n---\nname: base-ui-review\ndescription: 'Review the current diff for regressions, correctness bugs, tests, simplifications, and docs issues, scaling depth to a low/medium/high/xhigh/max effort level. Use ONLY when explicitly requested by name: the user runs /base-ui-review, writes $base-ui-review, or asks for \"the Base UI review skill\". Do NOT use for general review requests such as \"review my changes\", \"review this diff/branch/PR\", or after finishing an implementation — handle those without this skill unless the user names it. Pass --comment to post a top-level PR comment, --comment inline for inline PR comments, or --fix to apply findings.'\n---\n\n# Base UI Review\n\nReview current diff. Find **regressions and correctness bugs** first. Also find\n**cleanup** (reuse / simplification / efficiency). Default effort: `medium`. See\n[Effort levels](#effort-levels) for depth and subagent fan-out.\n\nArgument hint: `[low|medium|high|xhigh|max] [--fix] [--comment [inline]] [<target>]`\n\nThis skill is **opt-in only**: run it when the user explicitly asks for it by\nname (`/base-ui-review`, `$base-ui-review`, \"the Base UI review skill\", or a CI\njob configured to use it). A plain \"review my changes\" or \"review this PR\", or\nwrapping up an implementation, is not an invocation — review without this\nworkflow unless the user names it.\n\n`medium` = **precision**. Every finding actionable. `high`, `xhigh`, `max` =\n**recall**. Missed bug ships. Keep uncertain findings when mechanism is real;\nlabel them clearly.\n\n## Scope\n\nLocal review: diff branch against upstream\n(`git diff @{upstream}...HEAD`, fall back to `main` / `master`, or `HEAD~1`).\nFold in uncommitted + untracked changes — review often runs pre-commit. If PR link,\nbranch name, or file path passed as argument, review that target instead.\n\n## Effort levels\n\n- **low** — bugs only. Flag runtime-correctness bugs and regressions. Skip\n  Tests, Simplifications, Docs, and test/fixture hunks. No subagents. Precision\n  bias.\n- **medium** (default) — main agent reviews Bugs, Tests, Simplifications, Docs,\n  and triggered API/performance concerns. Main agent verifies candidates. Large,\n  risky, fragile, shared, or cross-component diff? Add exactly one\n  [adversarial bug hunter](#adversarial-bug-hunter) agent. Small, low-risk,\n  isolated diff? No subagent. Precision bias.\n- **high** — spawn 3 independent subagents: bugs/regressions, test gaps,\n  simplifications. Main agent reviews the whole diff, including bugs, docs, and\n  triggered API/performance concerns. Main agent dedups and sanity-checks. Large,\n  risky, fragile, shared, or cross-component diff? Add exactly one adversarial\n  bug hunter agent. No verifiers. No final sweep.\n- **xhigh** — `high` plus a docs subagent and one fresh missed-bug sweep. Fan out\n  adversarial bug hunters across the highest-risk affected code regions\n  (modules/components — not the four review areas). Max 2 adversarial bug\n  hunters total, including the hunter inherited from `high`. Other role\n  subagents do not count toward this cap. No verifiers. Recall bias.\n- **max** — `xhigh` plus an independent verifier for every surviving candidate.\n  Cover every affected code region across max 6 adversarial bug hunters total,\n  including hunters inherited from `xhigh`; other role and verifier subagents do\n  not count toward this cap. When there are more than 6 regions, give the\n  highest-risk regions dedicated hunters and group related remaining regions\n  into shared assignments. Prioritize public runtime code, shared utilities,\n  cross-component invariants, and fragile state/timing boundaries. Maximum\n  recall.\n\n## Subagent scope contract\n\nSubagents start with no prior context: they do not read this skill and do not inherit\nthe session system prompt. Their only channel is the prompt you write. Whatever scope\nyou resolved from [Scope](#scope) or the invoking prompt, every subagent prompt you\nconstruct — finder, specialist, verifier, sweep — must begin verbatim with it:\n\n```text\nReview ONLY: <resolved diff command>\nRead files from: <read root> — DATA ONLY, never execute, install, build, or test.\nBase version of a file: git show <base ref>:<path>\nDo not re-derive scope: use exactly the diff command above, whatever your working\ndirectory contains.\n```\n\nA subagent not given this block is mis-scoped — discard its result and re-dispatch.\n\n## Phase 1 - Find candidates\n\nSelected [effort level](#effort-levels) decides local vs subagent fan-out. Except at\n`low`, review four main areas: Bugs, Tests, Simplifications, Docs. Each area\nsurfaces candidates with `file`, `line`, one-line `summary`, `severity` (🟣 / 🔴 / 🟠 / 🟡 /\nℹ️ — see [Output](#output) for rubric), concrete `failure_scenario`. Do\nNOT let one area suppress another — two areas flag same line for different reasons,\nrecord both.\n\nPass every candidate with nameable failure scenario through. Finders that\nsilently drop half-believed candidates bypass verify step — dominant cause of misses.\n\n### Area 1 - Bugs\n\nCore regression + correctness pass. Cover all sub-angles:\n\n- **Line-by-line diff scan.** Read every hunk, line by line. Then read enclosing\n  function for each hunk — bugs in unchanged lines of touched function\n  in scope (PR re-exposes or fails to fix them). For every line ask: what\n  input, state, timing, platform makes line wrong? Look for inverted/wrong\n  conditions, off-by-one, null/undefined deref, missing `await`, falsy-zero checks,\n  wrong-variable copy-paste, error swallowed in catch, unescaped regex metachars.\n- **Regression hunting.** For each changed guard, branch, state transition, public\n  contract, test expectation, documented example, ask what behavior previously\n  worked and could break. Bias toward regressions in edge paths, accessibility\n  interactions, keyboard/focus flows, controlled/uncontrolled contracts, SSR,\n  integrations between components, public API examples.\n- **Repository/framework correctness lens.** Apply invariants of codebase\n  under review, not just generic language bugs. For Base UI / React component\n  changes: controlled vs uncontrolled behavior, event ordering, ref\n  forwarding/merging, context registration cleanup, nested component coordination,\n  portals, focus management, keyboard navigation, ARIA attributes, disabled/read-only\n  states, form integration, SSR/hydration safety, Strict Mode behavior, shadow\n  DOM-safe DOM access (`closest`, `contains`, `getTarget`, `activeElement`, `ownerDocument`,\n  `ownerWindow`).\n- **Removed-behavior auditor.** For every line diff DELETES or replaces, name\n  invariant/behavior it enforced, then search new code for where invariant\n  re-established. Can't find it? Candidate: removed\n  guard, dropped error path, narrowed validation, deleted test covering real case.\n- **Cross-file tracer.** For each function diff changes, find callers (Grep\n  symbol) and check if change breaks any call site: new\n  precondition, changed return shape, new exception, timing/ordering\n  dependency. Also check callees: parallel change in same PR make call\n  unsafe?\n\n### Area 2 - Tests\n\nReview test changes and tests that _should_ have changed. Flag:\n\n- New/changed behavior with no test exercising it\n- Assertions not actually pinning behavior (asserting mock called instead of\n  result, snapshot-only coverage, asserting on value test itself computed)\n- Missing edge/error-path cases diff introduces (null, empty, boundary, failure,\n  concurrency)\n- Setup/teardown asymmetry (state leaked between tests, fixtures not reset)\n- Over-mocking hiding real contract\n- Tests deleted or weakened without justification\n- Tests whose names do not match what they assert, or whose names are misleading\n\nName specific case untested or under-asserted.\n\n### Area 3 - Simplifications\n\nBundle size is a top constraint. Smallest correct implementation wins. Preserve\npublic behavior, runtime performance, and maintainability. Treat every bundle\nsize increase as suspect — new bytes must earn their place; flag increases the\ndiff doesn't justify.\n\nAlways ask: \"Can this ship with less code, state, branching, or abstraction?\"\nLook for:\n\n- Heavy dependency or new abstraction where a few lines or existing util does\n  the job\n- Code doing too much for an edge case almost no one hits — guards, branches,\n  state, or config for scenarios not realistically reachable in consumer usage;\n  weigh handling cost against edge-case likelihood and propose dropping or\n  cheapening it\n- Duplicated logic re-implementing what codebase already has — Grep\n  shared/utility modules and files adjacent to change; name existing helper to\n  call instead\n- Non-tree-shakeable or whole-package imports; namespace imports of\n  side-effectful modules\n- Dead code left behind; redundant or derivable state\n- Special cases layered on shared infrastructure when mechanism should\n  generalize\n\nName smaller or better-shaped form doing same job. Measure real bundle effect\nwhen material. Source-line count proves nothing.\n\n### Area 4 - Docs\n\nFlag documentation and comments diff makes wrong or leaves stale:\n\n- Comments describing old behavior after code changed\n- JSDoc/docstrings whose params, return type, thrown errors no longer match\n  signature\n- README / API docs / changelog entries contradicting change; examples no longer\n  compile or run\n- TODO/FIXME change resolved but didn't remove; new non-obvious code with no\n  explanation where warranted\n\nQuote stale line and state what it should say.\n\n### Conditional specialist - API design\n\nNot part of default four-area fan-out. Skip entirely at\n`low`. At `medium`, include in main-agent pass when diff adds/changes\npublic API surface: component, prop, event, hook, provider, imperative method,\nexported type, value shape, behavior contract, docs example teaching API.\nAt `high`, `xhigh`, `max`, run as independent API design subagent when\ntriggered.\n\nHeavily critique API taste: naming, mental model, consistency with\nnearby APIs in same codebase, controlled/uncontrolled ergonomics, composition,\nescape hatches, type shape, default behavior, future extensibility, migration risk,\nlikely user footguns. Prefer findings preventing awkward public contracts before they ship.\nReport API design findings under Bugs when they create likely user-visible footguns\nor regressions, otherwise under Simplifications.\n\n### Conditional specialist - Runtime performance\n\nNot part of default four-area fan-out. Skip entirely at\n`low`. At `medium`, include in main-agent pass when diff likely affects\nruntime performance: render hot paths, large item collections, virtualization,\npositioning, layout measurement, scroll/resize/pointer/keyboard handlers,\nobservers, animations, repeated DOM reads/writes, state updates in loops,\ncomponent registration/lookup paths. At `high`, `xhigh`, `max`, run as\nindependent runtime performance subagent when triggered.\n\nPrefer concrete measurement when feasible: existing perf tests, targeted benchmark\nscripts, small reproducible measurement. If measuring not practical, state\nexpected complexity or browser work and what would confirm it. Report runtime\nperformance findings under Bugs when users can see lag, jank, hangs, excessive\nwork, otherwise under Simplifications.\n\n### Adversarial bug hunter\n\nSubagent role added per [Effort levels](#effort-levels). Assume there are bugs\nin the diff a consumer will hit. Do not trust PR description, comments, or test\nnames — verify against code. Attack changed invariants directly: construct\nconcrete input, state, timing, or platform that makes new code wrong. Report\nevery candidate with a nameable failure scenario; when none survive, report\nempty — never pad with weak findings to justify the hunt.\n\n---\n\nSimplification, test, docs candidates use same `file`/`line`/`summary`\nshape; in `failure_scenario`, state concrete cost (what duplicated, wasted,\nuntested, stale, harder to maintain) instead of crash. Regressions and\ncorrectness bugs always outrank simplification, test, docs findings when\nreview ordered.\n\n## Phase 2 - Verify candidates (local by default; max adds subagent votes)\n\nDedup candidates pointing at same line/mechanism, keep one with\nmost concrete failure scenario. Verify candidates locally in main agent by\ndefault.\n\nJudge every candidate by reachability and impact. Keep every valid bug. Demote\nto ℹ️ note when behavior not realistically reachable in real consumer usage,\nhas no meaningful user impact, or is optional improvement rather than\ncorrectness defect. Demotion is not refutation — demoted findings still print,\nat lower severity. At `max` effort, also run **one verifier** as subagent for each\nremaining candidate when subagents available and authorized: give it diff,\nrelevant file(s), candidate, have it return exactly one of:\n\n- **CONFIRMED** — can name inputs/state triggering it and wrong output or\n  crash. Quote line.\n- **PLAUSIBLE** — mechanism real, trigger uncertain (timing, env, config).\n  State what would confirm it.\n- **REFUTED** — factually wrong (code doesn't say that) or guarded elsewhere. Quote\n  line proving it.\n\nKeep candidates where vote CONFIRMED or PLAUSIBLE.\n\nAt **max**, verify recall-biased — **PLAUSIBLE by default**: do not\nrefute candidate for being \"speculative\" or \"depends on runtime state\" when\nstate realistic (concurrency races, nil/undefined on rare-but-reachable path,\nfalsy-zero treated as missing, off-by-one on boundary code doesn't exclude,\nretry storms / partial failures, regex/allowlist lost anchor). REFUTE only\nwhen constructible from code: factually wrong, provably impossible, already\nhandled in this diff, pure style with no observable effect.\n\n## Phase 3 - Sweep for gaps (xhigh / max effort)\n\nAt `xhigh` and `max`, run **one more finder** as fresh reviewer with\ncurrent finding list. Re-read diff and enclosing functions looking ONLY for\ndefects not already listed. Do not re-derive or re-confirm anything already there —\njob is gaps. Focus on what first pass misses: moved/extracted code\ndropping guard or anchor; second-tier footguns (dataclass default evaluated\nonce, `hash()` non-determinism, lock-scope shrink, predicate methods with side\neffects); setup/teardown asymmetry in tests; config defaults flipped. Surface\nadditional candidates naming defect not already on list. If nothing new,\nreturn empty sweep — do not pad.\n\n## Output\n\nReply in Markdown. Do not wrap main result in JSON or code fence. Use\nsentence case for `#` heading and all finding titles; no title case. Do\nnot open with generic target/base filler like \"Reviewed `owner/repo#123` against\n`branch`.\" Only mention target or base branch when explaining specific\nfinding or limitation.\n\nPrint only non-empty category sections, in this order: `Bugs`, `Tests`,\n`Simplifications`, `Docs`. A category with 0 findings gets nothing — no\nheading, no count, no `No findings.` placeholder. Always end with `Verdict`.\nBefore sending, verify every surviving finding prints exactly once and each\nprinted section count matches its numbered findings. When no findings exist\nanywhere, use the [No findings](#no-findings) format.\n\n### Severity rubric\n\nPrefix every finding title with one severity marker:\n\n- 🟣 **critical - blocking.** Correctness issue crashing common flows, losing\n  user data, creating security/privacy problem, making public component contract\n  unusable, or creating broad cross-component accessibility, focus, form, SSR\n  breakage. Must block merge.\n- 🔴 **high - blocking.** Realistic user-visible regression in normal component\n  usage, accessibility, keyboard/focus behavior, controlled/uncontrolled behavior,\n  form integration, SSR/hydration, public API behavior, or public docs example\n  no longer compiling or teaching broken API usage. Should block merge even\n  when affected path has workaround or not most common path.\n- 🟠 **medium - non-blocking.** Real issue worth fixing before merge when\n  practical but not normally blocking: narrow or uncommon bug, meaningful missing\n  test, stale public-doc prose not breaking copy-pasted code, cleanup\n  avoiding likely future mistakes. Use only when issue doesn't break public\n  contract and doesn't affect accessibility, focus, forms, SSR, or normal component\n  usage.\n- 🟡 **low - non-blocking.** Minor edge-case bug, small test/doc gap, modest\n  simplification useful but easy for maintainers to defer.\n- ℹ️ **note.** Informational — observation, heads-up, optional suggestion the\n  maintainer may reasonably decline.\n\nBase UI has stricter quality bar than most apps — small component-library\nregressions multiplied across many downstream products. When choosing between\nadjacent severities, choose higher severity if failure reaches realistic\nconsumer usage, accessibility behavior, form behavior, focus management, SSR,\npublic API contract or broken public docs example. Do not reserve 🔴 high only for\noutage-level failures.\n\nWithin each section, order findings 🟣 -> 🔴 -> 🟠 -> 🟡 -> ℹ️.\n\n### Verdict\n\nEnd review with `## Verdict` line derived from markers:\n\n- **Request changes** — at least one 🟣 or 🔴 finding.\n- **Approve after nits** — no 🟣 or 🔴, but one or more 🟠 or 🟡 findings worth\n  addressing.\n- **Approve** — no 🟣, 🔴, 🟠, 🟡 findings (only ℹ️ notes, or nothing).\n\nFollow verdict with one clause naming deciding factor.\n\n### Finding format\n\nUse this structure. Omit any category block whose count is zero:\n\n````md\n# PR review\n\nOne to three sentences summarizing the concrete risk, most important theme, and\nany meaningful verification limit. State up front whether anything is merge-blocking.\nIf there are no actionable findings, say that clearly.\n\n## Bugs ({count})\n\n### 1. {severity marker} {Sentence-case title}\n\n**Location:** `path/to/file.ext:123`\n\n```tsx\n// Small relevant code excerpt from the reviewed file.\n```\n\n{Description of what is wrong and why it matters.}\n\n**Failure scenario:** {Simple, obvious user-facing or example issue someone would\nsee.}\n\n**Fix:** {Specific recommended change.}\n\n## Tests ({count})\n\n## Simplifications ({count})\n\n## Docs ({count})\n\n## Verdict\n\n**{Request changes | Approve after nits | Approve}** - {one clause on the deciding factor}.\n\n---\n\n🤖 Review generated with {Claude Code | Codex}\n````\n\nSame per-finding shape for Tests, Simplifications, Docs. For Tests,\nmake failure scenario the missing case or weak assertion. For Simplifications,\nmake it concrete duplicated, heavier, or harder-to-maintain code path. For Docs,\nmake it stale or missing public/developer-facing information.\n\n### Finding quality\n\nDo not cap findings by count. Report every verified, actionable finding\nmaintainer would reasonably fix before merging. Do not pad review with weak,\nstylistic, speculative, low-importance notes. If many findings survive, group\nrelated issues under one finding when they share same root cause.\n\n### No findings\n\nIf nothing survives verification, omit all category headings and counts. Return\n`# PR review`, `No findings.`, a brief note of residual test gaps or risk,\n`## Verdict` with **Approve**, and the `🤖 Review generated with ...` footer.\n\n### Final output preflight\n\nTreat the output format as a hard contract. Before sending:\n\n- Use `# PR review`; start the summary with concrete risk, not target/base filler.\n- Use exact `## {Category} ({count})` headings for non-empty categories only.\n- Print each finding exactly once and verify every category count.\n- Use a separate `## Verdict` heading and the required closing footer.\n\nIf any check fails, rewrite the output before sending.\n\nAlways close review with `---` horizontal rule, blank line, then\n`🤖 Review generated with {Claude Code | Codex}`. Use **Claude Code** when this\nskill executed by Claude Code harness, **Codex** when executed by Codex harness.\n\n## Posting to GitHub (--comment)\n\nPost to GitHub only when target is GitHub PR and arguments include\ncomment mode:\n\n- No `--comment` — do not post to GitHub; if `--fix` also absent, stop at\n  Markdown review report.\n- `--comment` — post Markdown review as one top-level PR comment via\n  `gh pr comment`.\n- `--comment inline` — post inline comments for findings mapping to PR diff\n  lines, include all non-diff findings in top-level fallback comment.\n\nFor `--comment inline`, include same severity marker in each inline comment\nbody. Use latest PR head `commit_id`, `path`, `line`, `side`, post via\n`gh api` (`repos/{owner}/{repo}/pulls/{pr}/comments`), one call per finding. Include\nsuggestion block only when it fully fixes issue. (If GitHub inline-comment\nMCP tool available in session, use instead.)\n\nInline comments can only attach to lines present in PR diff. Put findings\noutside PR diff (unchanged lines in touched functions) in top-level\nfallback comment via `gh pr comment`; do not drop them or stop posting rest of\nreview because one inline comment not commentable. If target not\nPR, print findings to terminal and note `--comment` was ignored.\n\n## Applying fixes (--fix)\n\nIf `--fix` flag passed in arguments, after producing findings\nlist, apply findings to working tree instead of stopping at report: fix\neach one directly — correctness bugs and reuse/simplification/efficiency cleanups\nalike. Skip any finding whose fix would change intended behavior, require changes\nwell outside reviewed diff, or you judge false positive — note\nskip rather than arguing with it. Finish with brief summary of what fixed and\nwhat skipped.\n\nIf neither `--comment` nor `--fix` passed, stop at Markdown review report.\n\n<!-- File: .agents/skills/mui-release/SKILL.md (Tokens: ~714 | Category: anthropic-skill) -->\n---\nname: mui-release\ndescription: Run or assist a release in any MUI repo, at any stage - release PR, npm publish, docs deploy, GitHub release.\nargument-hint: '[target-version]'\n---\n\n# MUI Release\n\nEvery MUI repo releases through the same staged pipeline. Each stage depends on the previous one completing — never start a stage before its predecessor is done. This skill describes the shared skeleton; the details vary per repo.\n\n**Resumable:** the skill can be invoked at any stage — a release often spans multiple sessions (e.g. the PR was created and merged earlier, and the user now wants to trigger the npm publish). In the pipeline diagram below, each arrow out of a stage states the observable evidence that the stage is complete: resume at the first stage whose evidence is missing. Confirm the detected stage with the user before continuing; earlier stages' outputs are inputs, not work to redo.\n\n**Source of truth:** the target repo's `scripts/README.md` is the authoritative, evolving runbook. Always read it in the target checkout before releasing; use this skill to know what the stages mean and what to expect. Where the README contradicts this skill, the README wins. Repo-specific steps (docs release pages, hotfix flows, prerelease progressions, docs-only deploys, first-time package publishing) live only there. Repos without that runbook: read their release workflow directly.\n\n## The pipeline\n\nEach stage's instructions live in its own file — after detecting and confirming the current stage, read **that stage's file**:\n\n```mermaid\nflowchart TD\n    S1[\"Stage 1: Prepare the release PR\\n(stage-1-prepare-pr.md)\"]\n    S2[\"Stage 2: Merge the PR, then publish\\n(stage-2-publish-packages.md)\"]\n    S3[\"Stage 3: Publish the docs\\n(stage-3-publish-docs.md)\"]\n    S4[\"Stage 4: Publish the GitHub release, then announce\\n(stage-4-github-release.md)\"]\n\n    S1 -- \"open PR with the release label,\\napproved, CI green\" --> S2\n    S2 -- \"release PR merged, packages on npm at\\nthe new version, draft GitHub release created\" --> S3\n    S3 -- \"docs live for the new version\" --> S4\n    S4 -- \"published non-draft GitHub release for the\\ncurrent root package.json version\\n(release done, next one starts at Stage 1)\" --> S1\n```\n\nVerify each stage's evidence with read-only commands (run in the target checkout; `<version>` is the root `package.json` version):\n\n```bash\n# release PR: open (stage 1) or merged (stage 2 done merging)\ngh pr list --label release --state open --json number,title,reviewDecision\ngh pr list --label release --state merged --limit 1 --json number,title,mergedAt\ngh pr checks <number>                      # CI green?\n\n# packages on npm at the new version\nnpm view <main-package>@<version> version\n\n# GitHub release: exists? still a draft?\ngh release list --limit 5 --json tagName,isDraft,isLatest\ngh release view \"v<version>\" --json tagName,isDraft\n\n# docs live for the new version\ncurl -s <docs-url> | grep \"<version>\"      # or check the Netlify dashboard\n```\n\n<!-- File: .agents/skills/mui-release/stage-1-prepare-pr.md (Tokens: ~655 | Category: anthropic-skill) -->\n# Stage 1 — Prepare the release PR\n\nAll preparation lands as a normal PR against the branch being released (usually the repo's default branch, `master` in MUI repos; prereleases or older majors may release from a version branch — the README says which). Some repos require specific git remotes (an `upstream` pointing at the MUI repo, sometimes a dedicated docs remote) — check the README's prerequisites first.\n\n1. Create a branch off the up-to-date upstream release branch (`git fetch upstream --tags` first — the changelog script compares against the last tag).\n2. Ask the user for the target release version, showing them the current version (the root `package.json` version and the latest release tag) alongside the question so they can make an informed choice. If they passed a version when invoking the skill, use that instead of asking. Never pick the target version yourself.\n3. Bump the root `package.json` version to the target release version.\n4. Generate the changelog with `pnpm release:changelog` and **prepend** the output to the top-level `CHANGELOG.md`. Run with `--help` for options (comparison range, target branch, token flags).\n5. Clean the generated changelog: match the format of the repo's existing GitHub releases, describe breaking changes explicitly, fix package-name casing. Preserve any marker comments the script inserts — downstream automation may depend on them.\n6. Version the packages with `pnpm release:version` — an **interactive** (PTY) script that confirms the new version of each workspace package before bumping it (along with inter-package dependency ranges). Ask the user to run it in their own terminal and end the turn there. On the next turn, verify the outcome from `git diff` (which packages were bumped and to what) instead of the command's output, against these rules:\n   - Only bump packages that have changes since the last release — but if the tooling detects **any** change, do not skip the bump.\n   - Packages that track the root version — the repo's **main package** above all — must end up at exactly the root `package.json` version, even if that skips version numbers or the package had no changes of its own. The script skips unchanged packages, so the main package may need a manual bump after the run.\n7. Open the PR titled `[release] <target-version>` (e.g. `[release] v1.2.0`) with the `release` label — stage 2 finds the release PR by this label. Keep the PR description minimal: none at all, or a single line when something genuinely needs calling out (the changelog in the diff is the description).\n\nSome repos ship an interactive script (e.g. `pnpm release:prepare`) that automates this stage end to end — prefer it when the README offers one.\n\n**Stage complete when:** the PR is approved and CI is green.\n\n## Troubleshooting\n\n- **Changelog script fails:** build the changelog manually from the GitHub compare view between the last tag and the release branch (`github.com/mui/<repo>/compare/<lastTag>...<branch>`).\n\n<!-- File: .agents/skills/mui-release/stage-2-publish-packages.md (Tokens: ~460 | Category: anthropic-skill) -->\n# Stage 2 — Merge the PR, then publish the packages\n\nRequires stage 1 complete. Before merging, verify the PR still has the `release` label — the publish tooling finds the release PR by it.\n\n1. Just before merging, the user announces a **merge freeze** on the team's Slack channel so nothing else lands until the release and docs deploy are done — as an agent, remind them of this step.\n2. Merge the release PR.\n3. Trigger the publish. It always runs through the repo's `publish.yml` GitHub Actions workflow, never from a local machine:\n   - **CLI:** `pnpm release:publish` (maps to `code-infra publish`) finds the latest merged release PR, asks for confirmation, and dispatches the workflow. To publish from the exact release commit, pass the release PR's merge commit SHA on the default branch: `pnpm release:publish --sha <merge-commit-sha>` (get it with `gh pr view <number> --json mergeCommit`). The interactive picker may pre-select an unrelated commit — never accept the default without checking it's the `[release] vX.Y.Z` merge commit.\n   - **GitHub UI:** open the publish workflow → \"Run workflow\", supplying the release commit SHA and options.\n\n   Common options either way: a dry-run mode for debugging (also as `pnpm release:publish:dry-run` — still a real workflow run needing environment approval), an npm dist-tag for legacy/canary versions, and whether to auto-create the GitHub release. Legacy releases must pass `--sha` explicitly — the picker only sees the latest release PR.\n\n4. The run pauses on the `npm-publish` environment: click \"Review deployments\" and approve it. **Never approve workflow runs you didn't initiate.**\n\n**Stage complete when:** the workflow has published the packages to npm and created a **draft** GitHub release from the changelog.\n\n## Troubleshooting\n\n- **Publish reports \"no new packages to publish\":** the workflow ran against a commit whose package versions are already on npm — usually a wrong SHA (e.g. the picker's pre-selected default). Re-dispatch with `--sha <merge-commit-sha>` of the release PR.\n\n<!-- File: .agents/skills/mui-release/stage-3-publish-docs.md (Tokens: ~119 | Category: anthropic-skill) -->\n# Stage 3 — Publish the docs\n\nRequires stage 2 complete (packages published — docs must reference versions that exist on npm).\n\n`pnpm docs:deploy` pushes the release commit to the repo's docs deployment target — a versioned `docs-vX` branch or a dedicated docs repo/branch, mapped to the live docs domain. Force-pushing is expected. Deploys run on Netlify; follow progress on the site's Netlify dashboard. The README documents the branch scheme and URLs.\n\n**Stage complete when:** the Netlify deploy has finished and the docs are live.\n\n<!-- File: .agents/skills/mui-release/stage-4-github-release.md (Tokens: ~181 | Category: anthropic-skill) -->\n# Stage 4 — Publish the GitHub release, then announce\n\nRequires stage 3 complete (docs live).\n\n1. Review the draft release on the repo's GitHub releases page and publish it. Mark it correctly for what's being released:\n   - Stable release on the current major → **Set as the latest release**.\n   - Release for an older major → do **not** set as latest — the current major's release must keep the \"Latest\" badge.\n   - Unstable version (alpha/beta/RC) → check **Set as a pre-release** instead.\n2. The user lifts the merge freeze on Slack and follows the team's internal announcement instructions — as an agent, remind them of both.\n\n**Stage complete when:** the GitHub release is public (non-draft) — the release is done. The freeze lift and announcement are on the user's side; remind them.\n\n<!-- File: .claude/skills/base-ui-review/SKILL.md (Tokens: ~289 | Category: anthropic-skill) -->\n---\nname: base-ui-review\ndescription: 'Review the current diff for regressions, correctness bugs, tests, simplifications, and docs issues, scaling depth to a low/medium/high/xhigh/max effort level. Use ONLY when explicitly requested by name: the user runs /base-ui-review, writes $base-ui-review, or asks for \"the Base UI review skill\". Do NOT use for general review requests such as \"review my changes\", \"review this diff/branch/PR\", or after finishing an implementation — handle those without this skill unless the user names it. Pass --comment to post a top-level PR comment, --comment inline for inline PR comments, or --fix to apply findings.'\n---\n\n# Base UI Review\n\nThis is the Claude Code entrypoint for the shared repo skill.\n\nOnly run when the user explicitly asks for this skill by name\n(`/base-ui-review`, `$base-ui-review`, \"the Base UI review skill\", or a CI job\nconfigured to use it). Do not trigger on a generic \"review my changes\" request\nor after finishing an implementation.\n\nBefore reviewing, read `.agents/skills/base-ui-review/SKILL.md` completely and\nfollow that canonical workflow. Pass through any user arguments such as `low`,\n`medium`, `high`, `xhigh`, `max`, `--comment`, `--comment inline`, `--fix`, or a\nreview target.\n\n<!-- File: packages/react/README.md (Tokens: ~412 | Category: plugin-manifest) -->\n<!-- lint disable mui-first-block-heading -->\n\n<a href=\"https://base-ui.com\" target=\"_blank\"><img width=\"150\" height=\"133\" src=\"https://base-ui.com/static/logo.svg\" alt=\"Base UI logo\"></a>\n\nBase UI is a library of unstyled React components. You gain complete control over your app's CSS and accessibility features.\n\n## Installation\n\nInstall the package in your project directory with:\n\n```bash\nnpm install @base-ui/react\n```\n\n## Documentation\n\n<!-- #default-branch-switch -->\n\nVisit [base-ui.com](https://base-ui.com) to view the full documentation.\n\n## Questions\n\nFor how-to questions that don't involve making changes to the code base, please use [Stack Overflow](https://stackoverflow.com/questions/tagged/base-ui) instead of GitHub issues.\nUse the \"base-ui\" tag on Stack Overflow to make it easier for the community to find your question.\n\n## Contributing\n\nRead the [contributing guide](../../CONTRIBUTING.md) to learn about our development process, how to propose bug fixes and improvements, and how to build and test your changes.\n\nContributing to Base UI is about more than just issues and pull requests!\nThere are many other ways to [support Base UI](https://mui.com/material-ui/getting-started/faq/#mui-is-awesome-how-can-i-support-the-project) beyond contributing to the code base.\n\n## Changelog\n\nThe [changelog](https://github.com/mui/base-ui/releases) is regularly updated to reflect what's changed in each new release.\n\n## Roadmap\n\nFuture plans and high-priority features and enhancements can be found in the [roadmap](https://github.com/orgs/mui/projects/1).\n\n## License\n\nThis project is licensed under the terms of the [MIT license](../../LICENSE).\n\n## Security\n\nFor details of supported versions and contact details for reporting security issues, please refer to the [security policy](https://github.com/mui/base-ui/security/policy).\n\n<!-- File: packages/utils/README.md (Tokens: ~17 | Category: plugin-manifest) -->\n# @base-ui/utils\n\nA collection of React utility functions for Base UI.\n</yakaai_skills>"}