Getting it into your agent
One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.
npx skills add bendaamerahmed/backstage-idp-plugin --skill backstage-incident-debuggit clone --depth 1 https://github.com/bendaamerahmed/backstage-idp-pluginWrote this? Show the measurements
A badge with what this costs and how it scanned, read live from this page, so it follows the numbers instead of freezing them. Markdown for a README, HTML for a documentation site or a project page.
[](https://agentmods.dev/skills/bendaamerahmed/backstage-idp-plugin/backstage-incident-debug)<a href="https://agentmods.dev/skills/bendaamerahmed/backstage-idp-plugin/backstage-incident-debug"><img src="https://agentmods.dev/badge/skills/bendaamerahmed/backstage-idp-plugin/backstage-incident-debug/github.svg" alt="Measured on agentmods" height="20"></a>Or the 80×15 button, for a site that already has a row of RSS and ATOM ones. Only the verdict fits; the numbers stay here.
<a href="https://agentmods.dev/skills/bendaamerahmed/backstage-idp-plugin/backstage-incident-debug"><img src="https://agentmods.dev/badge/skills/bendaamerahmed/backstage-idp-plugin/backstage-incident-debug.svg" alt="Reviewed on agentmods" width="80" height="20"></a>What it costs to keep this loaded
Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.
| Model | Per session | Once invoked |
|---|---|---|
| Fable 5.1 | $0.00042 | $0.03930 |
| Opus 5 | $0.00021 | $0.01965 |
| Sonnet 5 | $0.00008 | $0.00786 |
| Haiku 4.5 | $0.00004 | $0.00393 |
Grade A, and why
backstage-incident-debug scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 10d ago.
A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.
Nothing flagged
None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.
How it starts
The opening of the file, as written. The whole thing — 97 lines — stays where its author put it; the contents beside it link to each section on GitHub.
Backstage Incident Debugging
Narrow a failing Backstage deployment to one layer with evidence before proposing a cause. Read-only by default; anything that mutates a shared environment stops for authorization.
Preconditions
- The exact symptom, its first-seen timestamp, and which environment. Without a timestamp you cannot correlate with deploys, and correlation is most of the diagnosis.
- Read access to the failing environment's merged config, not the repo's
app-config.yaml.app-config.production.yamloverrides nearly everything that matters. - Backend reachability plus a token if auth is enforced. A
401withMissing credentialsfrom every endpoint is your missing token, not the incident. External callers usebackend.auth.externalAccess—type: static(withtoken,subject, optionalaccessRestrictions) ortype: jwks. - Release line from
backstage.json, andyarn backstage-cli info --format jsonfor Node, CLI, and resolved@backstage/*versions. - Generation, because half the diagnostics below do not exist in the other one. Backend:
createBackend()inpackages/backend/src/index.tsis the new backend system;createRouterfiles underpackages/backend/src/plugins/are legacy. Frontend:createAppfrom@backstage/frontend-defaultsis NFS (default since v1.49);@backstage/app-defaultsplus<FlatRoutes>is legacy.
Procedure
- Record symptom and blast radius before forming any hypothesis. One entity, one user, one plugin, or everyone. This single fact eliminates most layers: one entity is data or processing; one user is auth or permissions; one plugin is that plugin's config, backend, or upstream; everyone is process, config, or database.
- Establish whether the backend is up.
GET /.backstage/health/v1/livenessandGET /.backstage/health/v1/readiness(new backend system, v1.29.0+; legacy backends expose/healthcheck). Liveness OK with readiness failing means the process is alive and a dependency — usually the database — is not. Neither answering plus a restarting pod is a crash loop; jump to step 5. - Build the change timeline covering the 48h before first-seen: application deploy, changes to any
app-config.*file, credential or secret rotation, abackstage.jsonbump (backstage-upgrade), permission policy change, andcatalog-info.yamlchanges in target repos. "Nothing changed" almost always means an expiring credential, a scheduled provider run, or an upstream quota reset. - Reproduce against the failing environment's merged config, never the local default.
yarn backstage-cli config:print --lax --format yaml, passing--configfor each file in the same order the deployment does;--frontendprints exactly what the browser receives;--with-secretsonly if authorized. Validate withyarn backstage-cli config:check --lax --deprecated;--strictadditionally rejects keys no schema declares.config:schemashows which keys are even known.BACKSTAGE_ENVtakes comma-separated values, so you can stack the deployed config layers locally. - Split frontend from backend with the browser network tab, not with logs.
/api/*returning 4xx/5xx → backend; go to that plugin's layer below.- Request 200 but the data is wrong → data or processing, not transport.
- Blank page with no failing request → the bundle got the wrong config. Frontend config is injected at container start by the nginx entrypoint from environment variables, not baked at build time, and a single missing variable makes the whole
${VAR}value evaluate to undefined. Diffconfig:print --frontendagainst what the deployment sets. - Origin and CORS errors are
app.baseUrl/backend.baseUrldisagreeing with the real hostname, not a Backstage bug.
- Raise log level surgically.
LOG_LEVEL=debug(env var, takes precedence over config) is fine locally and a firehose in production. Preferbackend.logger.overrideswithmatchers: { plugin: catalog }andlevel: debugto raise one plugin, andbackend.logger.metato stamp every line with the environment. Levels areerror,warn,info(default),debug. - Read the logs for the right lines. Every line carries the plugin id from the plugin-scoped logger — filter on it first. The useful signals are the startup sequence for the failing plugin, and the last successful scheduled-task line for the relevant provider. Catalog processing errors are not logged by default, so an absence of catalog errors in the log is not evidence of a healthy catalog.
- Catalog layer. Query the catalog's own belief rather than reading provider code (
backstage-catalog):GET /api/catalog/entity-facets?facet=kind— a census. A whole integration that stopped ingesting is visible in one request.GET /api/catalog/entities/by-query?filter=metadata.annotations.backstage.io/orphan=true— the orphan set.GET /api/catalog/entities/by-name/<kind>/<ns>/<name>— readstatus.items; that is where processing errors actually live..../by-name/<kind>/<ns>/<name>/ancestry— which root is keeping the entity alive, or which one stopped.GET /api/catalog/locations— registered roots.POST /api/catalog/refreshwith{ entityRef }forces one cycle instead of waiting outcatalog.processingInterval.
- Scaffolder layer. Find the task id from the task list page under
/create/tasks, then read its status and event log. Read the exact backend route paths and client method names from the installed@backstage/plugin-scaffolder-backendrouter and@backstage/plugin-scaffolder-reacttypes — they are version-sensitive. Tasks are database rows with a heartbeat, so a task claimed by a backend instance that died stays claimed. - TechDocs layer. Establish which of the four stages broke — annotation, mkdocs source, generator, publisher — by listing the storage bucket under the entity's lowercased
<namespace>/<kind>/<name>/prefix before touching anything else (backstage-techdocs). - Auth layer. Drive the flow by hand at
/api/auth/<provider>/start?env=<auth.environment>and watch the callback. Watch/api/auth/<provider>/refreshin the network tab for session-persistence problems. Decode the issued token in the console withatob(token.split('.')[1])and checksubandentclaims against the catalog. - Permissions layer. Confirm
permission.enabledin the merged config for that environment — permissions are frequently on in production and off locally, which alone explains "works on my machine". Then confirm whether the policy sees the identity you think it does: an empty ownership claim set from the sign-in resolver denies everything a policy conditions on group membership. - Database layer. With no
backend.databaseconfig, each plugin gets an in-memory SQLite database that is discarded on restart — that is the cause of "everything is empty again after every deploy". Otherwise check connection-pool saturation, which presents as readiness failing and every plugin slowing at once rather than one plugin breaking. - Integration layer. Rate-limit exhaustion is partial, not total: discovery returns fewer repos than it did, refreshes stall, 403s arrive in bursts, and it recovers on its own at the quota reset. GitHub Apps (
integrations.github.apps) get substantially higher limits than a PAT; note thatThis endpoint requires you to be authenticatedfrom a correctly configured app usually means the app is not installed on that organization, not that the credential is wrong. - Stop after three hypotheses. Form at most three candidate causes, each with a stated disproof test, and run them cheapest-to-disprove first. If all three are disproved, return a BLOCKED report containing:
- the symptom, first-seen timestamp, and blast radius;
- the change timeline you built in step 3;
- the three hypotheses and the specific evidence that killed each;
- the layer you narrowed to and what remains ambiguous within it;
- the exact access, log, or authorization you would need to continue. Do not start a fourth round, and do not apply a speculative fix to see what happens.
- Stop for authorization before any production mutation. Restarting a pod, re-running a provider, deleting or re-registering a location, cancelling or retrying a scaffolder task, editing deployed config, rotating a credential, and running a migration all change shared state and most of them destroy evidence. Propose the exact command, its blast radius, and how you would undo it, then wait.
What this file has done since we first saw it
Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.
- 10d ago First seen · 97 lines · 42 tokens per session scan A 064737da5011
backstage-incident-debug is a skill published in the GitHub repository bendaamerahmed/backstage-idp-plugin (1 stars, last pushed 1mo ago), licensed MIT. It adds 42 tokens to every session and 3,930 once invoked, about $0.0002 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-31.
Other skills, from other repositories
audit
Project health audit and health check — architecture, performance, tests, dependencies, code quality. Use when assessing overall project health, before releases, or after refactors.
investigate
Investigate bugs and errors in Elixir/Phoenix — root-cause analysis for crashes, exceptions, stack traces, test failures. Use --parallel for deep 4-track investigation.
narrow-bare-rescue
Narrow bare rescue in Elixir so real errors like KeyError and typos propagate instead of being swallowed. Use to audit rescues and refactor error handling.
tidewave-integration
Tidewave MCP runtime tools — debugging, smoke testing, live state inspection, SQL queries, hex docs. Use when evaluating code in a running Phoenix app.
verify
Verify Elixir/Phoenix changes — compile, format, and test in one loop. Use after implementation, before PRs, or after fixing bugs.
perf
Analyze Elixir/Phoenix performance — N+1 queries, assign bloat, ecto optimization, genserver bottlenecks. Use when slowness, timeouts, or high memory reported.