npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@theplatformlog/template-authoring-backend

v0.2.0

Published

Backstage backend plugin that generates scaffolder Template entities from natural-language descriptions, constrained by a zod schema so the LLM cannot emit an invalid Template.

Readme

Template Authoring Backend

A Backstage backend plugin that generates scaffolder Template entities from a natural-language description, grounded on optional reference templates pulled from the catalog and constrained by a curated catalog of well-known scaffolder actions.

Ask things like:

"A Node.js microservice with Express, OpenTelemetry tracing, and GitHub Actions CI"

…and get back a runnable v1beta3 Template YAML with the right steps in the right order, declared parameters where the action inputs need user data, and entity-ref citations for the reference templates and actions the generator used.

Status

First slice. Backend HTTP endpoint only, no UI. Uses the AI SDK generateObject helper with a zod schema so the LLM is forced to emit a valid Template structure — not just freeform YAML it claims is valid.

Installation

yarn --cwd packages/backend add @backstage/plugin-template-authoring-backend

Register the plugin:

// packages/backend/src/index.ts
backend.add(import('@theplatformlog/template-authoring-backend'));

Configuration

templateAuthoring:
  # LLM provider: anthropic (default) | openai | google | mistral
  provider: anthropic
  # Model id for the chosen provider. Defaults to 'claude-opus-4-8'
  # for anthropic; required for any other provider.
  model: claude-opus-4-8
  # API key for the provider. If omitted, the provider SDK reads its
  # conventional env var (ANTHROPIC_API_KEY, OPENAI_API_KEY, etc.).
  apiKey: ${ANTHROPIC_API_KEY}
  # Defaults to 3
  maxReferenceTemplates: 3
  # Used when the LLM omits spec.owner. Defaults to 'group:default/unowned'.
  defaultOwner: group:default/platform

Using a non-Anthropic provider

@ai-sdk/anthropic ships with this plugin. To use another provider, install its Vercel AI SDK package in your backend and set provider + model:

yarn --cwd packages/backend add @ai-sdk/openai
templateAuthoring:
  provider: openai
  model: gpt-5
  apiKey: ${OPENAI_API_KEY}

Supported providers: anthropic, openai, google, mistral. Note that template generation relies on structured output (generateObject); pick a model on your provider that supports it.

API

POST /api/template-authoring/v1/generate

Request:

{
  "description": "A Node.js microservice with Express, structured logging, and GitHub Actions CI",
  "referenceTemplates": ["template:default/nodejs-service-base"]
}

referenceTemplates is optional. If supplied, each entity ref is fetched from the catalog and embedded in the user prompt as an example of the desired step layout — but the model is instructed not to copy them verbatim.

Response:

{
  "yaml": "apiVersion: scaffolder.backstage.io/v1beta3\nkind: Template\n...",
  "template": { "apiVersion": "scaffolder.backstage.io/v1beta3", "kind": "Template", ... },
  "citations": {
    "referenceTemplates": ["template:default/nodejs-service-base"],
    "actionsUsed": ["fetch:template", "publish:github", "catalog:register"]
  },
  "warnings": [
    "first step uses 'catalog:register'; templates typically start with a fetch:* step to populate the workspace"
  ]
}

Authentication uses the standard Backstage httpAuth service and accepts either a user or service credential. The credential token (if any) is forwarded to the catalog when fetching reference templates so per-user visibility filters are honoured.

Architecture

flowchart LR
    HTTP["<b>POST /v1/generate</b><br/>{ description, referenceTemplates }"] --> RL["<b>ReferenceTemplateLoader</b><br/>fetch + validate<br/>(must be kind: Template)"]
    RL --> CAT[("Catalog API")]
    HTTP --> GS["<b>TemplateGenerationService</b><br/>system prompt + reference YAML<br/>+ well-known action catalog"]
    GS --> AI["<b>AI SDK</b><br/>generateObject({schema, ...})<br/>Claude (or future BEP-0015 provider)"]
    GS --> V["<b>TemplateValidator</b><br/>step-ref resolution,<br/>action id whitelist,<br/>ordering hints"]
    V --> R["JSON response<br/>{ yaml, template,<br/>citations, warnings }"]

Why generateObject and not generateText?

If you ask an LLM for "YAML" you sometimes get back markdown code fences, sometimes get back commentary around the YAML, sometimes get back invalid YAML that needs re-parsing. generateObject constrains the response to JSON that conforms to a zod schema — for Backstage Templates, JSON and YAML are equivalent, so we emit JSON from the model and YAML to the caller via yaml.stringify.

The schema enforces:

  • apiVersion === 'scaffolder.backstage.io/v1beta3'
  • kind === 'Template'
  • metadata.name matches the kebab-case regex Backstage uses
  • spec.steps[].action is one of the curated whitelist of known action ids
  • spec.steps is non-empty

Why a curated action catalog?

In v1 the well-known action catalog is a static list. The plugin runs without having to wire into another plugin's runtime ActionsRegistry. A future revision should source this from the actual registry so the model only ever sees actions that the host backend has loaded — including third-party actions like mcp:call from the companion scaffolder-backend-module-mcp plugin.

Semantic validation beyond the schema

TemplateValidator runs three checks that the zod schema can't:

  1. Step reference resolution. Any ${{ steps.X.... }} expression in a step input or spec.output must point at a step id declared earlier in the template.
  2. Action id whitelist (double-check). zod already enforces this at the type level, but the validator catches the case where the schema is relaxed in a future revision.
  3. Ordering hints. First step is normally a fetch:*. catalog:register normally comes after publish:*. These surface as warnings, not exceptions — opinionated patterns, not hard rules.

Failures are returned alongside the template as a warnings[] field; the caller decides whether to surface them. This keeps the endpoint useful during early iteration even when the model produces something slightly off.

Where this fits

Third plugin in the AI-on-Backstage series:

  1. scaffolder-backend-module-mcp — Backstage as MCP client for scaffolder templates.
  2. catalog-assistant-backend — grounded LLM Q&A over the Software Catalog.
  3. template-authoring-backend — generate scaffolder Templates from natural language (this plugin).

Each composes the same AI-SDK shape, so all three swap behind the BEP-0015 AI Model Provider Service when it lands with a contained refactor.

Limitations

  • No self-correction pass yet. If the model produces a template whose step refs don't resolve, the warnings come back to the caller — we don't re-prompt the model to fix it. Worth adding once the average failure mode is well-understood.
  • No frontend. A separate plugin-template-authoring (frontend) is the natural follow-on for the scaffolder Templates page.
  • Curated action catalog. Not yet sourced from a live ActionsRegistry — see the rationale above.
  • One-shot. No conversation memory, no iterative refinement turn.