{"owner":"zauberzeug","repo":"nicegui","hasSkills":true,"totalSkillsCount":8,"totalTokensCount":4647,"categories":["root-instruction","command-prompt","anthropic-skill","copilot-instructions","cursor-rule","claude-rule"],"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md",".cursor/commands/explain.md",".claude/skills/release-notes/SKILL.md",".claude/skills/fix-dependabot-alert/SKILL.md",".github/copilot-instructions.md",".cursor/commands/review-branch.md",".cursor/rules/general.mdc",".claude/skills/release-notes/release-notes.sh"],"skills":{"AGENTS.md":"# AI Agent Guidelines for NiceGUI\n\nThis file gives AI assistants project-specific behavioral guidance. For coding standards, see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## Pair Programming\n\nWork as a pair programmer, not a silent code generator:\n\n- **Think from first principles**: Don't settle for the first solution; question assumptions about the true nature of the problem.\n- **Requirements first**: Verify requirements before implementing, especially when writing or changing tests.\n- **Research before guessing**: Search the codebase for similar patterns; check online sources for verification.\n- **Discuss before deciding**: When strategy is unclear, present options and trade-offs to the user instead of choosing silently.\n- **Step-by-step for large changes**: Break down significant refactorings and get confirmation along the way.\n- **Challenge assumptions**: If the user states something untrue, correct them directly.\n\n## What to Avoid\n\n- **Hard-wrapping prose on GitHub** — in issues, pull requests and comments, GitHub renders every line break, so keep each paragraph on a single line.\n- **Overwriting `.env` files** without explicit user confirmation\n- **Creating new files** when editing existing ones would suffice\n- **Global mutable state** in library code\n- **Unnecessary dependencies** — check if existing code suffices first\n- **Reflexive regression tests** — not every bug fix earns a test, and a test coupled to implementation details can be worse than none.\n  Assert observable behavior, not internals: no private attributes, no patched machinery, no fake objects mirroring the code under test.\n  If you catch yourself building scaffolding to observe an internal mechanism, stop — find the user-visible effect to assert on, or skip the test and give the reason in the pull request.\n  Before writing a test, read a recent one in the same file and copy its shape.\n  (Details in [CONTRIBUTING.md](CONTRIBUTING.md#coding-conventions).)\n\n## Before Claiming a Task Complete\n\nRun the project's tests and linters (see [CONTRIBUTING.md](CONTRIBUTING.md)) and review your own diff for unintended scope creep.\n\n## Creating Pull Requests\n\nAlways use the repository's PR template ([`.github/PULL_REQUEST_TEMPLATE.md`](.github/PULL_REQUEST_TEMPLATE.md)) with its **Motivation**, **Implementation**, and **Progress** sections.\nDo not invent alternative formats like \"Summary\" or \"Test plan\".\n\n## Reviewing Pull Requests\n\nFollow [REVIEW.md](REVIEW.md) — it lists what to look for, defines the severity vocabulary, and sets the tone for reviews.\n",".cursor/commands/explain.md":"---\ndescription: Explain what the current code does\n---\n\nExplain what this code does, focusing on:\n\n- Main purpose and functionality\n- Key patterns or approaches used\n- Important edge cases or assumptions\n- How it fits into the broader project (NiceGUI library structure, public API, etc.)\n\nUse clear, concise language.\n",".claude/skills/release-notes/SKILL.md":"---\nname: release-notes\ndescription: Write NiceGUI release notes for a milestone to release.md and a Reddit post to reddit.md. Use when asked to draft release notes or a release announcement for a given milestone/version (e.g. \"write release notes for 3.14\").\n---\n\nWrite release notes for the milestone passed as an argument (e.g. `3.14`) to `release.md` and a Reddit post to `reddit.md`.\n\n## How to gather data\n\n**Start with the helper script** [`release-notes.sh`](release-notes.sh) (in this skill's directory), which collects the deterministic data so nothing is forgotten:\n\n- `release-notes.sh dossier \"<milestone>\"` → one JSON dossier: every milestone issue/PR with labels, author, committers, reviewers, commenters, and extracted cross-reference `#`s; each cross-reference resolved to issue/PR/**discussion** with its author (discussions are the easiest contributor to miss); plus the sponsors dump sorted by monthly amount.\n- `release-notes.sh verify \"<milestone>\" release.md` → milestone tickets missing from the draft (and `#`s in the draft that aren't milestone tickets — expected for cross-refs).\n- `release-notes.sh check-docs <slug> [slug...]` → HTTP status per docs page, to verify links before using them.\n\nThe dossier gives you the raw facts; you still apply judgment for grouping tickets into stories, writing descriptions, and deciding which commenters are substantive. The manual `gh` recipes below remain valid as a fallback or for spot-checks.\n\n1. Use `gh` to list all issues and PRs in the milestone with their labels, linked PRs, authors, and participants.\n2. For each issue/PR, inspect the timeline and comments to identify contributors (see contributor rules below).\n3. For each merged PR, also fetch its reviewers and committers explicitly — `gh pr view <n> --json reviews,commits` — and fold them into the contributor list. Comment scraping alone misses reviewers who only left a formal review. (Do not credit the merger; see Contributors.)\n4. Resolve cross-referenced numbers that are **discussions**, not issues/PRs. `gh issue view <n>` / `gh pr view <n>` fail on a discussion number; query it via GraphQL instead, e.g. `gh api graphql -f query='{repository(owner:\"zauberzeug\",name:\"nicegui\"){discussion(number:N){title author{login}}}}'`, and credit the discussion author.\n5. Check if any PRs reference a GHSA (GitHub Security Advisory) — these go into a separate Security section.\n\n## Structure\n\nFollow the exact structure used in prior releases at https://github.com/zauberzeug/nicegui/releases.\n\n### Section mapping (by label)\n\n| Label            | Section heading               |\n| ---------------- | ----------------------------- |\n| (GHSA-based PRs) | Security                      |\n| `feature`        | New features and enhancements |\n| `bug`            | Bugfixes                      |\n| `documentation`  | Documentation                 |\n| `testing`        | Testing                       |\n| `dependencies`   | Dependencies                  |\n| `infrastructure` | Infrastructure                |\n\nIf a label doesn't map to any section above, use your best judgment to place it or create an appropriate section following the established pattern.\n\nSecurity section (if any) always comes first. Then the remaining sections in the order listed above.\nSecurity items start with a \"⚠️\" prefix (e.g. `⚠️ Prevent memory exhaustion via media streaming routes`).\n\n### Sponsors footer\n\nBoth `release.md` and `reddit.md` should end with a sponsors footer.\n\nFetch active sponsors via the GitHub GraphQL API:\n\n```\ngh api graphql -f query='{ organization(login: \"zauberzeug\") { sponsorshipsAsMaintainer(first: 100, activeOnly: true) { nodes { sponsorEntity { ... on User { login name } ... on Organization { login name } } tier { monthlyPriceInDollars isOneTime } } } } }'\n```\n\nMention sponsors by name (linked to their GitHub profile) if they meet either threshold:\n\n- Monthly sponsor: $150/month or more\n- One-time sponsor: $50 or more\n\nThe threshold is a starting point, not the final word: the named set is curated and may carry forward a long-standing sponsor that now sits below the threshold (e.g. a recurring sponsor named in the previous release). So **always surface the computed candidate set and confirm the final \"top sponsors\" line with the user before writing the footer** — list each candidate with its monthly/one-time amount, and cross-check against the previous release's footer at https://github.com/zauberzeug/nicegui/releases so a previously-named sponsor isn't silently dropped.\n\nUse the existing footer format:\n\n```\n---\n\n#### Special thanks to our top sponsors [Name1](https://github.com/login1) and [Name2](https://github.com/login2) ✨\n\nand all our other [sponsors](https://github.com/sponsors/zauberzeug) and [contributors](https://github.com/zauberzeug/nicegui/graphs/contributors) for supporting this project!\n\n🙏 _Want to support this project? Check out our [GitHub Sponsors page](https://github.com/sponsors/zauberzeug) to help us keep building amazing features!_\n```\n\nIf no sponsors meet the threshold, omit the \"Special thanks\" line and just keep the general sponsors/contributors line.\n\n### Documentation links\n\nWhen an item mentions a UI element or concept that has a documentation page, link it.\nFor example: [`ui.parallax`](https://nicegui.io/documentation/parallax), [`ui.scene`](https://nicegui.io/documentation/scene).\n\n**Important:** Do not guess URLs. Verify each link exists by fetching it (the `check-docs` helper does this in bulk).\nThe typical pattern is `https://nicegui.io/documentation/<element_name_without_ui_prefix>`,\nbut sections like `section_configuration_deployment` or `section_security` also exist.\nIf a page doesn't exist yet (e.g. new elements added in this release), ask the user whether to include the link anyway (it will go live after deployment).\n\n### Item format\n\nEach line follows this pattern:\n\n```\n- Short description of the change (#issue, #pr by @author1, @author2, @contributor3)\n```\n\n- One item per story (a story is usually an issue with a PR that fixes it, but may include follow-up fixes)\n\n- **Keep each item short: name the user-visible effect in one line, typically 15–25 words before the parentheses.**\n  Details such as root causes, mechanisms, implementation choices, measurements or lists of edge cases belong in the tickets, not in the notes; readers who want more will follow the ticket numbers.\n  An item may run a little longer only when it bundles several tickets or when a single clause would otherwise be ambiguous.\n  Prior releases set the bar: compare against the last release on https://github.com/zauberzeug/nicegui/releases and shorten anything that stands out.\n  The same applies to a `**Breaking change:**` block: one or two sentences with the old and the new behavior, no rationale.\n\n- Check PR descriptions for references to feature requests, discussions, or other issues that led to the change — include those ticket numbers too\n\n- Group related tickets into a single item — all ticket numbers for the milestone should appear somewhere\n\n- Ticket numbers go in parentheses: `(#123, #456 by @user1, @user2)`\n\n- If a PR has a breaking change, add a `**Breaking change:**` block below the item, like this:\n\n  ```\n  - Short description of the change (#issue, #pr by @author1, @author2)\n\n      **Breaking change:** Explanation of what changed and how to migrate.\n      For example, if an API was removed, show the old usage and the new replacement.\n  ```\n\n### Contributors\n\nFor each item, mention all involved contributors in the `by @...` list:\n\n- Issue author\n- **The author of any feature request / discussion that led to the change** (often referenced in the PR description), plus anyone who contributed substantively to that discussion — not only the issue/PR participants\n- Users with relevant contributions to discussions (substantive comments, reproductions, debugging - not just \"me too\" comments)\n- **Reviewers** who provided relevant feedback — include both review submissions (`gh pr view <n> --json reviews`) **and** inline review comments, not just top-level issue/PR comments. A formal review with no top-level comment is easy to miss with comment scraping alone.\n- Committers (anyone who pushed commits to the PR), ignoring AI/bot co-author logins such as `claude`\n\nDo **not** credit the merger as such — merging a PR is not, on its own, a contribution worth listing.\n\n**Make sure no contributor is forgotten** — when a borderline commenter is genuinely engaged (offered to help, attempted a fix, added environment detail), lean toward including them rather than filtering them out. Only ignore:\n\n- Simple \"me too\" comments with no added information\n- Review approvals without valuable comments or own commits\n\n## Verification\n\nAfter writing `release.md`, verify completeness — `release-notes.sh verify \"<milestone>\" release.md` does steps 1-3:\n\n1. Use `gh` to list all issue and PR numbers in the milestone.\n2. Extract all `#nnn` ticket numbers from the generated `release.md`.\n3. Compare the two sets. Report any milestone tickets missing from the release notes.\n4. If there are missing tickets, investigate them and either add them to the appropriate section or explain why they were excluded (e.g. duplicates, reverted, not actually resolved).\n\n## Reddit post\n\nAfter `release.md` is complete, create `reddit.md` based on it.\n\nKeep most of the Markdown unchanged, including:\n\n- \"⚠️\" for security issues\n- The sponsors footer\n\nApply these changes:\n\n- Add a title line at the top starting with \"NiceGUI x.y.z with ...\" mentioning the most important changes\n- Remove the parenthesized ticket numbers and contributors (the `(#123, #456 by @user1, @user2)` parts)\n- Keep the documentation links from `release.md`\n",".claude/skills/fix-dependabot-alert/SKILL.md":"---\nname: fix-dependabot-alert\ndescription: Fix one or more Dependabot security alerts by updating the affected packages, rebuilding bundles and vendored files, and preparing a commit. Use when asked to fix Dependabot alerts (e.g. \"fix Dependabot alert 252\", \"fix all new Dependabot alerts\").\n---\n\nFix the Dependabot alerts whose numbers are passed as arguments.\nIf no numbers are given or the user asks for \"all new\" alerts, fetch all open ones:\n\n```\ngh api 'repos/zauberzeug/nicegui/dependabot/alerts?state=open'\n```\n\n## Python alerts (`uv.lock`)\n\nAlerts on `uv.lock` are fixed by a pin in `pyproject.toml`, not by only re-locking:\nadd `\"<pkg>>=<patched>\",  # https://github.com/zauberzeug/nicegui/security/dependabot/<number>` to the section that pulls the package in\n(`dependencies` for runtime deps, the `dev` group for test-only deps; append `, for <parent>` if it is transitive — `uv tree --invert --package <pkg>` shows the parents),\nthen run `uv lock` and check that the patched version satisfies `requires-python`.\nCommit `pyproject.toml` and `uv.lock` together; `DEPENDENCIES.md` only covers npm packages and stays unchanged.\n\n## Prebuilt bundles (plotly, json_editor, mermaid)\n\nThree elements ship code that upstream built with dependencies compiled in:\n\n- plotly imports `plotly.js/dist/plotly.min.js`, which contains all of plotly's dependencies (e.g. `maplibre-gl`, `probe-image-size`).\n- json_editor imports `vanilla-jsoneditor`, which contains svelte and its UI dependencies (e.g. `svelte-select`, `@floating-ui/dom`); its other dependencies are bundled from our lockfile.\n- mermaid depends on `@mermaid-js/parser`, which contains `langium`, `chevrotain`, `vscode-jsonrpc` and its own copy of `lodash-es`; mermaid's other dependencies are bundled from our lockfile.\n\nAlerts on these compiled-in dependencies can not be fixed in the lockfile:\n`npm update` or an override closes the alert, but `dist/` still ships the vulnerable code.\nLeave such an alert open and tell the user;\nit is fixed by upgrading the parent package once a release contains the patched version (grep the upstream file to check).\nAll other dependencies are built from package sources, so their lockfiles decide what ships.\nThe `@iconify/utils` override in mermaid is deliberate: 3.1 generates short icon ids such as `c1` that collide with NiceGUI's element ids, so do not bump it to fix an alert without checking the ids.\n\n## Steps (npm alerts)\n\n01. **Fetch each alert** to identify the package, manifest path, and first patched version:\n\n    ```\n    gh api repos/zauberzeug/nicegui/dependabot/alerts/<number>\n    ```\n\n02. **Try the minimal fix first** — `npm update <pkg>` inside the manifest's directory.\n    If the existing semver range in the parent's `package.json` already allows the patched version, this is enough and `package.json` stays untouched.\n\n03. **Escalate to an npm override** if the patched version is outside the declared range (common for transitive deps).\n    Add the package to the `overrides` section of the manifest's `package.json` with a range that includes the patched version, then run `npm install`.\n\n04. **Rebuild if the element has a `dist/`** — run `npm run clean && npm run build` in the manifest's directory, so that chunks with old content hashes do not stay behind.\n    Don't hand-revert the `dist/` changes; let pre-commit hooks normalize any whitespace-only noise (the end-of-file-fixer will handle source-map trailing newlines).\n\n05. **Rebuild vendored core libraries if the root manifest changed** — run `npm run build` in the repository root; it runs `extract_core_libraries.py` to refresh `nicegui/static/`.\n    Whitespace-only churn in unrelated static files is normalized away by the pre-commit hooks.\n\n06. **Scan other lockfiles** in the repo for the same vulnerable package — sometimes Dependabot is slow to raise the next alert:\n\n    ```\n    find . -name 'package-lock.json' -not -path '*/node_modules/*' -not -path '*/.venv/*'\n    ```\n\n    Check each one for the package and apply the same fix if needed.\n\n07. **Check for other open alerts** that might as well be bundled into the same commit:\n\n    ```\n    gh api 'repos/zauberzeug/nicegui/dependabot/alerts?state=open'\n    ```\n\n08. **Regenerate `DEPENDENCIES.md`** — run `python3 summarize_dependencies.py`; it rewrites the file from the resolved lockfile versions and belongs in the same commit.\n\n09. **Confirm with the user before committing.** Then commit with a message following the established style:\n\n    - Single alert: `fix Dependabot alert 252`\n    - Multiple: `fix Dependabot alerts 250 and 251` or `fix Dependabot alerts 246, 247, 248 and 249`\n\n    Reference alert numbers as plain integers, **never** as `#252` — GitHub auto-links `#N` to issues/PRs, which points to the wrong ticket.\n\n10. **Do not push** unless the user explicitly asks.\n",".github/copilot-instructions.md":"# GitHub Copilot Instructions for NiceGUI\n\n**Read these files before working:**\n\n1. [README.md](../README.md) - Project overview and setup\n2. [AGENTS.md](../AGENTS.md) - AI agent guidelines\n3. [CONTRIBUTING.md](../CONTRIBUTING.md) - Coding standards and workflow\n",".cursor/commands/review-branch.md":"---\ndescription: Review current branch\n---\n\nReview the current branch according to REVIEW.md.\nProvide specific, actionable feedback.\n",".cursor/rules/general.mdc":"# Cursor Rule: general\n\nPath: `.cursor/rules/general.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/zauberzeug/nicegui/HEAD/.cursor/rules/general.mdc)",".claude/skills/release-notes/release-notes.sh":"# Claude Directive: release-notes.sh\n\nPath: `.claude/skills/release-notes/release-notes.sh`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/zauberzeug/nicegui/HEAD/.claude/skills/release-notes/release-notes.sh)"},"files":{"AGENTS.md":"# AI Agent Guidelines for NiceGUI\n\nThis file gives AI assistants project-specific behavioral guidance. For coding standards, see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## Pair Programming\n\nWork as a pair programmer, not a silent code generator:\n\n- **Think from first principles**: Don't settle for the first solution; question assumptions about the true nature of the problem.\n- **Requirements first**: Verify requirements before implementing, especially when writing or changing tests.\n- **Research before guessing**: Search the codebase for similar patterns; check online sources for verification.\n- **Discuss before deciding**: When strategy is unclear, present options and trade-offs to the user instead of choosing silently.\n- **Step-by-step for large changes**: Break down significant refactorings and get confirmation along the way.\n- **Challenge assumptions**: If the user states something untrue, correct them directly.\n\n## What to Avoid\n\n- **Hard-wrapping prose on GitHub** — in issues, pull requests and comments, GitHub renders every line break, so keep each paragraph on a single line.\n- **Overwriting `.env` files** without explicit user confirmation\n- **Creating new files** when editing existing ones would suffice\n- **Global mutable state** in library code\n- **Unnecessary dependencies** — check if existing code suffices first\n- **Reflexive regression tests** — not every bug fix earns a test, and a test coupled to implementation details can be worse than none.\n  Assert observable behavior, not internals: no private attributes, no patched machinery, no fake objects mirroring the code under test.\n  If you catch yourself building scaffolding to observe an internal mechanism, stop — find the user-visible effect to assert on, or skip the test and give the reason in the pull request.\n  Before writing a test, read a recent one in the same file and copy its shape.\n  (Details in [CONTRIBUTING.md](CONTRIBUTING.md#coding-conventions).)\n\n## Before Claiming a Task Complete\n\nRun the project's tests and linters (see [CONTRIBUTING.md](CONTRIBUTING.md)) and review your own diff for unintended scope creep.\n\n## Creating Pull Requests\n\nAlways use the repository's PR template ([`.github/PULL_REQUEST_TEMPLATE.md`](.github/PULL_REQUEST_TEMPLATE.md)) with its **Motivation**, **Implementation**, and **Progress** sections.\nDo not invent alternative formats like \"Summary\" or \"Test plan\".\n\n## Reviewing Pull Requests\n\nFollow [REVIEW.md](REVIEW.md) — it lists what to look for, defines the severity vocabulary, and sets the tone for reviews.\n",".cursor/commands/explain.md":"---\ndescription: Explain what the current code does\n---\n\nExplain what this code does, focusing on:\n\n- Main purpose and functionality\n- Key patterns or approaches used\n- Important edge cases or assumptions\n- How it fits into the broader project (NiceGUI library structure, public API, etc.)\n\nUse clear, concise language.\n",".claude/skills/release-notes/SKILL.md":"---\nname: release-notes\ndescription: Write NiceGUI release notes for a milestone to release.md and a Reddit post to reddit.md. Use when asked to draft release notes or a release announcement for a given milestone/version (e.g. \"write release notes for 3.14\").\n---\n\nWrite release notes for the milestone passed as an argument (e.g. `3.14`) to `release.md` and a Reddit post to `reddit.md`.\n\n## How to gather data\n\n**Start with the helper script** [`release-notes.sh`](release-notes.sh) (in this skill's directory), which collects the deterministic data so nothing is forgotten:\n\n- `release-notes.sh dossier \"<milestone>\"` → one JSON dossier: every milestone issue/PR with labels, author, committers, reviewers, commenters, and extracted cross-reference `#`s; each cross-reference resolved to issue/PR/**discussion** with its author (discussions are the easiest contributor to miss); plus the sponsors dump sorted by monthly amount.\n- `release-notes.sh verify \"<milestone>\" release.md` → milestone tickets missing from the draft (and `#`s in the draft that aren't milestone tickets — expected for cross-refs).\n- `release-notes.sh check-docs <slug> [slug...]` → HTTP status per docs page, to verify links before using them.\n\nThe dossier gives you the raw facts; you still apply judgment for grouping tickets into stories, writing descriptions, and deciding which commenters are substantive. The manual `gh` recipes below remain valid as a fallback or for spot-checks.\n\n1. Use `gh` to list all issues and PRs in the milestone with their labels, linked PRs, authors, and participants.\n2. For each issue/PR, inspect the timeline and comments to identify contributors (see contributor rules below).\n3. For each merged PR, also fetch its reviewers and committers explicitly — `gh pr view <n> --json reviews,commits` — and fold them into the contributor list. Comment scraping alone misses reviewers who only left a formal review. (Do not credit the merger; see Contributors.)\n4. Resolve cross-referenced numbers that are **discussions**, not issues/PRs. `gh issue view <n>` / `gh pr view <n>` fail on a discussion number; query it via GraphQL instead, e.g. `gh api graphql -f query='{repository(owner:\"zauberzeug\",name:\"nicegui\"){discussion(number:N){title author{login}}}}'`, and credit the discussion author.\n5. Check if any PRs reference a GHSA (GitHub Security Advisory) — these go into a separate Security section.\n\n## Structure\n\nFollow the exact structure used in prior releases at https://github.com/zauberzeug/nicegui/releases.\n\n### Section mapping (by label)\n\n| Label            | Section heading               |\n| ---------------- | ----------------------------- |\n| (GHSA-based PRs) | Security                      |\n| `feature`        | New features and enhancements |\n| `bug`            | Bugfixes                      |\n| `documentation`  | Documentation                 |\n| `testing`        | Testing                       |\n| `dependencies`   | Dependencies                  |\n| `infrastructure` | Infrastructure                |\n\nIf a label doesn't map to any section above, use your best judgment to place it or create an appropriate section following the established pattern.\n\nSecurity section (if any) always comes first. Then the remaining sections in the order listed above.\nSecurity items start with a \"⚠️\" prefix (e.g. `⚠️ Prevent memory exhaustion via media streaming routes`).\n\n### Sponsors footer\n\nBoth `release.md` and `reddit.md` should end with a sponsors footer.\n\nFetch active sponsors via the GitHub GraphQL API:\n\n```\ngh api graphql -f query='{ organization(login: \"zauberzeug\") { sponsorshipsAsMaintainer(first: 100, activeOnly: true) { nodes { sponsorEntity { ... on User { login name } ... on Organization { login name } } tier { monthlyPriceInDollars isOneTime } } } } }'\n```\n\nMention sponsors by name (linked to their GitHub profile) if they meet either threshold:\n\n- Monthly sponsor: $150/month or more\n- One-time sponsor: $50 or more\n\nThe threshold is a starting point, not the final word: the named set is curated and may carry forward a long-standing sponsor that now sits below the threshold (e.g. a recurring sponsor named in the previous release). So **always surface the computed candidate set and confirm the final \"top sponsors\" line with the user before writing the footer** — list each candidate with its monthly/one-time amount, and cross-check against the previous release's footer at https://github.com/zauberzeug/nicegui/releases so a previously-named sponsor isn't silently dropped.\n\nUse the existing footer format:\n\n```\n---\n\n#### Special thanks to our top sponsors [Name1](https://github.com/login1) and [Name2](https://github.com/login2) ✨\n\nand all our other [sponsors](https://github.com/sponsors/zauberzeug) and [contributors](https://github.com/zauberzeug/nicegui/graphs/contributors) for supporting this project!\n\n🙏 _Want to support this project? Check out our [GitHub Sponsors page](https://github.com/sponsors/zauberzeug) to help us keep building amazing features!_\n```\n\nIf no sponsors meet the threshold, omit the \"Special thanks\" line and just keep the general sponsors/contributors line.\n\n### Documentation links\n\nWhen an item mentions a UI element or concept that has a documentation page, link it.\nFor example: [`ui.parallax`](https://nicegui.io/documentation/parallax), [`ui.scene`](https://nicegui.io/documentation/scene).\n\n**Important:** Do not guess URLs. Verify each link exists by fetching it (the `check-docs` helper does this in bulk).\nThe typical pattern is `https://nicegui.io/documentation/<element_name_without_ui_prefix>`,\nbut sections like `section_configuration_deployment` or `section_security` also exist.\nIf a page doesn't exist yet (e.g. new elements added in this release), ask the user whether to include the link anyway (it will go live after deployment).\n\n### Item format\n\nEach line follows this pattern:\n\n```\n- Short description of the change (#issue, #pr by @author1, @author2, @contributor3)\n```\n\n- One item per story (a story is usually an issue with a PR that fixes it, but may include follow-up fixes)\n\n- **Keep each item short: name the user-visible effect in one line, typically 15–25 words before the parentheses.**\n  Details such as root causes, mechanisms, implementation choices, measurements or lists of edge cases belong in the tickets, not in the notes; readers who want more will follow the ticket numbers.\n  An item may run a little longer only when it bundles several tickets or when a single clause would otherwise be ambiguous.\n  Prior releases set the bar: compare against the last release on https://github.com/zauberzeug/nicegui/releases and shorten anything that stands out.\n  The same applies to a `**Breaking change:**` block: one or two sentences with the old and the new behavior, no rationale.\n\n- Check PR descriptions for references to feature requests, discussions, or other issues that led to the change — include those ticket numbers too\n\n- Group related tickets into a single item — all ticket numbers for the milestone should appear somewhere\n\n- Ticket numbers go in parentheses: `(#123, #456 by @user1, @user2)`\n\n- If a PR has a breaking change, add a `**Breaking change:**` block below the item, like this:\n\n  ```\n  - Short description of the change (#issue, #pr by @author1, @author2)\n\n      **Breaking change:** Explanation of what changed and how to migrate.\n      For example, if an API was removed, show the old usage and the new replacement.\n  ```\n\n### Contributors\n\nFor each item, mention all involved contributors in the `by @...` list:\n\n- Issue author\n- **The author of any feature request / discussion that led to the change** (often referenced in the PR description), plus anyone who contributed substantively to that discussion — not only the issue/PR participants\n- Users with relevant contributions to discussions (substantive comments, reproductions, debugging - not just \"me too\" comments)\n- **Reviewers** who provided relevant feedback — include both review submissions (`gh pr view <n> --json reviews`) **and** inline review comments, not just top-level issue/PR comments. A formal review with no top-level comment is easy to miss with comment scraping alone.\n- Committers (anyone who pushed commits to the PR), ignoring AI/bot co-author logins such as `claude`\n\nDo **not** credit the merger as such — merging a PR is not, on its own, a contribution worth listing.\n\n**Make sure no contributor is forgotten** — when a borderline commenter is genuinely engaged (offered to help, attempted a fix, added environment detail), lean toward including them rather than filtering them out. Only ignore:\n\n- Simple \"me too\" comments with no added information\n- Review approvals without valuable comments or own commits\n\n## Verification\n\nAfter writing `release.md`, verify completeness — `release-notes.sh verify \"<milestone>\" release.md` does steps 1-3:\n\n1. Use `gh` to list all issue and PR numbers in the milestone.\n2. Extract all `#nnn` ticket numbers from the generated `release.md`.\n3. Compare the two sets. Report any milestone tickets missing from the release notes.\n4. If there are missing tickets, investigate them and either add them to the appropriate section or explain why they were excluded (e.g. duplicates, reverted, not actually resolved).\n\n## Reddit post\n\nAfter `release.md` is complete, create `reddit.md` based on it.\n\nKeep most of the Markdown unchanged, including:\n\n- \"⚠️\" for security issues\n- The sponsors footer\n\nApply these changes:\n\n- Add a title line at the top starting with \"NiceGUI x.y.z with ...\" mentioning the most important changes\n- Remove the parenthesized ticket numbers and contributors (the `(#123, #456 by @user1, @user2)` parts)\n- Keep the documentation links from `release.md`\n",".claude/skills/fix-dependabot-alert/SKILL.md":"---\nname: fix-dependabot-alert\ndescription: Fix one or more Dependabot security alerts by updating the affected packages, rebuilding bundles and vendored files, and preparing a commit. Use when asked to fix Dependabot alerts (e.g. \"fix Dependabot alert 252\", \"fix all new Dependabot alerts\").\n---\n\nFix the Dependabot alerts whose numbers are passed as arguments.\nIf no numbers are given or the user asks for \"all new\" alerts, fetch all open ones:\n\n```\ngh api 'repos/zauberzeug/nicegui/dependabot/alerts?state=open'\n```\n\n## Python alerts (`uv.lock`)\n\nAlerts on `uv.lock` are fixed by a pin in `pyproject.toml`, not by only re-locking:\nadd `\"<pkg>>=<patched>\",  # https://github.com/zauberzeug/nicegui/security/dependabot/<number>` to the section that pulls the package in\n(`dependencies` for runtime deps, the `dev` group for test-only deps; append `, for <parent>` if it is transitive — `uv tree --invert --package <pkg>` shows the parents),\nthen run `uv lock` and check that the patched version satisfies `requires-python`.\nCommit `pyproject.toml` and `uv.lock` together; `DEPENDENCIES.md` only covers npm packages and stays unchanged.\n\n## Prebuilt bundles (plotly, json_editor, mermaid)\n\nThree elements ship code that upstream built with dependencies compiled in:\n\n- plotly imports `plotly.js/dist/plotly.min.js`, which contains all of plotly's dependencies (e.g. `maplibre-gl`, `probe-image-size`).\n- json_editor imports `vanilla-jsoneditor`, which contains svelte and its UI dependencies (e.g. `svelte-select`, `@floating-ui/dom`); its other dependencies are bundled from our lockfile.\n- mermaid depends on `@mermaid-js/parser`, which contains `langium`, `chevrotain`, `vscode-jsonrpc` and its own copy of `lodash-es`; mermaid's other dependencies are bundled from our lockfile.\n\nAlerts on these compiled-in dependencies can not be fixed in the lockfile:\n`npm update` or an override closes the alert, but `dist/` still ships the vulnerable code.\nLeave such an alert open and tell the user;\nit is fixed by upgrading the parent package once a release contains the patched version (grep the upstream file to check).\nAll other dependencies are built from package sources, so their lockfiles decide what ships.\nThe `@iconify/utils` override in mermaid is deliberate: 3.1 generates short icon ids such as `c1` that collide with NiceGUI's element ids, so do not bump it to fix an alert without checking the ids.\n\n## Steps (npm alerts)\n\n01. **Fetch each alert** to identify the package, manifest path, and first patched version:\n\n    ```\n    gh api repos/zauberzeug/nicegui/dependabot/alerts/<number>\n    ```\n\n02. **Try the minimal fix first** — `npm update <pkg>` inside the manifest's directory.\n    If the existing semver range in the parent's `package.json` already allows the patched version, this is enough and `package.json` stays untouched.\n\n03. **Escalate to an npm override** if the patched version is outside the declared range (common for transitive deps).\n    Add the package to the `overrides` section of the manifest's `package.json` with a range that includes the patched version, then run `npm install`.\n\n04. **Rebuild if the element has a `dist/`** — run `npm run clean && npm run build` in the manifest's directory, so that chunks with old content hashes do not stay behind.\n    Don't hand-revert the `dist/` changes; let pre-commit hooks normalize any whitespace-only noise (the end-of-file-fixer will handle source-map trailing newlines).\n\n05. **Rebuild vendored core libraries if the root manifest changed** — run `npm run build` in the repository root; it runs `extract_core_libraries.py` to refresh `nicegui/static/`.\n    Whitespace-only churn in unrelated static files is normalized away by the pre-commit hooks.\n\n06. **Scan other lockfiles** in the repo for the same vulnerable package — sometimes Dependabot is slow to raise the next alert:\n\n    ```\n    find . -name 'package-lock.json' -not -path '*/node_modules/*' -not -path '*/.venv/*'\n    ```\n\n    Check each one for the package and apply the same fix if needed.\n\n07. **Check for other open alerts** that might as well be bundled into the same commit:\n\n    ```\n    gh api 'repos/zauberzeug/nicegui/dependabot/alerts?state=open'\n    ```\n\n08. **Regenerate `DEPENDENCIES.md`** — run `python3 summarize_dependencies.py`; it rewrites the file from the resolved lockfile versions and belongs in the same commit.\n\n09. **Confirm with the user before committing.** Then commit with a message following the established style:\n\n    - Single alert: `fix Dependabot alert 252`\n    - Multiple: `fix Dependabot alerts 250 and 251` or `fix Dependabot alerts 246, 247, 248 and 249`\n\n    Reference alert numbers as plain integers, **never** as `#252` — GitHub auto-links `#N` to issues/PRs, which points to the wrong ticket.\n\n10. **Do not push** unless the user explicitly asks.\n",".github/copilot-instructions.md":"# GitHub Copilot Instructions for NiceGUI\n\n**Read these files before working:**\n\n1. [README.md](../README.md) - Project overview and setup\n2. [AGENTS.md](../AGENTS.md) - AI agent guidelines\n3. [CONTRIBUTING.md](../CONTRIBUTING.md) - Coding standards and workflow\n",".cursor/commands/review-branch.md":"---\ndescription: Review current branch\n---\n\nReview the current branch according to REVIEW.md.\nProvide specific, actionable feedback.\n",".cursor/rules/general.mdc":"# Cursor Rule: general\n\nPath: `.cursor/rules/general.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/zauberzeug/nicegui/HEAD/.cursor/rules/general.mdc)",".claude/skills/release-notes/release-notes.sh":"# Claude Directive: release-notes.sh\n\nPath: `.claude/skills/release-notes/release-notes.sh`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/zauberzeug/nicegui/HEAD/.claude/skills/release-notes/release-notes.sh)"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/zauberzeug/nicegui/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# AI Agent Guidelines for NiceGUI\n\nThis file gives AI assistants project-specific behavioral guidance. For coding standards, see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## Pair Programming\n\nWork as a pair programmer, not a silent code generator:\n\n- **Think from first principles**: Don't settle for the first solution; question assumptions about the true nature of the problem.\n- **Requirements first**: Verify requirements before implementing, especially when writing or changing tests.\n- **Research before guessing**: Search the codebase for similar patterns; check online sources for verification.\n- **Discuss before deciding**: When strategy is unclear, present options and trade-offs to the user instead of choosing silently.\n- **Step-by-step for large changes**: Break down significant refactorings and get confirmation along the way.\n- **Challenge assumptions**: If the user states something untrue, correct them directly.\n\n## What to Avoid\n\n- **Hard-wrapping prose on GitHub** — in issues, pull requests and comments, GitHub renders every line break, so keep each paragraph on a single line.\n- **Overwriting `.env` files** without explicit user confirmation\n- **Creating new files** when editing existing ones would suffice\n- **Global mutable state** in library code\n- **Unnecessary dependencies** — check if existing code suffices first\n- **Reflexive regression tests** — not every bug fix earns a test, and a test coupled to implementation details can be worse than none.\n  Assert observable behavior, not internals: no private attributes, no patched machinery, no fake objects mirroring the code under test.\n  If you catch yourself building scaffolding to observe an internal mechanism, stop — find the user-visible effect to assert on, or skip the test and give the reason in the pull request.\n  Before writing a test, read a recent one in the same file and copy its shape.\n  (Details in [CONTRIBUTING.md](CONTRIBUTING.md#coding-conventions).)\n\n## Before Claiming a Task Complete\n\nRun the project's tests and linters (see [CONTRIBUTING.md](CONTRIBUTING.md)) and review your own diff for unintended scope creep.\n\n## Creating Pull Requests\n\nAlways use the repository's PR template ([`.github/PULL_REQUEST_TEMPLATE.md`](.github/PULL_REQUEST_TEMPLATE.md)) with its **Motivation**, **Implementation**, and **Progress** sections.\nDo not invent alternative formats like \"Summary\" or \"Test plan\".\n\n## Reviewing Pull Requests\n\nFollow [REVIEW.md](REVIEW.md) — it lists what to look for, defines the severity vocabulary, and sets the tone for reviews.\n","isInternal":false,"tokens":536,"sizeBytes":2560},{"name":"SKILL.md","path":".claude/skills/fix-dependabot-alert/SKILL.md","rawUrl":"https://raw.githubusercontent.com/zauberzeug/nicegui/HEAD/.claude/skills/fix-dependabot-alert/SKILL.md","title":"fix-dependabot-alert","category":"anthropic-skill","format":"markdown","content":"---\nname: fix-dependabot-alert\ndescription: Fix one or more Dependabot security alerts by updating the affected packages, rebuilding bundles and vendored files, and preparing a commit. Use when asked to fix Dependabot alerts (e.g. \"fix Dependabot alert 252\", \"fix all new Dependabot alerts\").\n---\n\nFix the Dependabot alerts whose numbers are passed as arguments.\nIf no numbers are given or the user asks for \"all new\" alerts, fetch all open ones:\n\n```\ngh api 'repos/zauberzeug/nicegui/dependabot/alerts?state=open'\n```\n\n## Python alerts (`uv.lock`)\n\nAlerts on `uv.lock` are fixed by a pin in `pyproject.toml`, not by only re-locking:\nadd `\"<pkg>>=<patched>\",  # https://github.com/zauberzeug/nicegui/security/dependabot/<number>` to the section that pulls the package in\n(`dependencies` for runtime deps, the `dev` group for test-only deps; append `, for <parent>` if it is transitive — `uv tree --invert --package <pkg>` shows the parents),\nthen run `uv lock` and check that the patched version satisfies `requires-python`.\nCommit `pyproject.toml` and `uv.lock` together; `DEPENDENCIES.md` only covers npm packages and stays unchanged.\n\n## Prebuilt bundles (plotly, json_editor, mermaid)\n\nThree elements ship code that upstream built with dependencies compiled in:\n\n- plotly imports `plotly.js/dist/plotly.min.js`, which contains all of plotly's dependencies (e.g. `maplibre-gl`, `probe-image-size`).\n- json_editor imports `vanilla-jsoneditor`, which contains svelte and its UI dependencies (e.g. `svelte-select`, `@floating-ui/dom`); its other dependencies are bundled from our lockfile.\n- mermaid depends on `@mermaid-js/parser`, which contains `langium`, `chevrotain`, `vscode-jsonrpc` and its own copy of `lodash-es`; mermaid's other dependencies are bundled from our lockfile.\n\nAlerts on these compiled-in dependencies can not be fixed in the lockfile:\n`npm update` or an override closes the alert, but `dist/` still ships the vulnerable code.\nLeave such an alert open and tell the user;\nit is fixed by upgrading the parent package once a release contains the patched version (grep the upstream file to check).\nAll other dependencies are built from package sources, so their lockfiles decide what ships.\nThe `@iconify/utils` override in mermaid is deliberate: 3.1 generates short icon ids such as `c1` that collide with NiceGUI's element ids, so do not bump it to fix an alert without checking the ids.\n\n## Steps (npm alerts)\n\n01. **Fetch each alert** to identify the package, manifest path, and first patched version:\n\n    ```\n    gh api repos/zauberzeug/nicegui/dependabot/alerts/<number>\n    ```\n\n02. **Try the minimal fix first** — `npm update <pkg>` inside the manifest's directory.\n    If the existing semver range in the parent's `package.json` already allows the patched version, this is enough and `package.json` stays untouched.\n\n03. **Escalate to an npm override** if the patched version is outside the declared range (common for transitive deps).\n    Add the package to the `overrides` section of the manifest's `package.json` with a range that includes the patched version, then run `npm install`.\n\n04. **Rebuild if the element has a `dist/`** — run `npm run clean && npm run build` in the manifest's directory, so that chunks with old content hashes do not stay behind.\n    Don't hand-revert the `dist/` changes; let pre-commit hooks normalize any whitespace-only noise (the end-of-file-fixer will handle source-map trailing newlines).\n\n05. **Rebuild vendored core libraries if the root manifest changed** — run `npm run build` in the repository root; it runs `extract_core_libraries.py` to refresh `nicegui/static/`.\n    Whitespace-only churn in unrelated static files is normalized away by the pre-commit hooks.\n\n06. **Scan other lockfiles** in the repo for the same vulnerable package — sometimes Dependabot is slow to raise the next alert:\n\n    ```\n    find . -name 'package-lock.json' -not -path '*/node_modules/*' -not -path '*/.venv/*'\n    ```\n\n    Check each one for the package and apply the same fix if needed.\n\n07. **Check for other open alerts** that might as well be bundled into the same commit:\n\n    ```\n    gh api 'repos/zauberzeug/nicegui/dependabot/alerts?state=open'\n    ```\n\n08. **Regenerate `DEPENDENCIES.md`** — run `python3 summarize_dependencies.py`; it rewrites the file from the resolved lockfile versions and belongs in the same commit.\n\n09. **Confirm with the user before committing.** Then commit with a message following the established style:\n\n    - Single alert: `fix Dependabot alert 252`\n    - Multiple: `fix Dependabot alerts 250 and 251` or `fix Dependabot alerts 246, 247, 248 and 249`\n\n    Reference alert numbers as plain integers, **never** as `#252` — GitHub auto-links `#N` to issues/PRs, which points to the wrong ticket.\n\n10. **Do not push** unless the user explicitly asks.\n","frontmatter":{"name":"fix-dependabot-alert","description":"Fix one or more Dependabot security alerts by updating the affected packages, rebuilding bundles and vendored files, and preparing a commit. Use when asked to fix Dependabot alerts (e.g. \"fix Dependabot alert 252\", \"fix all new Dependabot alerts\")."},"isInternal":false,"tokens":1181,"sizeBytes":4853},{"name":"SKILL.md","path":".claude/skills/release-notes/SKILL.md","rawUrl":"https://raw.githubusercontent.com/zauberzeug/nicegui/HEAD/.claude/skills/release-notes/SKILL.md","title":"release-notes","category":"anthropic-skill","format":"markdown","content":"---\nname: release-notes\ndescription: Write NiceGUI release notes for a milestone to release.md and a Reddit post to reddit.md. Use when asked to draft release notes or a release announcement for a given milestone/version (e.g. \"write release notes for 3.14\").\n---\n\nWrite release notes for the milestone passed as an argument (e.g. `3.14`) to `release.md` and a Reddit post to `reddit.md`.\n\n## How to gather data\n\n**Start with the helper script** [`release-notes.sh`](release-notes.sh) (in this skill's directory), which collects the deterministic data so nothing is forgotten:\n\n- `release-notes.sh dossier \"<milestone>\"` → one JSON dossier: every milestone issue/PR with labels, author, committers, reviewers, commenters, and extracted cross-reference `#`s; each cross-reference resolved to issue/PR/**discussion** with its author (discussions are the easiest contributor to miss); plus the sponsors dump sorted by monthly amount.\n- `release-notes.sh verify \"<milestone>\" release.md` → milestone tickets missing from the draft (and `#`s in the draft that aren't milestone tickets — expected for cross-refs).\n- `release-notes.sh check-docs <slug> [slug...]` → HTTP status per docs page, to verify links before using them.\n\nThe dossier gives you the raw facts; you still apply judgment for grouping tickets into stories, writing descriptions, and deciding which commenters are substantive. The manual `gh` recipes below remain valid as a fallback or for spot-checks.\n\n1. Use `gh` to list all issues and PRs in the milestone with their labels, linked PRs, authors, and participants.\n2. For each issue/PR, inspect the timeline and comments to identify contributors (see contributor rules below).\n3. For each merged PR, also fetch its reviewers and committers explicitly — `gh pr view <n> --json reviews,commits` — and fold them into the contributor list. Comment scraping alone misses reviewers who only left a formal review. (Do not credit the merger; see Contributors.)\n4. Resolve cross-referenced numbers that are **discussions**, not issues/PRs. `gh issue view <n>` / `gh pr view <n>` fail on a discussion number; query it via GraphQL instead, e.g. `gh api graphql -f query='{repository(owner:\"zauberzeug\",name:\"nicegui\"){discussion(number:N){title author{login}}}}'`, and credit the discussion author.\n5. Check if any PRs reference a GHSA (GitHub Security Advisory) — these go into a separate Security section.\n\n## Structure\n\nFollow the exact structure used in prior releases at https://github.com/zauberzeug/nicegui/releases.\n\n### Section mapping (by label)\n\n| Label            | Section heading               |\n| ---------------- | ----------------------------- |\n| (GHSA-based PRs) | Security                      |\n| `feature`        | New features and enhancements |\n| `bug`            | Bugfixes                      |\n| `documentation`  | Documentation                 |\n| `testing`        | Testing                       |\n| `dependencies`   | Dependencies                  |\n| `infrastructure` | Infrastructure                |\n\nIf a label doesn't map to any section above, use your best judgment to place it or create an appropriate section following the established pattern.\n\nSecurity section (if any) always comes first. Then the remaining sections in the order listed above.\nSecurity items start with a \"⚠️\" prefix (e.g. `⚠️ Prevent memory exhaustion via media streaming routes`).\n\n### Sponsors footer\n\nBoth `release.md` and `reddit.md` should end with a sponsors footer.\n\nFetch active sponsors via the GitHub GraphQL API:\n\n```\ngh api graphql -f query='{ organization(login: \"zauberzeug\") { sponsorshipsAsMaintainer(first: 100, activeOnly: true) { nodes { sponsorEntity { ... on User { login name } ... on Organization { login name } } tier { monthlyPriceInDollars isOneTime } } } } }'\n```\n\nMention sponsors by name (linked to their GitHub profile) if they meet either threshold:\n\n- Monthly sponsor: $150/month or more\n- One-time sponsor: $50 or more\n\nThe threshold is a starting point, not the final word: the named set is curated and may carry forward a long-standing sponsor that now sits below the threshold (e.g. a recurring sponsor named in the previous release). So **always surface the computed candidate set and confirm the final \"top sponsors\" line with the user before writing the footer** — list each candidate with its monthly/one-time amount, and cross-check against the previous release's footer at https://github.com/zauberzeug/nicegui/releases so a previously-named sponsor isn't silently dropped.\n\nUse the existing footer format:\n\n```\n---\n\n#### Special thanks to our top sponsors [Name1](https://github.com/login1) and [Name2](https://github.com/login2) ✨\n\nand all our other [sponsors](https://github.com/sponsors/zauberzeug) and [contributors](https://github.com/zauberzeug/nicegui/graphs/contributors) for supporting this project!\n\n🙏 _Want to support this project? Check out our [GitHub Sponsors page](https://github.com/sponsors/zauberzeug) to help us keep building amazing features!_\n```\n\nIf no sponsors meet the threshold, omit the \"Special thanks\" line and just keep the general sponsors/contributors line.\n\n### Documentation links\n\nWhen an item mentions a UI element or concept that has a documentation page, link it.\nFor example: [`ui.parallax`](https://nicegui.io/documentation/parallax), [`ui.scene`](https://nicegui.io/documentation/scene).\n\n**Important:** Do not guess URLs. Verify each link exists by fetching it (the `check-docs` helper does this in bulk).\nThe typical pattern is `https://nicegui.io/documentation/<element_name_without_ui_prefix>`,\nbut sections like `section_configuration_deployment` or `section_security` also exist.\nIf a page doesn't exist yet (e.g. new elements added in this release), ask the user whether to include the link anyway (it will go live after deployment).\n\n### Item format\n\nEach line follows this pattern:\n\n```\n- Short description of the change (#issue, #pr by @author1, @author2, @contributor3)\n```\n\n- One item per story (a story is usually an issue with a PR that fixes it, but may include follow-up fixes)\n\n- **Keep each item short: name the user-visible effect in one line, typically 15–25 words before the parentheses.**\n  Details such as root causes, mechanisms, implementation choices, measurements or lists of edge cases belong in the tickets, not in the notes; readers who want more will follow the ticket numbers.\n  An item may run a little longer only when it bundles several tickets or when a single clause would otherwise be ambiguous.\n  Prior releases set the bar: compare against the last release on https://github.com/zauberzeug/nicegui/releases and shorten anything that stands out.\n  The same applies to a `**Breaking change:**` block: one or two sentences with the old and the new behavior, no rationale.\n\n- Check PR descriptions for references to feature requests, discussions, or other issues that led to the change — include those ticket numbers too\n\n- Group related tickets into a single item — all ticket numbers for the milestone should appear somewhere\n\n- Ticket numbers go in parentheses: `(#123, #456 by @user1, @user2)`\n\n- If a PR has a breaking change, add a `**Breaking change:**` block below the item, like this:\n\n  ```\n  - Short description of the change (#issue, #pr by @author1, @author2)\n\n      **Breaking change:** Explanation of what changed and how to migrate.\n      For example, if an API was removed, show the old usage and the new replacement.\n  ```\n\n### Contributors\n\nFor each item, mention all involved contributors in the `by @...` list:\n\n- Issue author\n- **The author of any feature request / discussion that led to the change** (often referenced in the PR description), plus anyone who contributed substantively to that discussion — not only the issue/PR participants\n- Users with relevant contributions to discussions (substantive comments, reproductions, debugging - not just \"me too\" comments)\n- **Reviewers** who provided relevant feedback — include both review submissions (`gh pr view <n> --json reviews`) **and** inline review comments, not just top-level issue/PR comments. A formal review with no top-level comment is easy to miss with comment scraping alone.\n- Committers (anyone who pushed commits to the PR), ignoring AI/bot co-author logins such as `claude`\n\nDo **not** credit the merger as such — merging a PR is not, on its own, a contribution worth listing.\n\n**Make sure no contributor is forgotten** — when a borderline commenter is genuinely engaged (offered to help, attempted a fix, added environment detail), lean toward including them rather than filtering them out. Only ignore:\n\n- Simple \"me too\" comments with no added information\n- Review approvals without valuable comments or own commits\n\n## Verification\n\nAfter writing `release.md`, verify completeness — `release-notes.sh verify \"<milestone>\" release.md` does steps 1-3:\n\n1. Use `gh` to list all issue and PR numbers in the milestone.\n2. Extract all `#nnn` ticket numbers from the generated `release.md`.\n3. Compare the two sets. Report any milestone tickets missing from the release notes.\n4. If there are missing tickets, investigate them and either add them to the appropriate section or explain why they were excluded (e.g. duplicates, reverted, not actually resolved).\n\n## Reddit post\n\nAfter `release.md` is complete, create `reddit.md` based on it.\n\nKeep most of the Markdown unchanged, including:\n\n- \"⚠️\" for security issues\n- The sponsors footer\n\nApply these changes:\n\n- Add a title line at the top starting with \"NiceGUI x.y.z with ...\" mentioning the most important changes\n- Remove the parenthesized ticket numbers and contributors (the `(#123, #456 by @user1, @user2)` parts)\n- Keep the documentation links from `release.md`\n","frontmatter":{"name":"release-notes","description":"Write NiceGUI release notes for a milestone to release.md and a Reddit post to reddit.md. Use when asked to draft release notes or a release announcement for a given milestone/version (e.g. \"write release notes for 3.14\")."},"isInternal":false,"tokens":2169,"sizeBytes":9794},{"name":"general.mdc","path":".cursor/rules/general.mdc","rawUrl":"https://raw.githubusercontent.com/zauberzeug/nicegui/HEAD/.cursor/rules/general.mdc","title":"Cursor Rule: general","category":"cursor-rule","format":"mdc","content":"# Cursor Rule: general\n\nPath: `.cursor/rules/general.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/zauberzeug/nicegui/HEAD/.cursor/rules/general.mdc)","tokens":300,"sizeBytes":172},{"name":"release-notes.sh","path":".claude/skills/release-notes/release-notes.sh","rawUrl":"https://raw.githubusercontent.com/zauberzeug/nicegui/HEAD/.claude/skills/release-notes/release-notes.sh","title":"Claude Directive: release-notes.sh","category":"claude-rule","format":"markdown","content":"# Claude Directive: release-notes.sh\n\nPath: `.claude/skills/release-notes/release-notes.sh`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/zauberzeug/nicegui/HEAD/.claude/skills/release-notes/release-notes.sh)","tokens":300,"sizeBytes":226},{"name":"copilot-instructions.md","path":".github/copilot-instructions.md","rawUrl":"https://raw.githubusercontent.com/zauberzeug/nicegui/HEAD/.github/copilot-instructions.md","title":"GitHub Copilot Instructions","category":"copilot-instructions","format":"markdown","content":"# GitHub Copilot Instructions for NiceGUI\n\n**Read these files before working:**\n\n1. [README.md](../README.md) - Project overview and setup\n2. [AGENTS.md](../AGENTS.md) - AI agent guidelines\n3. [CONTRIBUTING.md](../CONTRIBUTING.md) - Coding standards and workflow\n","isInternal":false,"tokens":72,"sizeBytes":263},{"name":"explain.md","path":".cursor/commands/explain.md","rawUrl":"https://raw.githubusercontent.com/zauberzeug/nicegui/HEAD/.cursor/commands/explain.md","title":"Command: /explain","category":"command-prompt","format":"markdown","content":"---\ndescription: Explain what the current code does\n---\n\nExplain what this code does, focusing on:\n\n- Main purpose and functionality\n- Key patterns or approaches used\n- Important edge cases or assumptions\n- How it fits into the broader project (NiceGUI library structure, public API, etc.)\n\nUse clear, concise language.\n","frontmatter":{"description":"Explain what the current code does"},"isInternal":false,"tokens":66,"sizeBytes":320},{"name":"review-branch.md","path":".cursor/commands/review-branch.md","rawUrl":"https://raw.githubusercontent.com/zauberzeug/nicegui/HEAD/.cursor/commands/review-branch.md","title":"Command: /review-branch","category":"command-prompt","format":"markdown","content":"---\ndescription: Review current branch\n---\n\nReview the current branch according to REVIEW.md.\nProvide specific, actionable feedback.\n","frontmatter":{"description":"Review current branch"},"isInternal":false,"tokens":23,"sizeBytes":133}],"systemPromptSnippet":"<yakaai_skills repo=\"zauberzeug/nicegui\">\n<!-- File: AGENTS.md (Tokens: ~536 | Category: root-instruction) -->\n# AI Agent Guidelines for NiceGUI\n\nThis file gives AI assistants project-specific behavioral guidance. For coding standards, see [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## Pair Programming\n\nWork as a pair programmer, not a silent code generator:\n\n- **Think from first principles**: Don't settle for the first solution; question assumptions about the true nature of the problem.\n- **Requirements first**: Verify requirements before implementing, especially when writing or changing tests.\n- **Research before guessing**: Search the codebase for similar patterns; check online sources for verification.\n- **Discuss before deciding**: When strategy is unclear, present options and trade-offs to the user instead of choosing silently.\n- **Step-by-step for large changes**: Break down significant refactorings and get confirmation along the way.\n- **Challenge assumptions**: If the user states something untrue, correct them directly.\n\n## What to Avoid\n\n- **Hard-wrapping prose on GitHub** — in issues, pull requests and comments, GitHub renders every line break, so keep each paragraph on a single line.\n- **Overwriting `.env` files** without explicit user confirmation\n- **Creating new files** when editing existing ones would suffice\n- **Global mutable state** in library code\n- **Unnecessary dependencies** — check if existing code suffices first\n- **Reflexive regression tests** — not every bug fix earns a test, and a test coupled to implementation details can be worse than none.\n  Assert observable behavior, not internals: no private attributes, no patched machinery, no fake objects mirroring the code under test.\n  If you catch yourself building scaffolding to observe an internal mechanism, stop — find the user-visible effect to assert on, or skip the test and give the reason in the pull request.\n  Before writing a test, read a recent one in the same file and copy its shape.\n  (Details in [CONTRIBUTING.md](CONTRIBUTING.md#coding-conventions).)\n\n## Before Claiming a Task Complete\n\nRun the project's tests and linters (see [CONTRIBUTING.md](CONTRIBUTING.md)) and review your own diff for unintended scope creep.\n\n## Creating Pull Requests\n\nAlways use the repository's PR template ([`.github/PULL_REQUEST_TEMPLATE.md`](.github/PULL_REQUEST_TEMPLATE.md)) with its **Motivation**, **Implementation**, and **Progress** sections.\nDo not invent alternative formats like \"Summary\" or \"Test plan\".\n\n## Reviewing Pull Requests\n\nFollow [REVIEW.md](REVIEW.md) — it lists what to look for, defines the severity vocabulary, and sets the tone for reviews.\n\n<!-- File: .claude/skills/fix-dependabot-alert/SKILL.md (Tokens: ~1181 | Category: anthropic-skill) -->\n---\nname: fix-dependabot-alert\ndescription: Fix one or more Dependabot security alerts by updating the affected packages, rebuilding bundles and vendored files, and preparing a commit. Use when asked to fix Dependabot alerts (e.g. \"fix Dependabot alert 252\", \"fix all new Dependabot alerts\").\n---\n\nFix the Dependabot alerts whose numbers are passed as arguments.\nIf no numbers are given or the user asks for \"all new\" alerts, fetch all open ones:\n\n```\ngh api 'repos/zauberzeug/nicegui/dependabot/alerts?state=open'\n```\n\n## Python alerts (`uv.lock`)\n\nAlerts on `uv.lock` are fixed by a pin in `pyproject.toml`, not by only re-locking:\nadd `\"<pkg>>=<patched>\",  # https://github.com/zauberzeug/nicegui/security/dependabot/<number>` to the section that pulls the package in\n(`dependencies` for runtime deps, the `dev` group for test-only deps; append `, for <parent>` if it is transitive — `uv tree --invert --package <pkg>` shows the parents),\nthen run `uv lock` and check that the patched version satisfies `requires-python`.\nCommit `pyproject.toml` and `uv.lock` together; `DEPENDENCIES.md` only covers npm packages and stays unchanged.\n\n## Prebuilt bundles (plotly, json_editor, mermaid)\n\nThree elements ship code that upstream built with dependencies compiled in:\n\n- plotly imports `plotly.js/dist/plotly.min.js`, which contains all of plotly's dependencies (e.g. `maplibre-gl`, `probe-image-size`).\n- json_editor imports `vanilla-jsoneditor`, which contains svelte and its UI dependencies (e.g. `svelte-select`, `@floating-ui/dom`); its other dependencies are bundled from our lockfile.\n- mermaid depends on `@mermaid-js/parser`, which contains `langium`, `chevrotain`, `vscode-jsonrpc` and its own copy of `lodash-es`; mermaid's other dependencies are bundled from our lockfile.\n\nAlerts on these compiled-in dependencies can not be fixed in the lockfile:\n`npm update` or an override closes the alert, but `dist/` still ships the vulnerable code.\nLeave such an alert open and tell the user;\nit is fixed by upgrading the parent package once a release contains the patched version (grep the upstream file to check).\nAll other dependencies are built from package sources, so their lockfiles decide what ships.\nThe `@iconify/utils` override in mermaid is deliberate: 3.1 generates short icon ids such as `c1` that collide with NiceGUI's element ids, so do not bump it to fix an alert without checking the ids.\n\n## Steps (npm alerts)\n\n01. **Fetch each alert** to identify the package, manifest path, and first patched version:\n\n    ```\n    gh api repos/zauberzeug/nicegui/dependabot/alerts/<number>\n    ```\n\n02. **Try the minimal fix first** — `npm update <pkg>` inside the manifest's directory.\n    If the existing semver range in the parent's `package.json` already allows the patched version, this is enough and `package.json` stays untouched.\n\n03. **Escalate to an npm override** if the patched version is outside the declared range (common for transitive deps).\n    Add the package to the `overrides` section of the manifest's `package.json` with a range that includes the patched version, then run `npm install`.\n\n04. **Rebuild if the element has a `dist/`** — run `npm run clean && npm run build` in the manifest's directory, so that chunks with old content hashes do not stay behind.\n    Don't hand-revert the `dist/` changes; let pre-commit hooks normalize any whitespace-only noise (the end-of-file-fixer will handle source-map trailing newlines).\n\n05. **Rebuild vendored core libraries if the root manifest changed** — run `npm run build` in the repository root; it runs `extract_core_libraries.py` to refresh `nicegui/static/`.\n    Whitespace-only churn in unrelated static files is normalized away by the pre-commit hooks.\n\n06. **Scan other lockfiles** in the repo for the same vulnerable package — sometimes Dependabot is slow to raise the next alert:\n\n    ```\n    find . -name 'package-lock.json' -not -path '*/node_modules/*' -not -path '*/.venv/*'\n    ```\n\n    Check each one for the package and apply the same fix if needed.\n\n07. **Check for other open alerts** that might as well be bundled into the same commit:\n\n    ```\n    gh api 'repos/zauberzeug/nicegui/dependabot/alerts?state=open'\n    ```\n\n08. **Regenerate `DEPENDENCIES.md`** — run `python3 summarize_dependencies.py`; it rewrites the file from the resolved lockfile versions and belongs in the same commit.\n\n09. **Confirm with the user before committing.** Then commit with a message following the established style:\n\n    - Single alert: `fix Dependabot alert 252`\n    - Multiple: `fix Dependabot alerts 250 and 251` or `fix Dependabot alerts 246, 247, 248 and 249`\n\n    Reference alert numbers as plain integers, **never** as `#252` — GitHub auto-links `#N` to issues/PRs, which points to the wrong ticket.\n\n10. **Do not push** unless the user explicitly asks.\n\n<!-- File: .claude/skills/release-notes/SKILL.md (Tokens: ~2169 | Category: anthropic-skill) -->\n---\nname: release-notes\ndescription: Write NiceGUI release notes for a milestone to release.md and a Reddit post to reddit.md. Use when asked to draft release notes or a release announcement for a given milestone/version (e.g. \"write release notes for 3.14\").\n---\n\nWrite release notes for the milestone passed as an argument (e.g. `3.14`) to `release.md` and a Reddit post to `reddit.md`.\n\n## How to gather data\n\n**Start with the helper script** [`release-notes.sh`](release-notes.sh) (in this skill's directory), which collects the deterministic data so nothing is forgotten:\n\n- `release-notes.sh dossier \"<milestone>\"` → one JSON dossier: every milestone issue/PR with labels, author, committers, reviewers, commenters, and extracted cross-reference `#`s; each cross-reference resolved to issue/PR/**discussion** with its author (discussions are the easiest contributor to miss); plus the sponsors dump sorted by monthly amount.\n- `release-notes.sh verify \"<milestone>\" release.md` → milestone tickets missing from the draft (and `#`s in the draft that aren't milestone tickets — expected for cross-refs).\n- `release-notes.sh check-docs <slug> [slug...]` → HTTP status per docs page, to verify links before using them.\n\nThe dossier gives you the raw facts; you still apply judgment for grouping tickets into stories, writing descriptions, and deciding which commenters are substantive. The manual `gh` recipes below remain valid as a fallback or for spot-checks.\n\n1. Use `gh` to list all issues and PRs in the milestone with their labels, linked PRs, authors, and participants.\n2. For each issue/PR, inspect the timeline and comments to identify contributors (see contributor rules below).\n3. For each merged PR, also fetch its reviewers and committers explicitly — `gh pr view <n> --json reviews,commits` — and fold them into the contributor list. Comment scraping alone misses reviewers who only left a formal review. (Do not credit the merger; see Contributors.)\n4. Resolve cross-referenced numbers that are **discussions**, not issues/PRs. `gh issue view <n>` / `gh pr view <n>` fail on a discussion number; query it via GraphQL instead, e.g. `gh api graphql -f query='{repository(owner:\"zauberzeug\",name:\"nicegui\"){discussion(number:N){title author{login}}}}'`, and credit the discussion author.\n5. Check if any PRs reference a GHSA (GitHub Security Advisory) — these go into a separate Security section.\n\n## Structure\n\nFollow the exact structure used in prior releases at https://github.com/zauberzeug/nicegui/releases.\n\n### Section mapping (by label)\n\n| Label            | Section heading               |\n| ---------------- | ----------------------------- |\n| (GHSA-based PRs) | Security                      |\n| `feature`        | New features and enhancements |\n| `bug`            | Bugfixes                      |\n| `documentation`  | Documentation                 |\n| `testing`        | Testing                       |\n| `dependencies`   | Dependencies                  |\n| `infrastructure` | Infrastructure                |\n\nIf a label doesn't map to any section above, use your best judgment to place it or create an appropriate section following the established pattern.\n\nSecurity section (if any) always comes first. Then the remaining sections in the order listed above.\nSecurity items start with a \"⚠️\" prefix (e.g. `⚠️ Prevent memory exhaustion via media streaming routes`).\n\n### Sponsors footer\n\nBoth `release.md` and `reddit.md` should end with a sponsors footer.\n\nFetch active sponsors via the GitHub GraphQL API:\n\n```\ngh api graphql -f query='{ organization(login: \"zauberzeug\") { sponsorshipsAsMaintainer(first: 100, activeOnly: true) { nodes { sponsorEntity { ... on User { login name } ... on Organization { login name } } tier { monthlyPriceInDollars isOneTime } } } } }'\n```\n\nMention sponsors by name (linked to their GitHub profile) if they meet either threshold:\n\n- Monthly sponsor: $150/month or more\n- One-time sponsor: $50 or more\n\nThe threshold is a starting point, not the final word: the named set is curated and may carry forward a long-standing sponsor that now sits below the threshold (e.g. a recurring sponsor named in the previous release). So **always surface the computed candidate set and confirm the final \"top sponsors\" line with the user before writing the footer** — list each candidate with its monthly/one-time amount, and cross-check against the previous release's footer at https://github.com/zauberzeug/nicegui/releases so a previously-named sponsor isn't silently dropped.\n\nUse the existing footer format:\n\n```\n---\n\n#### Special thanks to our top sponsors [Name1](https://github.com/login1) and [Name2](https://github.com/login2) ✨\n\nand all our other [sponsors](https://github.com/sponsors/zauberzeug) and [contributors](https://github.com/zauberzeug/nicegui/graphs/contributors) for supporting this project!\n\n🙏 _Want to support this project? Check out our [GitHub Sponsors page](https://github.com/sponsors/zauberzeug) to help us keep building amazing features!_\n```\n\nIf no sponsors meet the threshold, omit the \"Special thanks\" line and just keep the general sponsors/contributors line.\n\n### Documentation links\n\nWhen an item mentions a UI element or concept that has a documentation page, link it.\nFor example: [`ui.parallax`](https://nicegui.io/documentation/parallax), [`ui.scene`](https://nicegui.io/documentation/scene).\n\n**Important:** Do not guess URLs. Verify each link exists by fetching it (the `check-docs` helper does this in bulk).\nThe typical pattern is `https://nicegui.io/documentation/<element_name_without_ui_prefix>`,\nbut sections like `section_configuration_deployment` or `section_security` also exist.\nIf a page doesn't exist yet (e.g. new elements added in this release), ask the user whether to include the link anyway (it will go live after deployment).\n\n### Item format\n\nEach line follows this pattern:\n\n```\n- Short description of the change (#issue, #pr by @author1, @author2, @contributor3)\n```\n\n- One item per story (a story is usually an issue with a PR that fixes it, but may include follow-up fixes)\n\n- **Keep each item short: name the user-visible effect in one line, typically 15–25 words before the parentheses.**\n  Details such as root causes, mechanisms, implementation choices, measurements or lists of edge cases belong in the tickets, not in the notes; readers who want more will follow the ticket numbers.\n  An item may run a little longer only when it bundles several tickets or when a single clause would otherwise be ambiguous.\n  Prior releases set the bar: compare against the last release on https://github.com/zauberzeug/nicegui/releases and shorten anything that stands out.\n  The same applies to a `**Breaking change:**` block: one or two sentences with the old and the new behavior, no rationale.\n\n- Check PR descriptions for references to feature requests, discussions, or other issues that led to the change — include those ticket numbers too\n\n- Group related tickets into a single item — all ticket numbers for the milestone should appear somewhere\n\n- Ticket numbers go in parentheses: `(#123, #456 by @user1, @user2)`\n\n- If a PR has a breaking change, add a `**Breaking change:**` block below the item, like this:\n\n  ```\n  - Short description of the change (#issue, #pr by @author1, @author2)\n\n      **Breaking change:** Explanation of what changed and how to migrate.\n      For example, if an API was removed, show the old usage and the new replacement.\n  ```\n\n### Contributors\n\nFor each item, mention all involved contributors in the `by @...` list:\n\n- Issue author\n- **The author of any feature request / discussion that led to the change** (often referenced in the PR description), plus anyone who contributed substantively to that discussion — not only the issue/PR participants\n- Users with relevant contributions to discussions (substantive comments, reproductions, debugging - not just \"me too\" comments)\n- **Reviewers** who provided relevant feedback — include both review submissions (`gh pr view <n> --json reviews`) **and** inline review comments, not just top-level issue/PR comments. A formal review with no top-level comment is easy to miss with comment scraping alone.\n- Committers (anyone who pushed commits to the PR), ignoring AI/bot co-author logins such as `claude`\n\nDo **not** credit the merger as such — merging a PR is not, on its own, a contribution worth listing.\n\n**Make sure no contributor is forgotten** — when a borderline commenter is genuinely engaged (offered to help, attempted a fix, added environment detail), lean toward including them rather than filtering them out. Only ignore:\n\n- Simple \"me too\" comments with no added information\n- Review approvals without valuable comments or own commits\n\n## Verification\n\nAfter writing `release.md`, verify completeness — `release-notes.sh verify \"<milestone>\" release.md` does steps 1-3:\n\n1. Use `gh` to list all issue and PR numbers in the milestone.\n2. Extract all `#nnn` ticket numbers from the generated `release.md`.\n3. Compare the two sets. Report any milestone tickets missing from the release notes.\n4. If there are missing tickets, investigate them and either add them to the appropriate section or explain why they were excluded (e.g. duplicates, reverted, not actually resolved).\n\n## Reddit post\n\nAfter `release.md` is complete, create `reddit.md` based on it.\n\nKeep most of the Markdown unchanged, including:\n\n- \"⚠️\" for security issues\n- The sponsors footer\n\nApply these changes:\n\n- Add a title line at the top starting with \"NiceGUI x.y.z with ...\" mentioning the most important changes\n- Remove the parenthesized ticket numbers and contributors (the `(#123, #456 by @user1, @user2)` parts)\n- Keep the documentation links from `release.md`\n\n<!-- File: .cursor/rules/general.mdc (Tokens: ~300 | Category: cursor-rule) -->\n# Cursor Rule: general\n\nPath: `.cursor/rules/general.mdc`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/zauberzeug/nicegui/HEAD/.cursor/rules/general.mdc)\n\n<!-- File: .claude/skills/release-notes/release-notes.sh (Tokens: ~300 | Category: claude-rule) -->\n# Claude Directive: release-notes.sh\n\nPath: `.claude/skills/release-notes/release-notes.sh`\n\n[View Raw Content on GitHub](https://raw.githubusercontent.com/zauberzeug/nicegui/HEAD/.claude/skills/release-notes/release-notes.sh)\n\n<!-- File: .github/copilot-instructions.md (Tokens: ~72 | Category: copilot-instructions) -->\n# GitHub Copilot Instructions for NiceGUI\n\n**Read these files before working:**\n\n1. [README.md](../README.md) - Project overview and setup\n2. [AGENTS.md](../AGENTS.md) - AI agent guidelines\n3. [CONTRIBUTING.md](../CONTRIBUTING.md) - Coding standards and workflow\n\n<!-- File: .cursor/commands/explain.md (Tokens: ~66 | Category: command-prompt) -->\n---\ndescription: Explain what the current code does\n---\n\nExplain what this code does, focusing on:\n\n- Main purpose and functionality\n- Key patterns or approaches used\n- Important edge cases or assumptions\n- How it fits into the broader project (NiceGUI library structure, public API, etc.)\n\nUse clear, concise language.\n\n<!-- File: .cursor/commands/review-branch.md (Tokens: ~23 | Category: command-prompt) -->\n---\ndescription: Review current branch\n---\n\nReview the current branch according to REVIEW.md.\nProvide specific, actionable feedback.\n</yakaai_skills>"}