[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-red-hat-developer-rhdh-coding":3,"mdc-dy7wix-key":37,"related-repo-red-hat-developer-rhdh-coding":2036,"related-org-red-hat-developer-rhdh-coding":2145},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":12,"stars":26,"repoUrl":27,"updatedAt":28,"license":29,"forks":30,"topics":31,"repo":32,"sourceUrl":35,"mdContent":36},"rhdh-coding","develop Backstage and RHDH plugins","Backstage and RHDH plugin development patterns. Use when writing, modifying, or reviewing code in a Backstage or RHDH plugin — frontend components, backend services, API clients, styling, testing, entity pages, scaffolder actions, catalog processors, NFS Blueprints, dynamic plugin configuration. Also use when asked to \"add a feature to a plugin\", \"implement a Backstage component\", \"create an API client\", \"write plugin tests\", \"add a backend route\", \"create a scaffolder action\", \"what plugin type should I use\", or any coding task in a Backstage or RHDH codebase.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},"red-hat-developer","Red Hat Developer","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Fred-hat-developer.png","redhat-developer",[13,17,20,23],{"name":14,"slug":15,"type":16},"Backend","backend","tag",{"name":18,"slug":19,"type":16},"Engineering","engineering",{"name":21,"slug":22,"type":16},"API Development","api-development",{"name":24,"slug":25,"type":16},"Frontend","frontend",15,"https:\u002F\u002Fgithub.com\u002Fredhat-developer\u002Frhdh-skill","2026-07-16T06:00:20.436156",null,28,[],{"repoUrl":27,"stars":26,"forks":30,"topics":33,"description":34},[],"Claude Code skill for RHDH plugin lifecycle management","https:\u002F\u002Fgithub.com\u002Fredhat-developer\u002Frhdh-skill\u002Ftree\u002FHEAD\u002Fskills\u002Frhdh-coding","---\nname: rhdh-coding\ndescription: >-\n  Backstage and RHDH plugin development patterns. Use when writing, modifying,\n  or reviewing code in a Backstage or RHDH plugin — frontend components, backend\n  services, API clients, styling, testing, entity pages, scaffolder actions,\n  catalog processors, NFS Blueprints, dynamic plugin configuration. Also use\n  when asked to \"add a feature to a plugin\", \"implement a Backstage component\",\n  \"create an API client\", \"write plugin tests\", \"add a backend route\", \"create\n  a scaffolder action\", \"what plugin type should I use\", or any coding task in\n  a Backstage or RHDH codebase.\n---\n\n# RHDH Coding\n\nPatterns for Backstage and RHDH plugin development that agents need but can't\nreliably get from training data or codebase discovery alone. This covers what\nyou'd learn after six months of getting burned by non-obvious conventions.\n\n## Before You Write Code\n\n### 1. Check for existing specs\n\nLook for a spec, PRD, or OpenSpec design for this work — in `docs\u002Fplans\u002F**\u002F`,\n`specifications\u002F`, `openspec\u002Fchanges\u002F*\u002F`, or linked from the issue. If found,\nuse the component list and acceptance criteria as your implementation blueprint.\nRead `references\u002Ffrontend-specs.md` for what good frontend specs include.\n\n### 2. Discover the plugin context\n\nRun the detection script to understand what you're working with:\n\n```bash\npython scripts\u002Fdetect-rhdh-context.py --path \u003Cplugin-dir>\n```\n\nThis reports: Backstage role, frontend system (legacy\u002FNFS\u002Fdual), existing\nextensions, MUI version, dynamic plugin status, plugin ID, scalprum name.\n\n### 3. Read workspace instructions\n\n```bash\ntest -f AGENTS.md && cat AGENTS.md\ntest -f CLAUDE.md && cat CLAUDE.md\n```\n\nThese contain repo-specific rules that override general patterns.\n\n### 4. Check version compatibility\n\nConsult `..\u002Frhdh\u002Freferences\u002Fversions.md` for the RHDH → Backstage version\nmatrix. Your `@backstage\u002F*` dependency versions must match the target RHDH\nversion. Mismatched versions cause runtime errors — most commonly \"Cannot\nread properties of undefined.\"\n\n## Styling: BUI First\n\n**For new plugins,** use Backstage UI (`@backstage\u002Fui`) with CSS Modules and\nBUI CSS variables. **In existing plugins,** match whatever the workspace already\nuses — if it's MUI v4, stay consistent rather than mixing libraries. Only\nintroduce BUI in a workspace that has already adopted it or is actively migrating.\n\n**Priority for new plugins:**\n1. **BUI** (`@backstage\u002Fui`) — default for new plugins and new workspaces\n2. **MUI v5** (`@mui\u002Fmaterial`) — when BUI lacks the component you need\n3. **MUI v4** (`@material-ui\u002Fcore`) — legacy maintenance only\n\nWhen using MUI v5 alongside BUI, add the class name generator to prevent\ncollisions in dynamic plugin bundles:\n\n```typescript\n\u002F\u002F src\u002Findex.ts\nimport { unstable_ClassNameGenerator as ClassNameGenerator } from '@mui\u002Fmaterial\u002FclassName';\nClassNameGenerator.configure(name => name.startsWith('v5-') ? name : `v5-${name}`);\n```\n\n**Icons:** Use `@remixicon\u002Freact` (not `@material-ui\u002Ficons`).\n\nRead `references\u002Fbui.md` for the component mapping table and CSS variable reference.\n\n## Frontend Implementation\n\n### Verify BUI component APIs before use\n\nThe `references\u002Fbui.md` mapping table is a quick-start guide, not the source\nof truth. Before using any BUI component for the first time, check the actual\ntype definitions in `node_modules\u002F@backstage\u002Fui\u002Fdist\u002Findex.d.ts`. Patterns\nthat differ from what you might expect:\n\n- `Card` uses a discriminated union (href\u002FonPress\u002Fstatic) — no `onClick`\n- `Select` multi-mode uses `value`\u002F`onChange`, not `selectedKeys`\u002F`onSelectionChange`\n- `Table` requires `isRowHeader: true` on at least one column config\n- `Badge` has no `variant` prop\n\n### Follow existing repo conventions\n\nBefore creating any configuration, fixture path, or utility pattern, check\n2–3 other workspaces in the repo for the established convention. Discoveries\nthat save debugging time:\n\n- Catalog `type: file` paths resolve from `packages\u002Fbackend\u002F` CWD — use\n  `..\u002F..\u002F` to reach workspace root files\n- Frontend plugin `.eslintrc.js` may need `root: true` to avoid monorepo\n  plugin conflicts — check sibling packages before changing\n- `import React from 'react'` is blocked — use named imports\n\n### Use CLI tools when specs say to\n\nIf the task spec says \"scaffold via backstage-cli\" or \"run create-app\", use\nthose tools. Do not silently substitute manual file creation. If the CLI fails,\nreport the error and ask for guidance.\n\n### Keep hooks simple\n\nData-fetching hooks should fetch once and apply filters via `useMemo`. Do not\nsplit server-side and client-side filter concerns unless the spec explicitly\nidentifies a dataset size that requires server-side pagination. Do not suppress\n`react-hooks\u002Fexhaustive-deps` as a first approach — if you need a suppression,\nthe hook design is probably too complex.\n\n### Build incrementally, not in bulk\n\nDo not write all components in one pass and then run CI. Write one component\nor hook, run `yarn tsc:full` to verify types, and if it's visual, start the\ndev server and verify it renders correctly. Fix issues before moving to the\nnext component.\n\n### Verify visual output\n\nAfter writing visual components, verify they render correctly before\npresenting to the human. Start the dev server, navigate to the page, and\ncompare against design screenshots if provided. Do not rely solely on\ntsc + test passing — compiled code that looks wrong is still wrong.\n\n### Self-review before presenting\n\nBefore telling the human the work is done, review your own changes as if\nreviewing someone else's PR. Check for: duplicated utility functions across\nfiles, dead or stub code, hardcoded strings that should use translations,\nunnecessary complexity the spec did not ask for. Verify the public API\nsurface (what hooks return, what props components accept) matches what\nconsumers actually need.\n\n### PR workflow awareness\n\nBefore writing code, know what branch you are on and whether it matches the\ntarget PR. If there is existing uncommitted work, protect it before starting\nnew changes. When stashing, always use `--include-untracked` to capture new\nfiles. When committing a subset of changes, use `git add \u003Cspecific files>`.\n\n### Automated review bot suggestions\n\nDo not blindly apply automated review bot suggestions. Before making any\nchange a bot suggests: understand why the current code is the way it is,\ntest the suggested change locally, and if it breaks something, dismiss the\nsuggestion with an explanation.\n\n## Frontend System: NFS for New Plugins\n\nNew plugins targeting RHDH 1.5+ should use the **new frontend system (NFS)**\nwith Blueprints (`createFrontendPlugin`, `PageBlueprint`, `EntityCardBlueprint`,\netc.).\n\nLegacy system (`createPlugin` + `createRoutableExtension`) is for existing\nplugins not yet migrated. For migration, use the `nfs-migration` sibling skill.\n\nRead `references\u002Fnfs.md` for Blueprint patterns, alpha export structure, and\ncompatWrapper decisions.\n\n## Plugin Types\n\nNot sure whether to build a page, a card, an entity tab, or a backend module?\nRead `references\u002Fplugin-types.md` for the decision guide.\n\n## Backend: New System Only\n\nAll backend code MUST use:\n- `createBackendPlugin` — new standalone backend capabilities\n- `createBackendModule` — extensions to existing plugins (catalog, scaffolder, auth)\n\nFrom `@backstage\u002Fbackend-plugin-api`. Never the legacy backend system.\n\nCore services: `httpRouter`, `logger`, `rootConfig`, `httpAuth`, `database`,\n`scheduler`, `permissions`, `discovery`.\n\n**Default export is required** from the entry point (`src\u002Findex.ts`). Missing\ndefault export is the #1 cause of \"plugin not loading\" in RHDH.\n\n## RHDH Dynamic Plugins\n\nKey gotchas (read `references\u002Frhdh.md` for full details):\n\n- **Default export required** from `src\u002Findex.ts` — missing this is the #1 cause of \"plugin not loading\"\n- **Scalprum name** must match the key in `dynamic-plugins.yaml` wiring (derived from package name)\n- **MUI v5 class name generator** required when using `@mui\u002Fmaterial` in dynamic bundles\n- **Auth:** use `fetchApi` — it includes auth headers automatically. Don't implement custom auth.\n- **RHDH-only Blueprints:** `AppDrawerContentBlueprint`, `GlobalHeaderMenuItemBlueprint` — not upstream\n\n`references\u002Frhdh.md` covers all RHDH-specific patterns including backend modules,\nextension points, theming, i18n, and the common package pattern.\n\n## Analytics\n\nBUI components (`Link`, `ButtonLink`, `Tab`, `MenuItem`, `Tag`, `Table` rows)\nhave built-in click analytics via the Backstage Analytics API. Don't add manual\n`captureEvent('click', ...)` for these — it produces duplicates. Use `noTrack`\nprop to suppress the built-in event only when replacing it with a domain-specific\nverb (e.g., `deploy`, `approve`). For detailed instrumentation guidance, install\nthe official `plugin-analytics-instrumentation` skill from backstage.io.\n\n## Testing\n\nBackstage has its own test infrastructure that differs from standard React testing.\nRead `references\u002Ftesting.md` for: TestApiProvider setup, renderInTestApp,\nentity context mocking, async component testing, accessibility testing, and\ncommon gotchas.\n\n## Before You Commit\n\nRun these commands **in order** from the workspace root (e.g., `workspaces\u002Fboost\u002F`).\nStop on first failure — fix it before continuing. This sequence catches every CI\ngate locally.\n\n```bash\nyarn prettier:fix          # format code\nyarn tsc:full              # full TypeScript type check\nyarn build:all             # build all packages in the workspace\nyarn test --watchAll=false  # run tests (disable watch mode)\nyarn build:api-reports:only # generate\u002Fupdate API report files\n```\n\n### API reports\n\n`build:api-reports:only` generates `report.api.md` files for packages with\npublic exports. These files **must be committed** — CI checks them. All public\nexports need `\u002F** @public *\u002F` JSDoc with a description (not just the bare tag).\n\n### Changesets\n\nChangesets are required for published package changes. Rules:\n- Only cover plugins under `plugins\u002F` — **never `packages\u002F*`** (those are\n  private app\u002Fbackend packages that are never published)\n- Only include a plugin if it has changes in `src\u002F` or other published paths\n  (root `index.ts`, `config.d.ts`, `package.json`)\n- Changes only in `dev\u002F`, `tests\u002F`, `__fixtures__\u002F`, or stories do NOT need\n  a changeset for that plugin\n- Write the changeset file directly to `\u003Cworkspace>\u002F.changeset\u002F\u003Cid>.md` —\n  don't run `yarn changeset` interactively\n\n### Commits\n\nAll commits must be signed off (`git commit -s`) per DCO requirements.\n\n## Reference Index\n\n| Reference | Load when... |\n|-----------|-------------|\n| `references\u002Ffrontend-specs.md` | Writing specs, PRDs, or OpenSpec proposals for frontend features |\n| `references\u002Fbui.md` | Using BUI components — mapping table, CSS variables, icons |\n| `references\u002Fplugin-types.md` | Deciding what type of plugin or extension to build |\n| `references\u002Fnfs.md` | Writing NFS code — Blueprints, package exports, compatWrapper |\n| `references\u002Fdev-app.md` | Plugin dev mode, full Backstage app setup, sidebar, app-config |\n| `references\u002Ftesting.md` | Writing tests — TestApiProvider, entity mocking, a11y |\n| `references\u002Frhdh.md` | RHDH-specific patterns — dynamic plugins, backend modules, i18n |\n| `references\u002Fecosystem-skills.md` | Complementary open-source and official Backstage.io skills |\n\n## Sibling Skills (rhdh-skill)\n\n| Skill | Use when... |\n|-------|------------|\n| `create-plugin` | Scaffolding a new plugin from scratch |\n| `nfs-migration` | Migrating an existing plugin from legacy to NFS |\n| `overlay` | Managing overlay packaging for the Extensions Catalog |\n| `backstage-upgrade` | Upgrading Backstage dependency versions |\n| `rhdh-local` | Running and testing plugins locally |\n| `rhdh` | RHDH version matrix, repo navigation, ecosystem context |\n\n## Ecosystem & Official Backstage Skills\n\nRead `references\u002Fecosystem-skills.md` for complementary open-source skills\n(frontend quality from skills.sh) and official Backstage.io skills (migration\nand instrumentation workflows).\n",{"data":38,"body":39},{"name":4,"description":6},{"type":40,"children":41},"root",[42,50,56,63,70,108,114,119,175,180,186,257,262,268,289,295,321,329,385,390,586,612,625,631,637,657,756,762,767,831,837,842,848,869,875,888,894,899,905,910,916,936,942,947,953,987,1016,1028,1034,1047,1053,1058,1083,1096,1157,1175,1181,1194,1292,1302,1308,1394,1400,1413,1419,1439,1539,1545,1579,1585,1590,1701,1707,1720,1726,1884,1890,2013,2019,2030],{"type":43,"tag":44,"props":45,"children":46},"element","h1",{"id":4},[47],{"type":48,"value":49},"text","RHDH Coding",{"type":43,"tag":51,"props":52,"children":53},"p",{},[54],{"type":48,"value":55},"Patterns for Backstage and RHDH plugin development that agents need but can't\nreliably get from training data or codebase discovery alone. This covers what\nyou'd learn after six months of getting burned by non-obvious conventions.",{"type":43,"tag":57,"props":58,"children":60},"h2",{"id":59},"before-you-write-code",[61],{"type":48,"value":62},"Before You Write Code",{"type":43,"tag":64,"props":65,"children":67},"h3",{"id":66},"_1-check-for-existing-specs",[68],{"type":48,"value":69},"1. Check for existing specs",{"type":43,"tag":51,"props":71,"children":72},{},[73,75,82,84,90,92,98,100,106],{"type":48,"value":74},"Look for a spec, PRD, or OpenSpec design for this work — in ",{"type":43,"tag":76,"props":77,"children":79},"code",{"className":78},[],[80],{"type":48,"value":81},"docs\u002Fplans\u002F**\u002F",{"type":48,"value":83},",\n",{"type":43,"tag":76,"props":85,"children":87},{"className":86},[],[88],{"type":48,"value":89},"specifications\u002F",{"type":48,"value":91},", ",{"type":43,"tag":76,"props":93,"children":95},{"className":94},[],[96],{"type":48,"value":97},"openspec\u002Fchanges\u002F*\u002F",{"type":48,"value":99},", or linked from the issue. If found,\nuse the component list and acceptance criteria as your implementation blueprint.\nRead ",{"type":43,"tag":76,"props":101,"children":103},{"className":102},[],[104],{"type":48,"value":105},"references\u002Ffrontend-specs.md",{"type":48,"value":107}," for what good frontend specs include.",{"type":43,"tag":64,"props":109,"children":111},{"id":110},"_2-discover-the-plugin-context",[112],{"type":48,"value":113},"2. Discover the plugin context",{"type":43,"tag":51,"props":115,"children":116},{},[117],{"type":48,"value":118},"Run the detection script to understand what you're working with:",{"type":43,"tag":120,"props":121,"children":126},"pre",{"className":122,"code":123,"language":124,"meta":125,"style":125},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","python scripts\u002Fdetect-rhdh-context.py --path \u003Cplugin-dir>\n","bash","",[127],{"type":43,"tag":76,"props":128,"children":129},{"__ignoreMap":125},[130],{"type":43,"tag":131,"props":132,"children":135},"span",{"class":133,"line":134},"line",1,[136,142,148,153,159,164,170],{"type":43,"tag":131,"props":137,"children":139},{"style":138},"--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B",[140],{"type":48,"value":141},"python",{"type":43,"tag":131,"props":143,"children":145},{"style":144},"--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D",[146],{"type":48,"value":147}," scripts\u002Fdetect-rhdh-context.py",{"type":43,"tag":131,"props":149,"children":150},{"style":144},[151],{"type":48,"value":152}," --path",{"type":43,"tag":131,"props":154,"children":156},{"style":155},"--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF",[157],{"type":48,"value":158}," \u003C",{"type":43,"tag":131,"props":160,"children":161},{"style":144},[162],{"type":48,"value":163},"plugin-di",{"type":43,"tag":131,"props":165,"children":167},{"style":166},"--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8",[168],{"type":48,"value":169},"r",{"type":43,"tag":131,"props":171,"children":172},{"style":155},[173],{"type":48,"value":174},">\n",{"type":43,"tag":51,"props":176,"children":177},{},[178],{"type":48,"value":179},"This reports: Backstage role, frontend system (legacy\u002FNFS\u002Fdual), existing\nextensions, MUI version, dynamic plugin status, plugin ID, scalprum name.",{"type":43,"tag":64,"props":181,"children":183},{"id":182},"_3-read-workspace-instructions",[184],{"type":48,"value":185},"3. Read workspace instructions",{"type":43,"tag":120,"props":187,"children":189},{"className":122,"code":188,"language":124,"meta":125,"style":125},"test -f AGENTS.md && cat AGENTS.md\ntest -f CLAUDE.md && cat CLAUDE.md\n",[190],{"type":43,"tag":76,"props":191,"children":192},{"__ignoreMap":125},[193,227],{"type":43,"tag":131,"props":194,"children":195},{"class":133,"line":134},[196,202,207,212,217,222],{"type":43,"tag":131,"props":197,"children":199},{"style":198},"--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF",[200],{"type":48,"value":201},"test",{"type":43,"tag":131,"props":203,"children":204},{"style":144},[205],{"type":48,"value":206}," -f",{"type":43,"tag":131,"props":208,"children":209},{"style":144},[210],{"type":48,"value":211}," AGENTS.md",{"type":43,"tag":131,"props":213,"children":214},{"style":155},[215],{"type":48,"value":216}," &&",{"type":43,"tag":131,"props":218,"children":219},{"style":138},[220],{"type":48,"value":221}," cat",{"type":43,"tag":131,"props":223,"children":224},{"style":144},[225],{"type":48,"value":226}," AGENTS.md\n",{"type":43,"tag":131,"props":228,"children":230},{"class":133,"line":229},2,[231,235,239,244,248,252],{"type":43,"tag":131,"props":232,"children":233},{"style":198},[234],{"type":48,"value":201},{"type":43,"tag":131,"props":236,"children":237},{"style":144},[238],{"type":48,"value":206},{"type":43,"tag":131,"props":240,"children":241},{"style":144},[242],{"type":48,"value":243}," CLAUDE.md",{"type":43,"tag":131,"props":245,"children":246},{"style":155},[247],{"type":48,"value":216},{"type":43,"tag":131,"props":249,"children":250},{"style":138},[251],{"type":48,"value":221},{"type":43,"tag":131,"props":253,"children":254},{"style":144},[255],{"type":48,"value":256}," CLAUDE.md\n",{"type":43,"tag":51,"props":258,"children":259},{},[260],{"type":48,"value":261},"These contain repo-specific rules that override general patterns.",{"type":43,"tag":64,"props":263,"children":265},{"id":264},"_4-check-version-compatibility",[266],{"type":48,"value":267},"4. Check version compatibility",{"type":43,"tag":51,"props":269,"children":270},{},[271,273,279,281,287],{"type":48,"value":272},"Consult ",{"type":43,"tag":76,"props":274,"children":276},{"className":275},[],[277],{"type":48,"value":278},"..\u002Frhdh\u002Freferences\u002Fversions.md",{"type":48,"value":280}," for the RHDH → Backstage version\nmatrix. Your ",{"type":43,"tag":76,"props":282,"children":284},{"className":283},[],[285],{"type":48,"value":286},"@backstage\u002F*",{"type":48,"value":288}," dependency versions must match the target RHDH\nversion. Mismatched versions cause runtime errors — most commonly \"Cannot\nread properties of undefined.\"",{"type":43,"tag":57,"props":290,"children":292},{"id":291},"styling-bui-first",[293],{"type":48,"value":294},"Styling: BUI First",{"type":43,"tag":51,"props":296,"children":297},{},[298,304,306,312,314,319],{"type":43,"tag":299,"props":300,"children":301},"strong",{},[302],{"type":48,"value":303},"For new plugins,",{"type":48,"value":305}," use Backstage UI (",{"type":43,"tag":76,"props":307,"children":309},{"className":308},[],[310],{"type":48,"value":311},"@backstage\u002Fui",{"type":48,"value":313},") with CSS Modules and\nBUI CSS variables. ",{"type":43,"tag":299,"props":315,"children":316},{},[317],{"type":48,"value":318},"In existing plugins,",{"type":48,"value":320}," match whatever the workspace already\nuses — if it's MUI v4, stay consistent rather than mixing libraries. Only\nintroduce BUI in a workspace that has already adopted it or is actively migrating.",{"type":43,"tag":51,"props":322,"children":323},{},[324],{"type":43,"tag":299,"props":325,"children":326},{},[327],{"type":48,"value":328},"Priority for new plugins:",{"type":43,"tag":330,"props":331,"children":332},"ol",{},[333,351,368],{"type":43,"tag":334,"props":335,"children":336},"li",{},[337,342,344,349],{"type":43,"tag":299,"props":338,"children":339},{},[340],{"type":48,"value":341},"BUI",{"type":48,"value":343}," (",{"type":43,"tag":76,"props":345,"children":347},{"className":346},[],[348],{"type":48,"value":311},{"type":48,"value":350},") — default for new plugins and new workspaces",{"type":43,"tag":334,"props":352,"children":353},{},[354,359,360,366],{"type":43,"tag":299,"props":355,"children":356},{},[357],{"type":48,"value":358},"MUI v5",{"type":48,"value":343},{"type":43,"tag":76,"props":361,"children":363},{"className":362},[],[364],{"type":48,"value":365},"@mui\u002Fmaterial",{"type":48,"value":367},") — when BUI lacks the component you need",{"type":43,"tag":334,"props":369,"children":370},{},[371,376,377,383],{"type":43,"tag":299,"props":372,"children":373},{},[374],{"type":48,"value":375},"MUI v4",{"type":48,"value":343},{"type":43,"tag":76,"props":378,"children":380},{"className":379},[],[381],{"type":48,"value":382},"@material-ui\u002Fcore",{"type":48,"value":384},") — legacy maintenance only",{"type":43,"tag":51,"props":386,"children":387},{},[388],{"type":48,"value":389},"When using MUI v5 alongside BUI, add the class name generator to prevent\ncollisions in dynamic plugin bundles:",{"type":43,"tag":120,"props":391,"children":395},{"className":392,"code":393,"language":394,"meta":125,"style":125},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F src\u002Findex.ts\nimport { unstable_ClassNameGenerator as ClassNameGenerator } from '@mui\u002Fmaterial\u002FclassName';\nClassNameGenerator.configure(name => name.startsWith('v5-') ? name : `v5-${name}`);\n","typescript",[396],{"type":43,"tag":76,"props":397,"children":398},{"__ignoreMap":125},[399,408,467],{"type":43,"tag":131,"props":400,"children":401},{"class":133,"line":134},[402],{"type":43,"tag":131,"props":403,"children":405},{"style":404},"--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic",[406],{"type":48,"value":407},"\u002F\u002F src\u002Findex.ts\n",{"type":43,"tag":131,"props":409,"children":410},{"class":133,"line":229},[411,417,422,427,432,437,442,447,452,457,462],{"type":43,"tag":131,"props":412,"children":414},{"style":413},"--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic",[415],{"type":48,"value":416},"import",{"type":43,"tag":131,"props":418,"children":419},{"style":155},[420],{"type":48,"value":421}," {",{"type":43,"tag":131,"props":423,"children":424},{"style":166},[425],{"type":48,"value":426}," unstable_ClassNameGenerator",{"type":43,"tag":131,"props":428,"children":429},{"style":413},[430],{"type":48,"value":431}," as",{"type":43,"tag":131,"props":433,"children":434},{"style":166},[435],{"type":48,"value":436}," ClassNameGenerator",{"type":43,"tag":131,"props":438,"children":439},{"style":155},[440],{"type":48,"value":441}," }",{"type":43,"tag":131,"props":443,"children":444},{"style":413},[445],{"type":48,"value":446}," from",{"type":43,"tag":131,"props":448,"children":449},{"style":155},[450],{"type":48,"value":451}," '",{"type":43,"tag":131,"props":453,"children":454},{"style":144},[455],{"type":48,"value":456},"@mui\u002Fmaterial\u002FclassName",{"type":43,"tag":131,"props":458,"children":459},{"style":155},[460],{"type":48,"value":461},"'",{"type":43,"tag":131,"props":463,"children":464},{"style":155},[465],{"type":48,"value":466},";\n",{"type":43,"tag":131,"props":468,"children":470},{"class":133,"line":469},3,[471,476,481,486,491,497,503,508,512,517,521,525,530,534,539,544,549,554,559,563,568,572,577,582],{"type":43,"tag":131,"props":472,"children":473},{"style":166},[474],{"type":48,"value":475},"ClassNameGenerator",{"type":43,"tag":131,"props":477,"children":478},{"style":155},[479],{"type":48,"value":480},".",{"type":43,"tag":131,"props":482,"children":483},{"style":198},[484],{"type":48,"value":485},"configure",{"type":43,"tag":131,"props":487,"children":488},{"style":166},[489],{"type":48,"value":490},"(",{"type":43,"tag":131,"props":492,"children":494},{"style":493},"--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic",[495],{"type":48,"value":496},"name",{"type":43,"tag":131,"props":498,"children":500},{"style":499},"--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA",[501],{"type":48,"value":502}," =>",{"type":43,"tag":131,"props":504,"children":505},{"style":166},[506],{"type":48,"value":507}," name",{"type":43,"tag":131,"props":509,"children":510},{"style":155},[511],{"type":48,"value":480},{"type":43,"tag":131,"props":513,"children":514},{"style":198},[515],{"type":48,"value":516},"startsWith",{"type":43,"tag":131,"props":518,"children":519},{"style":166},[520],{"type":48,"value":490},{"type":43,"tag":131,"props":522,"children":523},{"style":155},[524],{"type":48,"value":461},{"type":43,"tag":131,"props":526,"children":527},{"style":144},[528],{"type":48,"value":529},"v5-",{"type":43,"tag":131,"props":531,"children":532},{"style":155},[533],{"type":48,"value":461},{"type":43,"tag":131,"props":535,"children":536},{"style":166},[537],{"type":48,"value":538},") ",{"type":43,"tag":131,"props":540,"children":541},{"style":155},[542],{"type":48,"value":543},"?",{"type":43,"tag":131,"props":545,"children":546},{"style":166},[547],{"type":48,"value":548}," name ",{"type":43,"tag":131,"props":550,"children":551},{"style":155},[552],{"type":48,"value":553},":",{"type":43,"tag":131,"props":555,"children":556},{"style":155},[557],{"type":48,"value":558}," `",{"type":43,"tag":131,"props":560,"children":561},{"style":144},[562],{"type":48,"value":529},{"type":43,"tag":131,"props":564,"children":565},{"style":155},[566],{"type":48,"value":567},"${",{"type":43,"tag":131,"props":569,"children":570},{"style":166},[571],{"type":48,"value":496},{"type":43,"tag":131,"props":573,"children":574},{"style":155},[575],{"type":48,"value":576},"}`",{"type":43,"tag":131,"props":578,"children":579},{"style":166},[580],{"type":48,"value":581},")",{"type":43,"tag":131,"props":583,"children":584},{"style":155},[585],{"type":48,"value":466},{"type":43,"tag":51,"props":587,"children":588},{},[589,594,596,602,604,610],{"type":43,"tag":299,"props":590,"children":591},{},[592],{"type":48,"value":593},"Icons:",{"type":48,"value":595}," Use ",{"type":43,"tag":76,"props":597,"children":599},{"className":598},[],[600],{"type":48,"value":601},"@remixicon\u002Freact",{"type":48,"value":603}," (not ",{"type":43,"tag":76,"props":605,"children":607},{"className":606},[],[608],{"type":48,"value":609},"@material-ui\u002Ficons",{"type":48,"value":611},").",{"type":43,"tag":51,"props":613,"children":614},{},[615,617,623],{"type":48,"value":616},"Read ",{"type":43,"tag":76,"props":618,"children":620},{"className":619},[],[621],{"type":48,"value":622},"references\u002Fbui.md",{"type":48,"value":624}," for the component mapping table and CSS variable reference.",{"type":43,"tag":57,"props":626,"children":628},{"id":627},"frontend-implementation",[629],{"type":48,"value":630},"Frontend Implementation",{"type":43,"tag":64,"props":632,"children":634},{"id":633},"verify-bui-component-apis-before-use",[635],{"type":48,"value":636},"Verify BUI component APIs before use",{"type":43,"tag":51,"props":638,"children":639},{},[640,642,647,649,655],{"type":48,"value":641},"The ",{"type":43,"tag":76,"props":643,"children":645},{"className":644},[],[646],{"type":48,"value":622},{"type":48,"value":648}," mapping table is a quick-start guide, not the source\nof truth. Before using any BUI component for the first time, check the actual\ntype definitions in ",{"type":43,"tag":76,"props":650,"children":652},{"className":651},[],[653],{"type":48,"value":654},"node_modules\u002F@backstage\u002Fui\u002Fdist\u002Findex.d.ts",{"type":48,"value":656},". Patterns\nthat differ from what you might expect:",{"type":43,"tag":658,"props":659,"children":660},"ul",{},[661,678,718,737],{"type":43,"tag":334,"props":662,"children":663},{},[664,670,672],{"type":43,"tag":76,"props":665,"children":667},{"className":666},[],[668],{"type":48,"value":669},"Card",{"type":48,"value":671}," uses a discriminated union (href\u002FonPress\u002Fstatic) — no ",{"type":43,"tag":76,"props":673,"children":675},{"className":674},[],[676],{"type":48,"value":677},"onClick",{"type":43,"tag":334,"props":679,"children":680},{},[681,687,689,695,697,703,705,711,712],{"type":43,"tag":76,"props":682,"children":684},{"className":683},[],[685],{"type":48,"value":686},"Select",{"type":48,"value":688}," multi-mode uses ",{"type":43,"tag":76,"props":690,"children":692},{"className":691},[],[693],{"type":48,"value":694},"value",{"type":48,"value":696},"\u002F",{"type":43,"tag":76,"props":698,"children":700},{"className":699},[],[701],{"type":48,"value":702},"onChange",{"type":48,"value":704},", not ",{"type":43,"tag":76,"props":706,"children":708},{"className":707},[],[709],{"type":48,"value":710},"selectedKeys",{"type":48,"value":696},{"type":43,"tag":76,"props":713,"children":715},{"className":714},[],[716],{"type":48,"value":717},"onSelectionChange",{"type":43,"tag":334,"props":719,"children":720},{},[721,727,729,735],{"type":43,"tag":76,"props":722,"children":724},{"className":723},[],[725],{"type":48,"value":726},"Table",{"type":48,"value":728}," requires ",{"type":43,"tag":76,"props":730,"children":732},{"className":731},[],[733],{"type":48,"value":734},"isRowHeader: true",{"type":48,"value":736}," on at least one column config",{"type":43,"tag":334,"props":738,"children":739},{},[740,746,748,754],{"type":43,"tag":76,"props":741,"children":743},{"className":742},[],[744],{"type":48,"value":745},"Badge",{"type":48,"value":747}," has no ",{"type":43,"tag":76,"props":749,"children":751},{"className":750},[],[752],{"type":48,"value":753},"variant",{"type":48,"value":755}," prop",{"type":43,"tag":64,"props":757,"children":759},{"id":758},"follow-existing-repo-conventions",[760],{"type":48,"value":761},"Follow existing repo conventions",{"type":43,"tag":51,"props":763,"children":764},{},[765],{"type":48,"value":766},"Before creating any configuration, fixture path, or utility pattern, check\n2–3 other workspaces in the repo for the established convention. Discoveries\nthat save debugging time:",{"type":43,"tag":658,"props":768,"children":769},{},[770,799,820],{"type":43,"tag":334,"props":771,"children":772},{},[773,775,781,783,789,791,797],{"type":48,"value":774},"Catalog ",{"type":43,"tag":76,"props":776,"children":778},{"className":777},[],[779],{"type":48,"value":780},"type: file",{"type":48,"value":782}," paths resolve from ",{"type":43,"tag":76,"props":784,"children":786},{"className":785},[],[787],{"type":48,"value":788},"packages\u002Fbackend\u002F",{"type":48,"value":790}," CWD — use\n",{"type":43,"tag":76,"props":792,"children":794},{"className":793},[],[795],{"type":48,"value":796},"..\u002F..\u002F",{"type":48,"value":798}," to reach workspace root files",{"type":43,"tag":334,"props":800,"children":801},{},[802,804,810,812,818],{"type":48,"value":803},"Frontend plugin ",{"type":43,"tag":76,"props":805,"children":807},{"className":806},[],[808],{"type":48,"value":809},".eslintrc.js",{"type":48,"value":811}," may need ",{"type":43,"tag":76,"props":813,"children":815},{"className":814},[],[816],{"type":48,"value":817},"root: true",{"type":48,"value":819}," to avoid monorepo\nplugin conflicts — check sibling packages before changing",{"type":43,"tag":334,"props":821,"children":822},{},[823,829],{"type":43,"tag":76,"props":824,"children":826},{"className":825},[],[827],{"type":48,"value":828},"import React from 'react'",{"type":48,"value":830}," is blocked — use named imports",{"type":43,"tag":64,"props":832,"children":834},{"id":833},"use-cli-tools-when-specs-say-to",[835],{"type":48,"value":836},"Use CLI tools when specs say to",{"type":43,"tag":51,"props":838,"children":839},{},[840],{"type":48,"value":841},"If the task spec says \"scaffold via backstage-cli\" or \"run create-app\", use\nthose tools. Do not silently substitute manual file creation. If the CLI fails,\nreport the error and ask for guidance.",{"type":43,"tag":64,"props":843,"children":845},{"id":844},"keep-hooks-simple",[846],{"type":48,"value":847},"Keep hooks simple",{"type":43,"tag":51,"props":849,"children":850},{},[851,853,859,861,867],{"type":48,"value":852},"Data-fetching hooks should fetch once and apply filters via ",{"type":43,"tag":76,"props":854,"children":856},{"className":855},[],[857],{"type":48,"value":858},"useMemo",{"type":48,"value":860},". Do not\nsplit server-side and client-side filter concerns unless the spec explicitly\nidentifies a dataset size that requires server-side pagination. Do not suppress\n",{"type":43,"tag":76,"props":862,"children":864},{"className":863},[],[865],{"type":48,"value":866},"react-hooks\u002Fexhaustive-deps",{"type":48,"value":868}," as a first approach — if you need a suppression,\nthe hook design is probably too complex.",{"type":43,"tag":64,"props":870,"children":872},{"id":871},"build-incrementally-not-in-bulk",[873],{"type":48,"value":874},"Build incrementally, not in bulk",{"type":43,"tag":51,"props":876,"children":877},{},[878,880,886],{"type":48,"value":879},"Do not write all components in one pass and then run CI. Write one component\nor hook, run ",{"type":43,"tag":76,"props":881,"children":883},{"className":882},[],[884],{"type":48,"value":885},"yarn tsc:full",{"type":48,"value":887}," to verify types, and if it's visual, start the\ndev server and verify it renders correctly. Fix issues before moving to the\nnext component.",{"type":43,"tag":64,"props":889,"children":891},{"id":890},"verify-visual-output",[892],{"type":48,"value":893},"Verify visual output",{"type":43,"tag":51,"props":895,"children":896},{},[897],{"type":48,"value":898},"After writing visual components, verify they render correctly before\npresenting to the human. Start the dev server, navigate to the page, and\ncompare against design screenshots if provided. Do not rely solely on\ntsc + test passing — compiled code that looks wrong is still wrong.",{"type":43,"tag":64,"props":900,"children":902},{"id":901},"self-review-before-presenting",[903],{"type":48,"value":904},"Self-review before presenting",{"type":43,"tag":51,"props":906,"children":907},{},[908],{"type":48,"value":909},"Before telling the human the work is done, review your own changes as if\nreviewing someone else's PR. Check for: duplicated utility functions across\nfiles, dead or stub code, hardcoded strings that should use translations,\nunnecessary complexity the spec did not ask for. Verify the public API\nsurface (what hooks return, what props components accept) matches what\nconsumers actually need.",{"type":43,"tag":64,"props":911,"children":913},{"id":912},"pr-workflow-awareness",[914],{"type":48,"value":915},"PR workflow awareness",{"type":43,"tag":51,"props":917,"children":918},{},[919,921,927,929,935],{"type":48,"value":920},"Before writing code, know what branch you are on and whether it matches the\ntarget PR. If there is existing uncommitted work, protect it before starting\nnew changes. When stashing, always use ",{"type":43,"tag":76,"props":922,"children":924},{"className":923},[],[925],{"type":48,"value":926},"--include-untracked",{"type":48,"value":928}," to capture new\nfiles. When committing a subset of changes, use ",{"type":43,"tag":76,"props":930,"children":932},{"className":931},[],[933],{"type":48,"value":934},"git add \u003Cspecific files>",{"type":48,"value":480},{"type":43,"tag":64,"props":937,"children":939},{"id":938},"automated-review-bot-suggestions",[940],{"type":48,"value":941},"Automated review bot suggestions",{"type":43,"tag":51,"props":943,"children":944},{},[945],{"type":48,"value":946},"Do not blindly apply automated review bot suggestions. Before making any\nchange a bot suggests: understand why the current code is the way it is,\ntest the suggested change locally, and if it breaks something, dismiss the\nsuggestion with an explanation.",{"type":43,"tag":57,"props":948,"children":950},{"id":949},"frontend-system-nfs-for-new-plugins",[951],{"type":48,"value":952},"Frontend System: NFS for New Plugins",{"type":43,"tag":51,"props":954,"children":955},{},[956,958,963,965,971,972,978,979,985],{"type":48,"value":957},"New plugins targeting RHDH 1.5+ should use the ",{"type":43,"tag":299,"props":959,"children":960},{},[961],{"type":48,"value":962},"new frontend system (NFS)",{"type":48,"value":964},"\nwith Blueprints (",{"type":43,"tag":76,"props":966,"children":968},{"className":967},[],[969],{"type":48,"value":970},"createFrontendPlugin",{"type":48,"value":91},{"type":43,"tag":76,"props":973,"children":975},{"className":974},[],[976],{"type":48,"value":977},"PageBlueprint",{"type":48,"value":91},{"type":43,"tag":76,"props":980,"children":982},{"className":981},[],[983],{"type":48,"value":984},"EntityCardBlueprint",{"type":48,"value":986},",\netc.).",{"type":43,"tag":51,"props":988,"children":989},{},[990,992,998,1000,1006,1008,1014],{"type":48,"value":991},"Legacy system (",{"type":43,"tag":76,"props":993,"children":995},{"className":994},[],[996],{"type":48,"value":997},"createPlugin",{"type":48,"value":999}," + ",{"type":43,"tag":76,"props":1001,"children":1003},{"className":1002},[],[1004],{"type":48,"value":1005},"createRoutableExtension",{"type":48,"value":1007},") is for existing\nplugins not yet migrated. For migration, use the ",{"type":43,"tag":76,"props":1009,"children":1011},{"className":1010},[],[1012],{"type":48,"value":1013},"nfs-migration",{"type":48,"value":1015}," sibling skill.",{"type":43,"tag":51,"props":1017,"children":1018},{},[1019,1020,1026],{"type":48,"value":616},{"type":43,"tag":76,"props":1021,"children":1023},{"className":1022},[],[1024],{"type":48,"value":1025},"references\u002Fnfs.md",{"type":48,"value":1027}," for Blueprint patterns, alpha export structure, and\ncompatWrapper decisions.",{"type":43,"tag":57,"props":1029,"children":1031},{"id":1030},"plugin-types",[1032],{"type":48,"value":1033},"Plugin Types",{"type":43,"tag":51,"props":1035,"children":1036},{},[1037,1039,1045],{"type":48,"value":1038},"Not sure whether to build a page, a card, an entity tab, or a backend module?\nRead ",{"type":43,"tag":76,"props":1040,"children":1042},{"className":1041},[],[1043],{"type":48,"value":1044},"references\u002Fplugin-types.md",{"type":48,"value":1046}," for the decision guide.",{"type":43,"tag":57,"props":1048,"children":1050},{"id":1049},"backend-new-system-only",[1051],{"type":48,"value":1052},"Backend: New System Only",{"type":43,"tag":51,"props":1054,"children":1055},{},[1056],{"type":48,"value":1057},"All backend code MUST use:",{"type":43,"tag":658,"props":1059,"children":1060},{},[1061,1072],{"type":43,"tag":334,"props":1062,"children":1063},{},[1064,1070],{"type":43,"tag":76,"props":1065,"children":1067},{"className":1066},[],[1068],{"type":48,"value":1069},"createBackendPlugin",{"type":48,"value":1071}," — new standalone backend capabilities",{"type":43,"tag":334,"props":1073,"children":1074},{},[1075,1081],{"type":43,"tag":76,"props":1076,"children":1078},{"className":1077},[],[1079],{"type":48,"value":1080},"createBackendModule",{"type":48,"value":1082}," — extensions to existing plugins (catalog, scaffolder, auth)",{"type":43,"tag":51,"props":1084,"children":1085},{},[1086,1088,1094],{"type":48,"value":1087},"From ",{"type":43,"tag":76,"props":1089,"children":1091},{"className":1090},[],[1092],{"type":48,"value":1093},"@backstage\u002Fbackend-plugin-api",{"type":48,"value":1095},". Never the legacy backend system.",{"type":43,"tag":51,"props":1097,"children":1098},{},[1099,1101,1107,1108,1114,1115,1121,1122,1128,1129,1135,1136,1142,1143,1149,1150,1156],{"type":48,"value":1100},"Core services: ",{"type":43,"tag":76,"props":1102,"children":1104},{"className":1103},[],[1105],{"type":48,"value":1106},"httpRouter",{"type":48,"value":91},{"type":43,"tag":76,"props":1109,"children":1111},{"className":1110},[],[1112],{"type":48,"value":1113},"logger",{"type":48,"value":91},{"type":43,"tag":76,"props":1116,"children":1118},{"className":1117},[],[1119],{"type":48,"value":1120},"rootConfig",{"type":48,"value":91},{"type":43,"tag":76,"props":1123,"children":1125},{"className":1124},[],[1126],{"type":48,"value":1127},"httpAuth",{"type":48,"value":91},{"type":43,"tag":76,"props":1130,"children":1132},{"className":1131},[],[1133],{"type":48,"value":1134},"database",{"type":48,"value":83},{"type":43,"tag":76,"props":1137,"children":1139},{"className":1138},[],[1140],{"type":48,"value":1141},"scheduler",{"type":48,"value":91},{"type":43,"tag":76,"props":1144,"children":1146},{"className":1145},[],[1147],{"type":48,"value":1148},"permissions",{"type":48,"value":91},{"type":43,"tag":76,"props":1151,"children":1153},{"className":1152},[],[1154],{"type":48,"value":1155},"discovery",{"type":48,"value":480},{"type":43,"tag":51,"props":1158,"children":1159},{},[1160,1165,1167,1173],{"type":43,"tag":299,"props":1161,"children":1162},{},[1163],{"type":48,"value":1164},"Default export is required",{"type":48,"value":1166}," from the entry point (",{"type":43,"tag":76,"props":1168,"children":1170},{"className":1169},[],[1171],{"type":48,"value":1172},"src\u002Findex.ts",{"type":48,"value":1174},"). Missing\ndefault export is the #1 cause of \"plugin not loading\" in RHDH.",{"type":43,"tag":57,"props":1176,"children":1178},{"id":1177},"rhdh-dynamic-plugins",[1179],{"type":48,"value":1180},"RHDH Dynamic Plugins",{"type":43,"tag":51,"props":1182,"children":1183},{},[1184,1186,1192],{"type":48,"value":1185},"Key gotchas (read ",{"type":43,"tag":76,"props":1187,"children":1189},{"className":1188},[],[1190],{"type":48,"value":1191},"references\u002Frhdh.md",{"type":48,"value":1193}," for full details):",{"type":43,"tag":658,"props":1195,"children":1196},{},[1197,1214,1232,1249,1267],{"type":43,"tag":334,"props":1198,"children":1199},{},[1200,1205,1207,1212],{"type":43,"tag":299,"props":1201,"children":1202},{},[1203],{"type":48,"value":1204},"Default export required",{"type":48,"value":1206}," from ",{"type":43,"tag":76,"props":1208,"children":1210},{"className":1209},[],[1211],{"type":48,"value":1172},{"type":48,"value":1213}," — missing this is the #1 cause of \"plugin not loading\"",{"type":43,"tag":334,"props":1215,"children":1216},{},[1217,1222,1224,1230],{"type":43,"tag":299,"props":1218,"children":1219},{},[1220],{"type":48,"value":1221},"Scalprum name",{"type":48,"value":1223}," must match the key in ",{"type":43,"tag":76,"props":1225,"children":1227},{"className":1226},[],[1228],{"type":48,"value":1229},"dynamic-plugins.yaml",{"type":48,"value":1231}," wiring (derived from package name)",{"type":43,"tag":334,"props":1233,"children":1234},{},[1235,1240,1242,1247],{"type":43,"tag":299,"props":1236,"children":1237},{},[1238],{"type":48,"value":1239},"MUI v5 class name generator",{"type":48,"value":1241}," required when using ",{"type":43,"tag":76,"props":1243,"children":1245},{"className":1244},[],[1246],{"type":48,"value":365},{"type":48,"value":1248}," in dynamic bundles",{"type":43,"tag":334,"props":1250,"children":1251},{},[1252,1257,1259,1265],{"type":43,"tag":299,"props":1253,"children":1254},{},[1255],{"type":48,"value":1256},"Auth:",{"type":48,"value":1258}," use ",{"type":43,"tag":76,"props":1260,"children":1262},{"className":1261},[],[1263],{"type":48,"value":1264},"fetchApi",{"type":48,"value":1266}," — it includes auth headers automatically. Don't implement custom auth.",{"type":43,"tag":334,"props":1268,"children":1269},{},[1270,1275,1277,1283,1284,1290],{"type":43,"tag":299,"props":1271,"children":1272},{},[1273],{"type":48,"value":1274},"RHDH-only Blueprints:",{"type":48,"value":1276}," ",{"type":43,"tag":76,"props":1278,"children":1280},{"className":1279},[],[1281],{"type":48,"value":1282},"AppDrawerContentBlueprint",{"type":48,"value":91},{"type":43,"tag":76,"props":1285,"children":1287},{"className":1286},[],[1288],{"type":48,"value":1289},"GlobalHeaderMenuItemBlueprint",{"type":48,"value":1291}," — not upstream",{"type":43,"tag":51,"props":1293,"children":1294},{},[1295,1300],{"type":43,"tag":76,"props":1296,"children":1298},{"className":1297},[],[1299],{"type":48,"value":1191},{"type":48,"value":1301}," covers all RHDH-specific patterns including backend modules,\nextension points, theming, i18n, and the common package pattern.",{"type":43,"tag":57,"props":1303,"children":1305},{"id":1304},"analytics",[1306],{"type":48,"value":1307},"Analytics",{"type":43,"tag":51,"props":1309,"children":1310},{},[1311,1313,1319,1320,1326,1327,1333,1334,1340,1341,1347,1348,1353,1355,1361,1363,1369,1371,1377,1378,1384,1386,1392],{"type":48,"value":1312},"BUI components (",{"type":43,"tag":76,"props":1314,"children":1316},{"className":1315},[],[1317],{"type":48,"value":1318},"Link",{"type":48,"value":91},{"type":43,"tag":76,"props":1321,"children":1323},{"className":1322},[],[1324],{"type":48,"value":1325},"ButtonLink",{"type":48,"value":91},{"type":43,"tag":76,"props":1328,"children":1330},{"className":1329},[],[1331],{"type":48,"value":1332},"Tab",{"type":48,"value":91},{"type":43,"tag":76,"props":1335,"children":1337},{"className":1336},[],[1338],{"type":48,"value":1339},"MenuItem",{"type":48,"value":91},{"type":43,"tag":76,"props":1342,"children":1344},{"className":1343},[],[1345],{"type":48,"value":1346},"Tag",{"type":48,"value":91},{"type":43,"tag":76,"props":1349,"children":1351},{"className":1350},[],[1352],{"type":48,"value":726},{"type":48,"value":1354}," rows)\nhave built-in click analytics via the Backstage Analytics API. Don't add manual\n",{"type":43,"tag":76,"props":1356,"children":1358},{"className":1357},[],[1359],{"type":48,"value":1360},"captureEvent('click', ...)",{"type":48,"value":1362}," for these — it produces duplicates. Use ",{"type":43,"tag":76,"props":1364,"children":1366},{"className":1365},[],[1367],{"type":48,"value":1368},"noTrack",{"type":48,"value":1370},"\nprop to suppress the built-in event only when replacing it with a domain-specific\nverb (e.g., ",{"type":43,"tag":76,"props":1372,"children":1374},{"className":1373},[],[1375],{"type":48,"value":1376},"deploy",{"type":48,"value":91},{"type":43,"tag":76,"props":1379,"children":1381},{"className":1380},[],[1382],{"type":48,"value":1383},"approve",{"type":48,"value":1385},"). For detailed instrumentation guidance, install\nthe official ",{"type":43,"tag":76,"props":1387,"children":1389},{"className":1388},[],[1390],{"type":48,"value":1391},"plugin-analytics-instrumentation",{"type":48,"value":1393}," skill from backstage.io.",{"type":43,"tag":57,"props":1395,"children":1397},{"id":1396},"testing",[1398],{"type":48,"value":1399},"Testing",{"type":43,"tag":51,"props":1401,"children":1402},{},[1403,1405,1411],{"type":48,"value":1404},"Backstage has its own test infrastructure that differs from standard React testing.\nRead ",{"type":43,"tag":76,"props":1406,"children":1408},{"className":1407},[],[1409],{"type":48,"value":1410},"references\u002Ftesting.md",{"type":48,"value":1412}," for: TestApiProvider setup, renderInTestApp,\nentity context mocking, async component testing, accessibility testing, and\ncommon gotchas.",{"type":43,"tag":57,"props":1414,"children":1416},{"id":1415},"before-you-commit",[1417],{"type":48,"value":1418},"Before You Commit",{"type":43,"tag":51,"props":1420,"children":1421},{},[1422,1424,1429,1431,1437],{"type":48,"value":1423},"Run these commands ",{"type":43,"tag":299,"props":1425,"children":1426},{},[1427],{"type":48,"value":1428},"in order",{"type":48,"value":1430}," from the workspace root (e.g., ",{"type":43,"tag":76,"props":1432,"children":1434},{"className":1433},[],[1435],{"type":48,"value":1436},"workspaces\u002Fboost\u002F",{"type":48,"value":1438},").\nStop on first failure — fix it before continuing. This sequence catches every CI\ngate locally.",{"type":43,"tag":120,"props":1440,"children":1442},{"className":122,"code":1441,"language":124,"meta":125,"style":125},"yarn prettier:fix          # format code\nyarn tsc:full              # full TypeScript type check\nyarn build:all             # build all packages in the workspace\nyarn test --watchAll=false  # run tests (disable watch mode)\nyarn build:api-reports:only # generate\u002Fupdate API report files\n",[1443],{"type":43,"tag":76,"props":1444,"children":1445},{"__ignoreMap":125},[1446,1464,1481,1498,1521],{"type":43,"tag":131,"props":1447,"children":1448},{"class":133,"line":134},[1449,1454,1459],{"type":43,"tag":131,"props":1450,"children":1451},{"style":138},[1452],{"type":48,"value":1453},"yarn",{"type":43,"tag":131,"props":1455,"children":1456},{"style":144},[1457],{"type":48,"value":1458}," prettier:fix",{"type":43,"tag":131,"props":1460,"children":1461},{"style":404},[1462],{"type":48,"value":1463},"          # format code\n",{"type":43,"tag":131,"props":1465,"children":1466},{"class":133,"line":229},[1467,1471,1476],{"type":43,"tag":131,"props":1468,"children":1469},{"style":138},[1470],{"type":48,"value":1453},{"type":43,"tag":131,"props":1472,"children":1473},{"style":144},[1474],{"type":48,"value":1475}," tsc:full",{"type":43,"tag":131,"props":1477,"children":1478},{"style":404},[1479],{"type":48,"value":1480},"              # full TypeScript type check\n",{"type":43,"tag":131,"props":1482,"children":1483},{"class":133,"line":469},[1484,1488,1493],{"type":43,"tag":131,"props":1485,"children":1486},{"style":138},[1487],{"type":48,"value":1453},{"type":43,"tag":131,"props":1489,"children":1490},{"style":144},[1491],{"type":48,"value":1492}," build:all",{"type":43,"tag":131,"props":1494,"children":1495},{"style":404},[1496],{"type":48,"value":1497},"             # build all packages in the workspace\n",{"type":43,"tag":131,"props":1499,"children":1501},{"class":133,"line":1500},4,[1502,1506,1511,1516],{"type":43,"tag":131,"props":1503,"children":1504},{"style":138},[1505],{"type":48,"value":1453},{"type":43,"tag":131,"props":1507,"children":1508},{"style":144},[1509],{"type":48,"value":1510}," test",{"type":43,"tag":131,"props":1512,"children":1513},{"style":144},[1514],{"type":48,"value":1515}," --watchAll=false",{"type":43,"tag":131,"props":1517,"children":1518},{"style":404},[1519],{"type":48,"value":1520},"  # run tests (disable watch mode)\n",{"type":43,"tag":131,"props":1522,"children":1524},{"class":133,"line":1523},5,[1525,1529,1534],{"type":43,"tag":131,"props":1526,"children":1527},{"style":138},[1528],{"type":48,"value":1453},{"type":43,"tag":131,"props":1530,"children":1531},{"style":144},[1532],{"type":48,"value":1533}," build:api-reports:only",{"type":43,"tag":131,"props":1535,"children":1536},{"style":404},[1537],{"type":48,"value":1538}," # generate\u002Fupdate API report files\n",{"type":43,"tag":64,"props":1540,"children":1542},{"id":1541},"api-reports",[1543],{"type":48,"value":1544},"API reports",{"type":43,"tag":51,"props":1546,"children":1547},{},[1548,1554,1556,1562,1564,1569,1571,1577],{"type":43,"tag":76,"props":1549,"children":1551},{"className":1550},[],[1552],{"type":48,"value":1553},"build:api-reports:only",{"type":48,"value":1555}," generates ",{"type":43,"tag":76,"props":1557,"children":1559},{"className":1558},[],[1560],{"type":48,"value":1561},"report.api.md",{"type":48,"value":1563}," files for packages with\npublic exports. These files ",{"type":43,"tag":299,"props":1565,"children":1566},{},[1567],{"type":48,"value":1568},"must be committed",{"type":48,"value":1570}," — CI checks them. All public\nexports need ",{"type":43,"tag":76,"props":1572,"children":1574},{"className":1573},[],[1575],{"type":48,"value":1576},"\u002F** @public *\u002F",{"type":48,"value":1578}," JSDoc with a description (not just the bare tag).",{"type":43,"tag":64,"props":1580,"children":1582},{"id":1581},"changesets",[1583],{"type":48,"value":1584},"Changesets",{"type":43,"tag":51,"props":1586,"children":1587},{},[1588],{"type":48,"value":1589},"Changesets are required for published package changes. Rules:",{"type":43,"tag":658,"props":1591,"children":1592},{},[1593,1619,1653,1680],{"type":43,"tag":334,"props":1594,"children":1595},{},[1596,1598,1604,1606,1617],{"type":48,"value":1597},"Only cover plugins under ",{"type":43,"tag":76,"props":1599,"children":1601},{"className":1600},[],[1602],{"type":48,"value":1603},"plugins\u002F",{"type":48,"value":1605}," — ",{"type":43,"tag":299,"props":1607,"children":1608},{},[1609,1611],{"type":48,"value":1610},"never ",{"type":43,"tag":76,"props":1612,"children":1614},{"className":1613},[],[1615],{"type":48,"value":1616},"packages\u002F*",{"type":48,"value":1618}," (those are\nprivate app\u002Fbackend packages that are never published)",{"type":43,"tag":334,"props":1620,"children":1621},{},[1622,1624,1630,1632,1638,1639,1645,1646,1652],{"type":48,"value":1623},"Only include a plugin if it has changes in ",{"type":43,"tag":76,"props":1625,"children":1627},{"className":1626},[],[1628],{"type":48,"value":1629},"src\u002F",{"type":48,"value":1631}," or other published paths\n(root ",{"type":43,"tag":76,"props":1633,"children":1635},{"className":1634},[],[1636],{"type":48,"value":1637},"index.ts",{"type":48,"value":91},{"type":43,"tag":76,"props":1640,"children":1642},{"className":1641},[],[1643],{"type":48,"value":1644},"config.d.ts",{"type":48,"value":91},{"type":43,"tag":76,"props":1647,"children":1649},{"className":1648},[],[1650],{"type":48,"value":1651},"package.json",{"type":48,"value":581},{"type":43,"tag":334,"props":1654,"children":1655},{},[1656,1658,1664,1665,1671,1672,1678],{"type":48,"value":1657},"Changes only in ",{"type":43,"tag":76,"props":1659,"children":1661},{"className":1660},[],[1662],{"type":48,"value":1663},"dev\u002F",{"type":48,"value":91},{"type":43,"tag":76,"props":1666,"children":1668},{"className":1667},[],[1669],{"type":48,"value":1670},"tests\u002F",{"type":48,"value":91},{"type":43,"tag":76,"props":1673,"children":1675},{"className":1674},[],[1676],{"type":48,"value":1677},"__fixtures__\u002F",{"type":48,"value":1679},", or stories do NOT need\na changeset for that plugin",{"type":43,"tag":334,"props":1681,"children":1682},{},[1683,1685,1691,1693,1699],{"type":48,"value":1684},"Write the changeset file directly to ",{"type":43,"tag":76,"props":1686,"children":1688},{"className":1687},[],[1689],{"type":48,"value":1690},"\u003Cworkspace>\u002F.changeset\u002F\u003Cid>.md",{"type":48,"value":1692}," —\ndon't run ",{"type":43,"tag":76,"props":1694,"children":1696},{"className":1695},[],[1697],{"type":48,"value":1698},"yarn changeset",{"type":48,"value":1700}," interactively",{"type":43,"tag":64,"props":1702,"children":1704},{"id":1703},"commits",[1705],{"type":48,"value":1706},"Commits",{"type":43,"tag":51,"props":1708,"children":1709},{},[1710,1712,1718],{"type":48,"value":1711},"All commits must be signed off (",{"type":43,"tag":76,"props":1713,"children":1715},{"className":1714},[],[1716],{"type":48,"value":1717},"git commit -s",{"type":48,"value":1719},") per DCO requirements.",{"type":43,"tag":57,"props":1721,"children":1723},{"id":1722},"reference-index",[1724],{"type":48,"value":1725},"Reference Index",{"type":43,"tag":1727,"props":1728,"children":1729},"table",{},[1730,1749],{"type":43,"tag":1731,"props":1732,"children":1733},"thead",{},[1734],{"type":43,"tag":1735,"props":1736,"children":1737},"tr",{},[1738,1744],{"type":43,"tag":1739,"props":1740,"children":1741},"th",{},[1742],{"type":48,"value":1743},"Reference",{"type":43,"tag":1739,"props":1745,"children":1746},{},[1747],{"type":48,"value":1748},"Load when...",{"type":43,"tag":1750,"props":1751,"children":1752},"tbody",{},[1753,1770,1786,1802,1818,1835,1851,1867],{"type":43,"tag":1735,"props":1754,"children":1755},{},[1756,1765],{"type":43,"tag":1757,"props":1758,"children":1759},"td",{},[1760],{"type":43,"tag":76,"props":1761,"children":1763},{"className":1762},[],[1764],{"type":48,"value":105},{"type":43,"tag":1757,"props":1766,"children":1767},{},[1768],{"type":48,"value":1769},"Writing specs, PRDs, or OpenSpec proposals for frontend features",{"type":43,"tag":1735,"props":1771,"children":1772},{},[1773,1781],{"type":43,"tag":1757,"props":1774,"children":1775},{},[1776],{"type":43,"tag":76,"props":1777,"children":1779},{"className":1778},[],[1780],{"type":48,"value":622},{"type":43,"tag":1757,"props":1782,"children":1783},{},[1784],{"type":48,"value":1785},"Using BUI components — mapping table, CSS variables, icons",{"type":43,"tag":1735,"props":1787,"children":1788},{},[1789,1797],{"type":43,"tag":1757,"props":1790,"children":1791},{},[1792],{"type":43,"tag":76,"props":1793,"children":1795},{"className":1794},[],[1796],{"type":48,"value":1044},{"type":43,"tag":1757,"props":1798,"children":1799},{},[1800],{"type":48,"value":1801},"Deciding what type of plugin or extension to build",{"type":43,"tag":1735,"props":1803,"children":1804},{},[1805,1813],{"type":43,"tag":1757,"props":1806,"children":1807},{},[1808],{"type":43,"tag":76,"props":1809,"children":1811},{"className":1810},[],[1812],{"type":48,"value":1025},{"type":43,"tag":1757,"props":1814,"children":1815},{},[1816],{"type":48,"value":1817},"Writing NFS code — Blueprints, package exports, compatWrapper",{"type":43,"tag":1735,"props":1819,"children":1820},{},[1821,1830],{"type":43,"tag":1757,"props":1822,"children":1823},{},[1824],{"type":43,"tag":76,"props":1825,"children":1827},{"className":1826},[],[1828],{"type":48,"value":1829},"references\u002Fdev-app.md",{"type":43,"tag":1757,"props":1831,"children":1832},{},[1833],{"type":48,"value":1834},"Plugin dev mode, full Backstage app setup, sidebar, app-config",{"type":43,"tag":1735,"props":1836,"children":1837},{},[1838,1846],{"type":43,"tag":1757,"props":1839,"children":1840},{},[1841],{"type":43,"tag":76,"props":1842,"children":1844},{"className":1843},[],[1845],{"type":48,"value":1410},{"type":43,"tag":1757,"props":1847,"children":1848},{},[1849],{"type":48,"value":1850},"Writing tests — TestApiProvider, entity mocking, a11y",{"type":43,"tag":1735,"props":1852,"children":1853},{},[1854,1862],{"type":43,"tag":1757,"props":1855,"children":1856},{},[1857],{"type":43,"tag":76,"props":1858,"children":1860},{"className":1859},[],[1861],{"type":48,"value":1191},{"type":43,"tag":1757,"props":1863,"children":1864},{},[1865],{"type":48,"value":1866},"RHDH-specific patterns — dynamic plugins, backend modules, i18n",{"type":43,"tag":1735,"props":1868,"children":1869},{},[1870,1879],{"type":43,"tag":1757,"props":1871,"children":1872},{},[1873],{"type":43,"tag":76,"props":1874,"children":1876},{"className":1875},[],[1877],{"type":48,"value":1878},"references\u002Fecosystem-skills.md",{"type":43,"tag":1757,"props":1880,"children":1881},{},[1882],{"type":48,"value":1883},"Complementary open-source and official Backstage.io skills",{"type":43,"tag":57,"props":1885,"children":1887},{"id":1886},"sibling-skills-rhdh-skill",[1888],{"type":48,"value":1889},"Sibling Skills (rhdh-skill)",{"type":43,"tag":1727,"props":1891,"children":1892},{},[1893,1909],{"type":43,"tag":1731,"props":1894,"children":1895},{},[1896],{"type":43,"tag":1735,"props":1897,"children":1898},{},[1899,1904],{"type":43,"tag":1739,"props":1900,"children":1901},{},[1902],{"type":48,"value":1903},"Skill",{"type":43,"tag":1739,"props":1905,"children":1906},{},[1907],{"type":48,"value":1908},"Use when...",{"type":43,"tag":1750,"props":1910,"children":1911},{},[1912,1929,1945,1962,1979,1996],{"type":43,"tag":1735,"props":1913,"children":1914},{},[1915,1924],{"type":43,"tag":1757,"props":1916,"children":1917},{},[1918],{"type":43,"tag":76,"props":1919,"children":1921},{"className":1920},[],[1922],{"type":48,"value":1923},"create-plugin",{"type":43,"tag":1757,"props":1925,"children":1926},{},[1927],{"type":48,"value":1928},"Scaffolding a new plugin from scratch",{"type":43,"tag":1735,"props":1930,"children":1931},{},[1932,1940],{"type":43,"tag":1757,"props":1933,"children":1934},{},[1935],{"type":43,"tag":76,"props":1936,"children":1938},{"className":1937},[],[1939],{"type":48,"value":1013},{"type":43,"tag":1757,"props":1941,"children":1942},{},[1943],{"type":48,"value":1944},"Migrating an existing plugin from legacy to NFS",{"type":43,"tag":1735,"props":1946,"children":1947},{},[1948,1957],{"type":43,"tag":1757,"props":1949,"children":1950},{},[1951],{"type":43,"tag":76,"props":1952,"children":1954},{"className":1953},[],[1955],{"type":48,"value":1956},"overlay",{"type":43,"tag":1757,"props":1958,"children":1959},{},[1960],{"type":48,"value":1961},"Managing overlay packaging for the Extensions Catalog",{"type":43,"tag":1735,"props":1963,"children":1964},{},[1965,1974],{"type":43,"tag":1757,"props":1966,"children":1967},{},[1968],{"type":43,"tag":76,"props":1969,"children":1971},{"className":1970},[],[1972],{"type":48,"value":1973},"backstage-upgrade",{"type":43,"tag":1757,"props":1975,"children":1976},{},[1977],{"type":48,"value":1978},"Upgrading Backstage dependency versions",{"type":43,"tag":1735,"props":1980,"children":1981},{},[1982,1991],{"type":43,"tag":1757,"props":1983,"children":1984},{},[1985],{"type":43,"tag":76,"props":1986,"children":1988},{"className":1987},[],[1989],{"type":48,"value":1990},"rhdh-local",{"type":43,"tag":1757,"props":1992,"children":1993},{},[1994],{"type":48,"value":1995},"Running and testing plugins locally",{"type":43,"tag":1735,"props":1997,"children":1998},{},[1999,2008],{"type":43,"tag":1757,"props":2000,"children":2001},{},[2002],{"type":43,"tag":76,"props":2003,"children":2005},{"className":2004},[],[2006],{"type":48,"value":2007},"rhdh",{"type":43,"tag":1757,"props":2009,"children":2010},{},[2011],{"type":48,"value":2012},"RHDH version matrix, repo navigation, ecosystem context",{"type":43,"tag":57,"props":2014,"children":2016},{"id":2015},"ecosystem-official-backstage-skills",[2017],{"type":48,"value":2018},"Ecosystem & Official Backstage Skills",{"type":43,"tag":51,"props":2020,"children":2021},{},[2022,2023,2028],{"type":48,"value":616},{"type":43,"tag":76,"props":2024,"children":2026},{"className":2025},[],[2027],{"type":48,"value":1878},{"type":48,"value":2029}," for complementary open-source skills\n(frontend quality from skills.sh) and official Backstage.io skills (migration\nand instrumentation workflows).",{"type":43,"tag":2031,"props":2032,"children":2033},"style",{},[2034],{"type":48,"value":2035},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":2037,"total":2144},[2038,2052,2065,2084,2098,2115,2125],{"slug":2039,"name":2039,"fn":2040,"description":2041,"org":2042,"tags":2043,"stars":26,"repoUrl":27,"updatedAt":2051},"agent-ready","assess repository readiness for AI agents","Assesses a git repository's readiness for use by AI coding agents using the agentready CLI, then walks through and addresses each gap. RHDH-aware: detects RHDH repositories and uses rhdh-repos.md context to pre-fill AGENTS.md and skip inapplicable findings. Use when asked to \"assess agent readiness\", \"run agentready\", \"check how agent-ready this repo is\", \"make this repo agent-ready\", \"improve agent readiness score\", \"assess all RHDH repos\", \"batch agent readiness\", or \"onboard this repo for agents\".\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2044,2047,2050],{"name":2045,"slug":2046,"type":16},"Agents","agents",{"name":2048,"slug":2049,"type":16},"Code Analysis","code-analysis",{"name":18,"slug":19,"type":16},"2026-07-16T06:03:24.758348",{"slug":1973,"name":1973,"fn":2053,"description":2054,"org":2055,"tags":2056,"stars":26,"repoUrl":27,"updatedAt":2064},"upgrade Backstage dependencies","Upgrade @backstage\u002F* dependencies in a plugin or app to a target version. Use when asked to \"upgrade backstage\", \"bump backstage\", \"update @backstage\", \"align backstage deps\", \"backstage version bump\", \"upgrade dependencies\", \"backstage-cli versions:bump\", \"update to latest backstage\", \"fix version mismatch\", \"backstage version alignment\", \"upgrade before migration\", or any request to update Backstage package versions in a project.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2057,2058,2061],{"name":18,"slug":19,"type":16},{"name":2059,"slug":2060,"type":16},"Maintenance","maintenance",{"name":2062,"slug":2063,"type":16},"Migration","migration","2026-07-16T06:03:24.067361",{"slug":2066,"name":2066,"fn":2067,"description":2068,"org":2069,"tags":2070,"stars":26,"repoUrl":27,"updatedAt":2083},"base-images-and-rpms","update base images and lockfiles","Updates base images with updateBaseImages.sh and regenerates rpms.lock.yaml with rpm-lockfile-prototype in redhat-developer\u002Frhdh, rhdh-must-gather, and rhdh-operator. Use --analyze for read-only Containerfile\u002FDockerfile scan (current vs latest tags, UBI skew). Use for weekly upstream maintenance, UBI\u002FRHEL base image bumps, RPM lockfile refresh, base-images-and-rpms, main, release-*, or analyzing base images before updating.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2071,2074,2077,2080],{"name":2072,"slug":2073,"type":16},"Automation","automation",{"name":2075,"slug":2076,"type":16},"Configuration","configuration",{"name":2078,"slug":2079,"type":16},"Containers","containers",{"name":2081,"slug":2082,"type":16},"Deployment","deployment","2026-07-16T06:03:27.784453",{"slug":2085,"name":2085,"fn":2086,"description":2087,"org":2088,"tags":2089,"stars":26,"repoUrl":27,"updatedAt":2097},"bug-fix","diagnose and fix plugin bugs","Reproduce, diagnose, fix, and PR plugin bugs from Jira tickets or GitHub issues. Works with both rhdh-plugins and community-plugins. Supports UI bugs (Playwright e2e with before\u002Fafter recordings) and backend bugs (unit\u002Fintegration test verification). Triages issues for agent-readiness before attempting a fix. Accepts a Jira key (RHDHBUGS-1934), Jira URL (redhat.atlassian.net\u002Fbrowse\u002F...), GitHub issue URL (github.com\u002F...\u002Fissues\u002FN), or a request to \"fix this bug\", \"reproduce and fix\", \"\u002Fbug-fix\". By default, stops after the fix for user verification before PR creation. Supports --no-verify mode to skip the verification gate and auto-create the PR. Chains into raise-pr for the full PR lifecycle.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2090,2093,2096],{"name":2091,"slug":2092,"type":16},"Debugging","debugging",{"name":2094,"slug":2095,"type":16},"QA","qa",{"name":1399,"slug":1396,"type":16},"2026-07-29T06:00:33.054762",{"slug":2099,"name":2099,"fn":2100,"description":2101,"org":2102,"tags":2103,"stars":26,"repoUrl":27,"updatedAt":2114},"compute-plugin-package-overlay-cve-list","generate CVE management reports","Builds an RHDH CVE Management CSV from GA plugin workspace changes in rhdh-plugin-export-overlays since a version tag (patches, source.json, plugins-list). One row per CVE × plugins-list package (multi-workspace CVEs expand). Use for \"CVE CSV\", \"workspace CVEs since tag\", \"collect overlay CVEs\", \"CVE management CSV\", orchestrator\u002Flightspeed CVE review, or plugin package overlay CVE list.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2104,2107,2108,2111],{"name":2105,"slug":2106,"type":16},"Compliance","compliance",{"name":18,"slug":19,"type":16},{"name":2109,"slug":2110,"type":16},"Reporting","reporting",{"name":2112,"slug":2113,"type":16},"Security","security","2026-08-01T05:41:57.852801",{"slug":1923,"name":1923,"fn":2116,"description":2117,"org":2118,"tags":2119,"stars":26,"repoUrl":27,"updatedAt":2124},"scaffold and package RHDH dynamic plugins","Full lifecycle for RHDH dynamic plugins — scaffold, implement, export, package, and configure. Use when asked to \"create RHDH plugin\", \"bootstrap dynamic plugin\", \"create backend plugin\", \"create frontend plugin\", \"export dynamic plugin\", \"package plugin as OCI\", \"generate frontend wiring\", \"create plugin container image\", \"configure mount points\", \"create dynamic route\", \"add entity card\", \"scaffold RHDH plugin\", \"publish plugin to registry\", \"create tgz archive\", or mentions creating, exporting, packaging, or wiring a Backstage plugin for Red Hat Developer Hub. Also use when asked to \"build a plugin from scratch\", \"dynamic plugin tutorial\", \"RHDH plugin from scratch\", or \"build Backstage plugin for RHDH\". Covers backend plugins (APIs, scaffolder actions, processors), frontend plugins (pages, cards, themes), export\u002Fpackaging (OCI, tgz, npm), and frontend wiring configuration (mount points, routes, entity tabs, themes).\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2120,2121],{"name":2081,"slug":2082,"type":16},{"name":2122,"slug":2123,"type":16},"Plugin Development","plugin-development","2026-07-16T06:02:28.983498",{"slug":2126,"name":2126,"fn":2127,"description":2128,"org":2129,"tags":2130,"stars":26,"repoUrl":27,"updatedAt":2143},"cursor-mcp-auth","authenticate Atlassian MCP for Jira","Ensures Cursor Atlassian MCP (plugin-atlassian-atlassian → mcp.atlassian.com) is authenticated for redhat.atlassian.net via OAuth. Use for \"authenticate Jira\", \"Atlassian MCP\", \"jira auth failed\", \"mcp_auth Atlassian\", \"cursor MCP auth\", or when another skill needs working Jira access through Cursor MCP.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2131,2134,2137,2140],{"name":2132,"slug":2133,"type":16},"Auth","auth",{"name":2135,"slug":2136,"type":16},"Jira","jira",{"name":2138,"slug":2139,"type":16},"MCP","mcp",{"name":2141,"slug":2142,"type":16},"OAuth","oauth","2026-07-29T06:00:33.525179",24,{"items":2146,"total":2144},[2147,2153,2159,2166,2172,2179,2184,2191,2203,2216,2228,2237],{"slug":2039,"name":2039,"fn":2040,"description":2041,"org":2148,"tags":2149,"stars":26,"repoUrl":27,"updatedAt":2051},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2150,2151,2152],{"name":2045,"slug":2046,"type":16},{"name":2048,"slug":2049,"type":16},{"name":18,"slug":19,"type":16},{"slug":1973,"name":1973,"fn":2053,"description":2054,"org":2154,"tags":2155,"stars":26,"repoUrl":27,"updatedAt":2064},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2156,2157,2158],{"name":18,"slug":19,"type":16},{"name":2059,"slug":2060,"type":16},{"name":2062,"slug":2063,"type":16},{"slug":2066,"name":2066,"fn":2067,"description":2068,"org":2160,"tags":2161,"stars":26,"repoUrl":27,"updatedAt":2083},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2162,2163,2164,2165],{"name":2072,"slug":2073,"type":16},{"name":2075,"slug":2076,"type":16},{"name":2078,"slug":2079,"type":16},{"name":2081,"slug":2082,"type":16},{"slug":2085,"name":2085,"fn":2086,"description":2087,"org":2167,"tags":2168,"stars":26,"repoUrl":27,"updatedAt":2097},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2169,2170,2171],{"name":2091,"slug":2092,"type":16},{"name":2094,"slug":2095,"type":16},{"name":1399,"slug":1396,"type":16},{"slug":2099,"name":2099,"fn":2100,"description":2101,"org":2173,"tags":2174,"stars":26,"repoUrl":27,"updatedAt":2114},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2175,2176,2177,2178],{"name":2105,"slug":2106,"type":16},{"name":18,"slug":19,"type":16},{"name":2109,"slug":2110,"type":16},{"name":2112,"slug":2113,"type":16},{"slug":1923,"name":1923,"fn":2116,"description":2117,"org":2180,"tags":2181,"stars":26,"repoUrl":27,"updatedAt":2124},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2182,2183],{"name":2081,"slug":2082,"type":16},{"name":2122,"slug":2123,"type":16},{"slug":2126,"name":2126,"fn":2127,"description":2128,"org":2185,"tags":2186,"stars":26,"repoUrl":27,"updatedAt":2143},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2187,2188,2189,2190],{"name":2132,"slug":2133,"type":16},{"name":2135,"slug":2136,"type":16},{"name":2138,"slug":2139,"type":16},{"name":2141,"slug":2142,"type":16},{"slug":2192,"name":2192,"fn":2193,"description":2194,"org":2195,"tags":2196,"stars":26,"repoUrl":27,"updatedAt":2202},"konflux-release-data-rpa","update release tags in konflux-release-data","Bumps RHDH ReleasePlanAdmission tag versions in konflux-release-data for a stream release (e.g. 1.9.7), opens a GitLab merge request, and launches it in the browser. Use when updating RPA tags, konflux-release-data, ReleasePlanAdmission, rhdh-1-9-*.yaml, rhdh-plugin-catalog-1-9-*.yaml, or preparing an RHDH patch release.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2197,2198,2199],{"name":2072,"slug":2073,"type":16},{"name":2081,"slug":2082,"type":16},{"name":2200,"slug":2201,"type":16},"GitLab","gitlab","2026-07-16T06:00:19.516231",{"slug":2204,"name":2204,"fn":2205,"description":2206,"org":2207,"tags":2208,"stars":26,"repoUrl":27,"updatedAt":2215},"konflux-tekton-updates","update Konflux Tekton task digests","Bumps Konflux Tekton task digests with .tekton\u002FupdateDigests.sh --minor --no-push, applies konflux-ci\u002Fbuild-definitions MIGRATION.md pipeline fixes, and regenerates PipelineRuns. Use for rhdh-plugin-catalog, RHDH midstream (4-rhdh), Konflux task minor bumps, prefetch-dependencies-oci-ta, build-image-index, or updateDigests.sh.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2209,2210,2213,2214],{"name":2072,"slug":2073,"type":16},{"name":2211,"slug":2212,"type":16},"CI\u002FCD","ci-cd",{"name":2081,"slug":2082,"type":16},{"name":18,"slug":19,"type":16},"2026-07-16T06:03:28.123118",{"slug":2217,"name":2217,"fn":2218,"description":2219,"org":2220,"tags":2221,"stars":26,"repoUrl":27,"updatedAt":2227},"lifecycle","check Red Hat product lifecycle status","Check version lifecycle and support status for platforms and integrations used by RHDH. Covers OCP, AKS, EKS, GKE, RHDH releases, RHBK, Quay, PostgreSQL, and any Red Hat product via the Product Life Cycles API. Use when asking about version support, EOL dates, GA dates, support phases, or planning version upgrades. Also use for \"is X still supported\", \"what versions should we test\", or \"when does X reach EOL\".",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2222,2223,2224],{"name":2105,"slug":2106,"type":16},{"name":2059,"slug":2060,"type":16},{"name":2225,"slug":2226,"type":16},"Operations","operations","2026-07-16T06:03:19.344038",{"slug":1013,"name":1013,"fn":2229,"description":2230,"org":2231,"tags":2232,"stars":26,"repoUrl":27,"updatedAt":2236},"migrate plugins to New Frontend System","Migrate Backstage frontend plugins from the legacy system to the New Frontend System (NFS). Use when asked to \"migrate to NFS\", \"new frontend system\", \"convert plugin to NFS\", \"createFrontendPlugin\", \"PageBlueprint\", \"ApiBlueprint\", \"SubPageBlueprint\", \"alpha to GA\", \"legacy to NFS\", \"frontend migration\", \"extension blueprints\", \"migrate frontend plugin\", \"NFS support\", \"graduate alpha\", or mentions migrating a Backstage plugin to the new frontend system for RHDH.\n",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2233,2234,2235],{"name":18,"slug":19,"type":16},{"name":24,"slug":25,"type":16},{"name":2062,"slug":2063,"type":16},"2026-07-16T06:03:27.078987",{"slug":1956,"name":1956,"fn":2238,"description":2239,"org":2240,"tags":2241,"stars":26,"repoUrl":27,"updatedAt":2248},"manage RHDH plugin export overlays","Manages the rhdh-plugin-export-overlays repository — onboards plugins to the Extensions Catalog, updates plugin versions, fixes overlay build failures, triages and analyzes PRs, triggers publishes, and manages plugin workspaces. Use when working with overlays, importing plugins, debugging CI, checking PRs, bumping versions, or mentions \"Extensions Catalog\", \"overlay build failed\", \"plugin registry\", \"overlay PR\", \"overlay doctor\", \"plugin import\", \"add plugin to catalog\", \"onboard plugin\", or \"plugin workspace\".",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[2242,2243,2246,2247],{"name":2072,"slug":2073,"type":16},{"name":2244,"slug":2245,"type":16},"Code Review","code-review",{"name":2081,"slug":2082,"type":16},{"name":18,"slug":19,"type":16},"2026-07-16T06:03:20.380044"]