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-scaffoldergit 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-scaffolder)<a href="https://agentmods.dev/skills/bendaamerahmed/backstage-idp-plugin/backstage-scaffolder"><img src="https://agentmods.dev/badge/skills/bendaamerahmed/backstage-idp-plugin/backstage-scaffolder/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-scaffolder"><img src="https://agentmods.dev/badge/skills/bendaamerahmed/backstage-idp-plugin/backstage-scaffolder.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.00041 | $0.03948 |
| Opus 5 | $0.00020 | $0.01974 |
| Sonnet 5 | $0.00008 | $0.00790 |
| Haiku 4.5 | $0.00004 | $0.00395 |
Grade A, and why
backstage-scaffolder 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 11d 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 — 104 lines — stays where its author put it; the contents beside it link to each section on GitHub.
Backstage Scaffolder
Write Template entities and custom scaffolder actions that survive review, run under the permission framework, and fail loudly instead of silently.
Preconditions
- Release line from
backstage.json; scaffolder packages resolved viayarn why @backstage/plugin-scaffolder-backend. - Backend generation:
createBackend()+backend.add(import('@backstage/plugin-scaffolder-backend'))inpackages/backend/src/index.tsis the new backend system. Apackages/backend/src/plugins/scaffolder.tsrouter is legacy — migrate first (backstage-plugin-migrate) or register actions through the router's options and say so in your report. - Frontend generation matters only for custom field extensions: NFS uses
FormFieldBlueprint+createFormFieldfrom@backstage/plugin-scaffolder-react/alpha. Read the installed package's exports rather than assuming the legacy registration shape. @backstage/plugin-catalog-backend-module-scaffolder-entity-modelpresent in the backend — without itkind: Templatedoes not validate and no template appears.- Working SCM
integrationsinapp-config.yamlfor whichever host the template publishes to. - A local backend you may run. Any run that touches a real SCM org is an external mutation — stop and get authorization first.
Procedure
- Inventory before authoring.
GET /api/scaffolder/v2/actions(or the/create/actionspage) for installed actions and their input/output schemas;GET /api/scaffolder/v2/templating-extensionsfor available filters and globals. Never guess an action's input keys — they are published there. - Start the entity.
apiVersion: scaffolder.backstage.io/v1beta3,kind: Template,metadata.name, andspec.owner+spec.type. Body isspec.parameters,spec.steps,spec.output. - Write
spec.parametersas oneFormStepor an array of them. Each step is JSON Schema (title,description,required,properties) with rjsfui:*keys merged in —ui:autofocus,ui:emptyValue,ui:help,ui:widget,ui:options. Array elements become separate wizard pages; use them to keep any one page short. Custom validation messages followajv-errors. - Use the built-in pickers instead of free-text strings.
ui:field: RepoUrlPickerwithui:options.allowedHosts(must match anintegrationshost), plusallowedOwners/allowedReposto narrow. Value is a repo spec string likegithub.com?repo=x&owner=y, not a URL.ui:field: OwnerPickerwithui:options.catalogFilter— eitherkind: [Group, User]or a list of full catalog API filters (metadata.annotations.github.com/team-slug: { exists: true }).ui:field: EntityPickerfor arbitrary catalog entities;RepoBranchPickerandRepoOwnerPickerfor autocomplete, both of which requirerequestUserCredentials(andhostfor the owner picker) to function.- Set
ui:options.requestUserCredentials: { secretsKey: USER_OAUTH_TOKEN, additionalScopes: { github: [workflow] } }when the template must act as the user; consume it as${{ secrets.USER_OAUTH_TOKEN }}. Requires a configured auth provider andScmAuthApi(backstage-auth).
- Route every credential through secrets, never parameters.
ui:field: Secretkeeps the value out of the task record and REST responses and masks it in the review step. Read it as${{ secrets.name }}—${{ parameters.name }}will be undefined.- For programmatic task creation declare
spec.secrets.schemawithrequired/properties. A missing secret then fails task creation with400andsecrets.X is required, instead of mid-run. - Org-wide values belong in
scaffolder.defaultEnvironmentinapp-config.yaml, read as${{ environment.parameters.* }}and${{ environment.secrets.* }}. Environment secrets are masked in logs and never reach the frontend.
- Write
spec.stepsasid,name,action,input, with optionalifandeach. Use camelCase step and action ids: a dash makes${{ steps.my-action.output.x }}evaluate toNaN, and the bracket form${{ steps['my-action'].output.x }}is the only workaround. Witheach, the iteration value is${{ each.value }}(or${{ each.value.field }}), and the step's outputs become an array. - Prefer built-ins over custom code.
- Shipped in
@backstage/plugin-scaffolder-backend:fetch:plain,fetch:plain:file,fetch:template,fetch:template:file,catalog:register,catalog:write,debug:log,debug:wait,fs:delete,fs:rename,fs:readdir. - Publish/PR actions come from
@backstage/plugin-scaffolder-backend-module-{github,gitlab,azure,bitbucket-cloud,bitbucket-server,gerrit,gitea}; add one withyarn --cwd packages/backend add <pkg>thenbackend.add(import('<pkg>')). - Community actions live under
@backstage-community/plugin-scaffolder-backend-module-*. Read the handler before installing one.
- Shipped in
- Template the skeleton with
fetch:template. Inside skeleton files the variables are${{ values.x }}— onlytemplate.yamlitself sees${{ parameters.x }}— and they must be passed explicitly throughinput.values. UsecopyWithoutTemplatingfor files whose own${{ }}syntax must survive (GitHub Actions workflows, Helm charts),targetPathto place output in a subdirectory, andreplace: trueonly when overwriting existing workspace files is intended. - Glue steps with expressions.
${{ }}is evaluated by Nunjitsu, a deliberately reduced subset of Nunjucks. Check its compatibility guide before using any Nunjucks tag or filter; do not assume full Nunjucks.- Built-in filters:
parseRepoUrl,parseEntityRef(accepts{ defaultKind, defaultNamespace }),pick('name'),projectSlug. Custom filters and globals are registered from a backend module againstscaffolderTemplatingExtensionPoint. ${{ user.entity }}gives the caller's catalogUserentity — useful forgitAuthorName/gitAuthorEmail— and requires a sign-in resolver that maps to a catalog user.
- Handle failure paths explicitly. After a step fails, later steps are skipped unless their
ifinvokes${{ always() }}or${{ failure() }}. Any template that creates external resources before a step that can fail needs afailure()cleanup step;if: ${{ true }}will not run. - Finish with
spec.output.linkstaketitleplusurl, oricon+entityReffor a catalog link;textitems taketitle+contentmarkdown. Both accept a per-itemif. Source values from${{ steps['publish'].output.remoteUrl }}/${{ steps['register'].output.entityRef }}. - Gate sensitive parameters and steps with
backstage:permissions: { tags: [<tag>] }on the parameter step or the step, then enforce in the policy (step 15).backstage:featureFlaghides parameters or fields but cannot gatespec.steps[].if— expose a boolean parameter and branch on it instead. - Scaffold custom actions, do not hand-roll.
yarn backstage-cli new→scaffolder-backend-modulegenerates the package,module.ts, an action and a test.createTemplateActionfrom@backstage/plugin-scaffolder-nodetakesid(namespacedprovider:entity:verb, camelCase segments),description,examples,supportsDryRun,schema.input/schema.output,handler.- Current schemas are per-property zod callbacks —
contents: z => z.string({ description: '...' }). The accepted schema shape has changed across releases, so readcreateTemplateAction's type from the installed package before writing it. examples: TemplateExample[](YAML strings of astepssnippet) is what renders on/create/actions. Without it, template authors cannot discover the action's usage.
- Register the action in
createBackendModule, whose option shape you read from the installed@backstage/backend-plugin-apitypes — currentlypluginId,moduleIdandregister.- Depend on
scaffolderActionsExtensionPointfrom@backstage/plugin-scaffolder-nodeand callscaffolder.addActions(myAction(...)). - Pass core services (
coreServices.rootConfig,coreServices.cache,coreServices.discovery,coreServices.auth) asdepsand close over them in the action factory; never reach for globals inside a handler. - Inside the handler use only
ctx:ctx.input,ctx.output(key, value),ctx.logger,ctx.workspacePath,ctx.createTemporaryDirectory(),ctx.isDryRun,ctx.metadata.name,ctx.checkpoint(experimental idempotency — version the key whenever its return type changes, or a retried task fails on the stale cached value). - Resolve every path with
resolveSafeChildPath(ctx.workspacePath, ctx.input.filename)from@backstage/backend-plugin-api.
- Depend on
- Enforce permissions in the policy (
backstage-permissions). Without one, every signed-in user may execute every template and every action.- Permissions from
@backstage/plugin-scaffolder-common/alpha:templateParameterReadPermission,templateStepReadPermission,actionExecutePermission,taskCreatePermission,taskReadPermission,taskCancelPermission. - Decisions and rules from
@backstage/plugin-scaffolder-backend/alpha:createScaffolderTemplateConditionalDecision+scaffolderTemplateConditions.hasTag;createScaffolderActionConditionalDecision+scaffolderActionConditions.hasActionId/hasProperty;createScaffolderTaskConditionalDecision+scaffolderTaskConditions.isTaskOwner. - Rules compose with
not/allOf/anyOf— e.g. denydebug:logonly whenhasProperty({ key: 'message', value: 'not-this!' }).
- Permissions from
- Register the template as a
Location—catalog.locationswithrules: [{ allow: [Template] }], or/catalog-import. Restrict which repositories may contributeTemplateentities: scaffolder jobs run on the backend host with the backend's credentials, so template authorship is a privileged capability.
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.
- 11d ago First seen · 104 lines · 41 tokens per session scan A cedd58487222
backstage-scaffolder is a skill published in the GitHub repository bendaamerahmed/backstage-idp-plugin (1 stars, last pushed 1mo ago), licensed MIT. It adds 41 tokens to every session and 3,948 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
catchup
Summarize and review what changed while you were away. Use after a weekend, vacation, or flight to check missed PRs, git commits, Linear tickets, and meetings — one prioritized brief, not a firehose.
plan
Plan features spanning multiple domains: billing (Stripe), auth (RBAC), real-time (Presence), webhooks, jobs (Oban). Use when designing interconnected systems or converting review findings into tasks.
work
Execute Elixir/Phoenix plan tasks with progress tracking. Use after /phx:plan to implement features with mix compile and mix test verification after each step, or --continue to resume interrupted work.
phx-deps-update
Bump outdated Hex deps — inventory, snapshot changelogs, update, fix breaks, split reviewable PRs (patches bundled, majors solo). Use to upgrade/bump Elixir dependencies or when versions fall behind. NOT for deps.get failures (phx-investigate).
new-work
Create and manage todo tracking documents for features, bugs, and multi-step tasks. Use when starting new work that benefits from a persistent record of decisions, progress, and context.
chief-operating-officer
Owns execution: how work actually gets done across the organization, including process, program management, capacity, vendors, supply chain, and service delivery. Use this when execution is the problem rather than strategy, to design or fix a process, to resolve cross-functional handoff failures, to plan capacity, to…