.agents/skills/dev-portal-manager/SKILL.md
Guides platform architects in managing the software catalog, structuring documentation for Backstage plugins, and maintaining developer portal integrations
npx skillsauth add em-jones/staccato-toolkit dev-portal-managerInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
The dev-portal-manager skill provides comprehensive guidance for managing a Backstage-based developer portal. It covers:
devbox.json and package.jsonLoad this skill when you need to:
.entities/All catalog entities are stored as YAML files under .entities/ at the repository root.
Files follow the pattern: .entities/<kind-lowercase>-<name-kebab-case>.yaml
Examples:
.entities/component-openspec-td.yaml.entities/system-developer-platform.yaml.entities/domain-engineering-productivity.yaml.entities/resource-jq.yamlA Component represents a software artifact (service, library, website, etc.).
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: openspec-td
title: OpenSpec Task-Driven Development
description: Task management and workflow orchestration for OpenSpec-driven development
annotations:
backstage.io/techdocs-ref: dir:.
backstage.io/adr-location: docs/adrs
tags:
- openspec
- task-management
- workflow
links:
- url: https://github.com/org/openspec-td
title: Repository
icon: github
spec:
type: library
lifecycle: production
owner: platform-team
system: developer-platform
Required fields:
metadata.name: Unique identifier (kebab-case)metadata.description: Brief description of the componentspec.type: Component type (service, library, website, etc.)spec.lifecycle: Lifecycle stage (experimental, production, deprecated)spec.owner: Owning team or group (references a Group entity)Recommended annotations:
backstage.io/techdocs-ref: dir:. — Enable TechDocs (requires mkdocs.yml)backstage.io/adr-location: docs/adrs — Enable ADRs pluginA System groups related components into a logical boundary.
apiVersion: backstage.io/v1alpha1
kind: System
metadata:
name: developer-platform
title: Developer Platform
description: Tools and automations for engineering productivity
tags:
- platform
- developer-experience
spec:
owner: platform-team
domain: engineering-productivity
Required fields:
metadata.name: Unique identifiermetadata.description: System purposespec.owner: Owning teamOptional fields:
spec.domain: Parent domain referenceA Domain represents a high-level business or organizational area.
apiVersion: backstage.io/v1alpha1
kind: Domain
metadata:
name: engineering-productivity
title: Engineering Productivity
description: Initiatives and systems that improve developer velocity and experience
spec:
owner: platform-leadership
Required fields:
metadata.name: Unique identifiermetadata.description: Domain scopespec.owner: Owning groupA Group represents a team, department, or organizational unit.
apiVersion: backstage.io/v1alpha1
kind: Group
metadata:
name: platform-team
title: Platform Engineering Team
description: Team responsible for developer tooling and infrastructure
spec:
type: team
profile:
displayName: Platform Engineering
email: [email protected]
children: []
Required fields:
metadata.name: Unique identifierspec.type: Group type (team, business-unit, organization, etc.)A Resource represents an external dependency, tool, or infrastructure component.
apiVersion: backstage.io/v1alpha1
kind: Resource
metadata:
name: jq
title: jq
description: Command-line JSON processor
tags:
- cli
- json
- utility
spec:
type: utility
owner: platform-team
system: developer-platform
Required fields:
metadata.name: Unique identifierspec.type: Resource type (utility, node-library, database, api, etc.)spec.owner: Owning teamCommon resource types:
utility: CLI tools, system utilities (e.g., jq, yq, devbox)node-library: npm packagesdatabase: Database systemsapi: External APIs.entities/Before referencing an entity in a design, verify the entity file exists in .entities/.
Two scripts automate Resource entity creation from project metadata files:
derive-from-devbox.shPurpose: Generate Resource entities for tools declared in devbox.json
Location: .opencode/skills/dev-portal-manager/scripts/derive-from-devbox.sh
Usage:
./derive-from-devbox.sh [DEVBOX_JSON] [ENTITIES_DIR]
Defaults:
DEVBOX_JSON: ./devbox.jsonENTITIES_DIR: ./.entitiesBehavior:
packages array from devbox.jsonkind: Resource entity with spec.type: utility$ENTITIES_DIR/resource-<tool-name-kebab-case>.yamlpackages is empty or absent, exits cleanly with an informational messageExample:
# From repo root
.opencode/skills/dev-portal-manager/scripts/derive-from-devbox.sh
# From component directory
.opencode/skills/dev-portal-manager/scripts/derive-from-devbox.sh ./devbox.json ../../.entities
derive-from-package-json.shPurpose: Generate Resource entities for npm packages declared in package.json
Location: .opencode/skills/dev-portal-manager/scripts/derive-from-package-json.sh
Usage:
./derive-from-package-json.sh [PACKAGE_JSON] [ENTITIES_DIR]
Defaults:
PACKAGE_JSON: ./package.jsonENTITIES_DIR: ./.entitiesBehavior:
dependencies and devDependencies from package.jsonkind: Resource entity with spec.type: node-library$ENTITIES_DIR/resource-<package-name-kebab-case>.yamlExample:
# From repo root
.opencode/skills/dev-portal-manager/scripts/derive-from-package-json.sh
# From component directory
.opencode/skills/dev-portal-manager/scripts/derive-from-package-json.sh ./package.json ../../.entities
Note: These scripts are templates. Adapt them for specific project structures or organizational needs.
Backstage TechDocs renders Markdown documentation using MkDocs.
For a component to support TechDocs:
mkdocs.yml at component root:site_name: 'Component Name'
site_description: 'Brief description'
nav:
- Home: index.md
- Architecture: architecture.md
plugins:
- techdocs-core
docs/ directory with at least index.md:# Component Name
Welcome to the component documentation.
## Overview
[Component description]
## Getting Started
[Quick start guide]
catalog-info.yaml:metadata:
annotations:
backstage.io/techdocs-ref: dir:.
mkdocs.yml at the component rootdocs/index.md with basic contentbackstage.io/techdocs-ref: dir:. annotation to catalog-info.yamlBefore registering a component entity, ensure the TechDocs annotation is present if documentation is intended.
The Backstage ADRs plugin (@backstage-community/plugin-adr) displays architectural decisions stored as Markdown files.
docs/adrs/ directory at component root
ADR files following naming convention:
NNNN-<title-kebab-case>.md0001-use-openspec-workflow.mdNNNN: Zero-padded sequence number (0001, 0002, etc.)Annotation in catalog-info.yaml:
metadata:
annotations:
backstage.io/adr-location: docs/adrs
# <Sequence>. <Title>
Date: YYYY-MM-DD
## Status
[Proposed | Accepted | Deprecated | Superseded]
## Context
[What is the issue that we're seeing that is motivating this decision or change?]
## Decision
[What is the change that we're proposing and/or doing?]
## Consequences
[What becomes easier or more difficult to do because of this change?]
docs/adrs/docs/adrs/NNNN-<title>.md with the ADR contentbackstage.io/adr-location: docs/adrs annotation exists in catalog-info.yamlThe Backstage Tech Radar plugin visualizes technology adoption across the organization.
tech-radar frontmatter in design.mdAll Tech Radar entries are declared in the YAML frontmatter of design.md files. The docs/tech-radar.json file is generated from these declarations — do not edit it manually.
Frontmatter format:
---
tech-radar:
- name: "chi"
quadrant: "Frameworks/Libraries"
ring: "Adopt"
description: "Lightweight Go router with clean middleware composition"
moved: 1
- name: "gin"
quadrant: "Frameworks/Libraries"
ring: "Assess"
description: "Popular alternative - rejected due to custom Context type"
moved: 0
---
Required fields per entry:
name: Technology name (case-sensitive for display, matched case-insensitively for deduplication)quadrant: One of: Infrastructure, Languages, Frameworks/Libraries, Patterns/Processesring: One of: Adopt, Trial, Assess, Holddescription: Brief explanation of the technology and adoption rationaleOptional fields:
moved: Change since last radar (1 = moved in, -1 = moved out, 0 = no change; defaults to 0)When no technologies are adopted: Omit the tech-radar key or set it to [].
Add the entry to the tech-radar frontmatter block in design.md:
design.md filetech-radar list in the frontmatterRun the sync script to propagate the change:
bash .opencode/skills/dev-portal-manager/scripts/sync-tech-radar.sh
The script will:
design.md files under openspec/changes/ (including archive/)tech-radar frontmatter blocksdate frontmatter fielddocs/tech-radar.json with the merged entriesCommit both files:
git add openspec/changes/<change-name>/design.md docs/tech-radar.json
git commit -m "Add <technology> to Tech Radar (ring: <ring>)"
Automatic sync at archive time: The sync script runs automatically when archiving a change (via openspec-archive-change). Manual syncing is only needed if you want to propagate changes before archiving.
Note: The Tech Radar is a platform-level concern. Entries represent organization-wide technology decisions, not component-specific choices. If two changes declare the same technology with different rings, the entry from the more recently dated change wins (a warning is emitted).
OpenSpec change designs can be surfaced in Backstage as ADRs by symlinking the design.md file into a component's docs/adrs/ directory.
From the component's docs/adrs/ directory:
docs/adrs/<sequence>-<change-name>.md → ../../openspec/changes/<change-name>/design.md
Assumptions:
docs/ is at the repository rootopenspec/changes/ is at the repository rootIf the component is nested, adjust the relative path accordingly.
Identify the owning component:
Determine the next ADR sequence number:
ls docs/adrs/ | grep -E '^[0-9]{4}-' | sort | tail -1
Create the symlink:
cd docs/adrs
ln -s ../../openspec/changes/<change-name>/design.md <sequence>-<change-name>.md
Verify the symlink:
ls -la docs/adrs/<sequence>-<change-name>.md
cat docs/adrs/<sequence>-<change-name>.md # Should display design.md content
Ensure the ADR annotation is present in the component's catalog-info.yaml:
metadata:
annotations:
backstage.io/adr-location: docs/adrs
For the initialize-developer-portal change owned by the openspec-td component:
cd docs/adrs
ln -s ../../openspec/changes/initialize-developer-portal/design.md 0001-initialize-developer-portal.md
Result: The change design appears as ADR 0001 in the Backstage ADRs plugin for the openspec-td component.
Do not create orphan symlinks. Instead:
platform or developer-platform component to own platform-wide decisions.entities/component-<name>.yaml
.entities/system-<name>.yaml
.entities/domain-<name>.yaml
.entities/group-<name>.yaml
.entities/resource-<name>.yaml
<component-root>/
catalog-info.yaml
mkdocs.yml
docs/
index.md
adrs/
0001-<title>.md
0002-<title>.md
docs/tech-radar.json
.opencode/skills/dev-portal-manager/scripts/derive-from-devbox.sh [devbox.json] [.entities]
.opencode/skills/dev-portal-manager/scripts/derive-from-package-json.sh [package.json] [.entities]
cd docs/adrs
ln -s ../../openspec/changes/<change-name>/design.md <sequence>-<change-name>.md
tools
<!--VITE PLUS START--> # Using Vite+, the Unified Toolchain for the Web This project is using Vite+, a unified toolchain built on top of Vite, Rolldown, Vitest, tsdown, Oxlint, Oxfmt, and Vite Task. Vite+ wraps runtime management, package management, and frontend tooling in a single global CLI called `vp`. Vite+ is distinct from Vite, but it invokes Vite through `vp dev` and `vp build`. ## Vite+ Workflow `vp` is a global binary that handles the full development lifecycle. Run `vp help` to pr
development
Guide for building performant data tables. Uses tanstack-table for table logic (sorting, filtering, pagination) and tanstack-virtual for rendering large datasets efficiently.
development
Expert guidance for building observable, expressive, and fault-tolerant TypeScript applications using the effect-ts/effect ecosystem. Covers Effect<A, E, R> type, error management, dependency injection via Layers, observability (logging, metrics, tracing), concurrency with Fibers, retry/scheduling, Schema validation, Streams, and Sinks.
tools
Complete E2E (end-to-end) and integration testing skill for TypeScript/NestJS projects using Jest, real infrastructure via Docker, and GWT pattern. ALWAYS use this skill when user needs to: **SETUP** - Initialize or configure E2E testing infrastructure: - Set up E2E testing for a new project - Configure docker-compose for testing (Kafka, PostgreSQL, MongoDB, Redis) - Create jest-e2e.config.ts or E2E Jest configuration - Set up test helpers for database, Kafka, or Redis - Configure .env.e2e environment variables - Create test/e2e directory structure **WRITE** - Create or add E2E/integration tests: - Write, create, add, or generate e2e tests or integration tests - Test API endpoints, workflows, or complete features end-to-end - Test with real databases, message brokers, or external services - Test Kafka consumers/producers, event-driven workflows - Working on any file ending in .e2e-spec.ts or in test/e2e/ directory - Use GWT (Given-When-Then) pattern for tests **REVIEW** - Audit or evaluate E2E tests: - Review existing E2E tests for quality - Check test isolation and cleanup patterns - Audit GWT pattern compliance - Evaluate assertion quality and specificity - Check for anti-patterns (multiple WHEN actions, conditional assertions) **RUN** - Execute or analyze E2E test results: - Run E2E tests - Start/stop Docker infrastructure for testing - Analyze E2E test results - Verify Docker services are healthy - Interpret test output and failures **DEBUG** - Fix failing or flaky E2E tests: - Fix failing E2E tests - Debug flaky tests or test isolation issues - Troubleshoot connection errors (database, Kafka, Redis) - Fix timeout issues or async operation failures - Diagnose race conditions or state leakage - Debug Kafka message consumption issues **OPTIMIZE** - Improve E2E test performance: - Speed up slow E2E tests - Optimize Docker infrastructure startup - Replace fixed waits with smart polling - Reduce beforeEach cleanup time - Improve test parallelization where safe Keywords: e2e, end-to-end, integration test, e2e-spec.ts, test/e2e, Jest, supertest, NestJS, Kafka, Redpanda, PostgreSQL, MongoDB, Redis, docker-compose, GWT pattern, Given-When-Then, real infrastructure, test isolation, flaky test, MSW, nock, waitForMessages, fix e2e, debug e2e, run e2e, review e2e, optimize e2e, setup e2e