Manifest Model
This page is the exhaustive reference for Shoehorn’s native manifest schema, schemaVersion: 1. Use it when you need the full object model for .shoehorn/manifest.yml, not just a quick-start example.
File Location
Section titled “File Location”Shoehorn looks for manifests in these common locations:
.shoehorn/manifest.yml.shoehorn/**/*.yml.shoehorn/**/*.yamlcatalog-info.yamlfor Backstage compatibility
Top-Level Fields
Section titled “Top-Level Fields”| Field | Required | Type | Notes |
|---|---|---|---|
schemaVersion | Yes | integer | Must be 1 |
annotations | No | object | String key-value metadata |
integrations | No | object | Changelog, runbooks, licenses |
description | No | string | Top-level description |
service | Yes | object | Core entity identity |
owner | Yes* | array | At least one owner, except catalog-source |
lifecycle | No | string | Lifecycle stage |
tags | No | array | Lowercase kebab-case tags |
links | No | array | External links |
interfaces | No | object | HTTP and gRPC metadata |
relations | No | array | Entity relationships |
extras | No | array | Slack channels, discovery pointers, custom extras |
docs | No | object | Documentation paths |
Complete Example
Section titled “Complete Example”schemaVersion: 1
annotations: github.com/project-slug: acme/payment-api pagerduty.com/service-id: P123456
integrations: changelog: path: CHANGELOG.md runbooks: - title: Payment API incident response path: docs/runbooks/payment-api.md severity: critical licenses: - title: Stripe API vendor: Stripe purchased: "2026-01-15" expires: "2027-01-14" seats: 1 cost: "$2000/year" contract: STRIPE-2026 notes: Auto-renews unless canceled
description: Handles payment authorization, capture, and refunds.
service: id: payment-api name: Payment API type: service tier: gold description: Public-facing payments backend members: - payments-oncall@example.com - payments-techlead@example.com
owner: - type: team id: payments-team - type: manager id: jane@example.com
lifecycle: production
tags: - payments - critical - pci
links: - name: Repository url: https://github.com/acme/payment-api icon: GitHub - name: Grafana url: https://grafana.example.com/d/payment-api icon: Grafana
interfaces: http: baseUrl: https://api.example.com/payments openapi: docs/openapi.yaml version: v1 auth: type: oauth2 rateLimits: requestsPerMinute: 600 requestsPerHour: 10000 graphql: endpoint: /graphql schema: schema/payment-api.graphql grpc: package: acme.payments.v1 proto: proto/payment.proto services: - PaymentService - RefundService protos: - proto/payment.proto - proto/refund.proto
relations: - type: depends_on target: database:payments-db notes: Primary OLTP database - type: publishes_to target: topic:payment-events - type: part_of target: system:payments-platform
extras: - type: slackchannel target: "#payments" - type: catalog-discovery-file target: .shoehorn/manifest.yml
docs: readme: path: README.mdservice
Section titled “service”The service block defines the entity’s identity and type.
| Field | Required | Type | Notes |
|---|---|---|---|
id | Yes | string | Lowercase kebab-case, unique within the tenant |
name | Yes | string | Human-readable display name |
type | Yes | string | Entity type |
tier | No | string | Importance or criticality tier |
description | No | string | Alternative to top-level description |
members | No | array | Email addresses, mainly for team entities |
Supported service.type values:
apiservicefrontenddatabaselibraryteamextrassystemresourcecatalog-sourcedomain
Supported service.tier values:
platinumgoldsilverbronzecriticalhighmediumlow
owner is an array of owner references. Each item has the same shape:
| Field | Required | Type | Notes |
|---|---|---|---|
type | Yes | string | Owner role or owner kind |
id | Yes | string | Team slug, email address, or other identifier |
Common owner types:
teamuserproductOwnerdesignerstakeholdersupportmanager
owner is required for every entity except catalog-source.
annotations
Section titled “annotations”annotations is a free-form string map for metadata that does not belong in the structured model.
Example:
annotations: github.com/project-slug: acme/payment-api backstage.io/techdocs-ref: dir:.integrations
Section titled “integrations”integrations groups optional metadata about changelogs, runbooks, and commercial licenses.
integrations.changelog
Section titled “integrations.changelog”| Field | Required | Type | Notes |
|---|---|---|---|
path | No | string | Path relative to repository root |
integrations.runbooks[]
Section titled “integrations.runbooks[]”| Field | Required | Type | Notes |
|---|---|---|---|
title | Yes | string | Display name |
path | No | string | Path relative to repository root |
severity | No | string | critical, high, medium, low |
integrations.licenses[]
Section titled “integrations.licenses[]”| Field | Required | Type | Notes |
|---|---|---|---|
title | Yes | string | License or contract name |
vendor | No | string | Vendor name |
purchased | No | string | ISO date string |
expires | No | string | ISO date string |
seats | No | integer | Minimum value 1 |
cost | No | string | Human-readable cost |
contract | No | string | Contract identifier |
notes | No | string | Free-form notes |
lifecycle
Section titled “lifecycle”Supported lifecycle values:
productionstagingdevelopmentdeprecatedexperimental
tags must be lowercase kebab-case strings.
Example:
tags: - payments - internal-apilinks[]
Section titled “links[]”Each link object has this shape:
| Field | Required | Type | Notes |
|---|---|---|---|
name | Yes | string | Display label |
url | Yes | string | Must start with http:// or https:// |
icon | No | string | Optional icon name |
interfaces
Section titled “interfaces”interfaces exposes API and protocol metadata.
interfaces.http
Section titled “interfaces.http”| Field | Required | Type | Notes |
|---|---|---|---|
baseUrl | No | string | Base URL for the HTTP API |
openapi | No | string | File path or URL |
version | No | string | Version label, for example v1 |
auth.type | No | string | oauth2, apikey, none |
rateLimits.requestsPerMinute | No | integer | Requests per minute |
rateLimits.requestsPerHour | No | integer | Requests per hour |
rateLimits.requestsPerDay | No | integer | Requests per day |
graphql.endpoint | No | string | Path or URL |
graphql.schema | No | string | Path or URL |
interfaces.grpc
Section titled “interfaces.grpc”| Field | Required | Type | Notes |
|---|---|---|---|
package | No | string | gRPC package name |
proto | No | string | Single proto path or URL |
services | No | array | Service names |
protos | No | array | Multiple proto paths or URLs |
relations[]
Section titled “relations[]”Each relation object has this shape:
| Field | Required | Type | Notes |
|---|---|---|---|
type | Yes | string | Relation type |
target | Yes | string | <type>:<identifier> |
notes | No | string | Extra context |
Supported relation types:
depends_onpublishes_toconsumes_apiprovides_apideployed_tocallsreads_fromwrites_tosubscribes_tousesviapart_of
Supported relation target prefixes:
service:database:topic:team:channel:link:oncall:system:resource:
extras[]
Section titled “extras[]”extras is for metadata that does not fit the main model but still belongs on the entity.
| Field | Required | Type | Notes |
|---|---|---|---|
type | Yes | string | Extra type |
target | Yes | string | Value for that extra |
Supported extra types:
slackchannelteamLinkscustomcatalog-discovery-urlcatalog-discovery-file
The docs block currently supports README discovery:
| Field | Required | Type | Notes |
|---|---|---|---|
readme.path | Yes | string | Path relative to repository root |
descriptioncan live at the top level or insideservice.description.docs.readme.path,integrations.changelog.path, andintegrations.runbooks[].pathare relative to the repository root.- Backstage
catalog-info.yamlfiles can be imported, but Shoehorn’s native manifest model is the schema on this page.
See Also
Section titled “See Also”- Manifests - Quick-start manifest guide
- Manifest Validation - Schema rules and common validation failures
- Repository Ownership - How GitHub ownership signals interact with manifests