Skip to content

Manifests

Manifests are YAML files that declaratively define entity metadata. They are the recommended way to manage entities at scale, following a GitOps-style workflow where your service catalog is defined alongside your code.

For an exhaustive field-by-field schema reference, see Manifest Model.

Place manifests in your repository at:

.shoehorn/manifest.yml

Shoehorn also discovers manifests matching these patterns (configurable):

  • .shoehorn/**/*.yml
  • .shoehorn/**/*.yaml
  • catalog-info.yaml (Backstage compatibility)
schemaVersion: 1
service:
id: payment-api # Required, kebab-case unique identifier
name: Payment API # Required, display name
type: service # Required, entity type
tier: gold # Optional, service tier
description: |
Handles payment processing, refunds, and transaction management.
owner: # Required (except for catalog-source type)
- type: team
id: payments-team
- type: user
id: alice@company.com
lifecycle: production # Optional
tags: # Optional
- payments
- financial
- critical
links: # Optional
- name: Repository
url: https://github.com/company/payment-api
icon: GitHub
- name: Grafana Dashboard
url: https://grafana.company.com/d/payments
icon: Grafana
relations: # Optional
- type: depends_on
target: service:stripe-integration
- type: depends_on
target: database:payments-db
- type: publishes_to
target: topic:payment-events
- type: part_of
target: system:financial
interfaces: # Optional
http:
baseUrl: https://api.company.com/v1/payments
openapi: docs/openapi.yaml
auth:
type: oauth2
grpc:
package: com.company.payments
proto: proto/payments.proto
services:
- PaymentService
- RefundService
integrations: # Optional
changelog:
path: CHANGELOG.md
runbooks:
- title: Payment Processing Incident
path: docs/runbooks/payment-incident.md
severity: critical
- title: Database Migration
path: docs/runbooks/db-migration.md
severity: high
licenses:
- title: Stripe API
vendor: Stripe
expires: "2025-12-31"
cost: "$2000/year"
docs: # Optional
readme:
path: README.md
extras: # Optional
- type: slackchannel
target: "#payments-team"
FieldRequiredDescription
idYesUnique kebab-case identifier. Must match ^[a-z0-9]+(-[a-z0-9]+)*$
nameYesHuman-readable display name
typeYesEntity type (see Entities)
tierNoService tier: platinum, gold, silver, bronze
membersNoArray of member emails (for team type)

At least one owner is required (except for catalog-source type).

FieldDescription
typeOwner type: team, user, productOwner, designer, stakeholder, support, manager
idTeam slug, user email, or entity reference
FieldRequiredDescription
typeYesRelation type (see below)
targetYesTarget in format <type>:<identifier>
roleNoRole in the relationship
notesNoAdditional context

Relation types: depends_on, publishes_to, consumes_api, provides_api, deployed_to, calls, reads_from, writes_to, subscribes_to, uses, via, part_of

Target types: service, database, topic, team, channel, link, oncall, system, resource

FieldRequiredDescription
nameYesLink display name
urlYesURL (must be http:// or https://)
iconNoIcon name (see Annotations Reference for supported icons)
interfaces:
http:
baseUrl: "https://api.example.com/v1" # HTTP base URL
openapi: "docs/openapi.yaml" # OpenAPI spec path or URL
auth:
type: "oauth2" # oauth2, apikey, none
graphql:
endpoint: "/graphql" # GraphQL endpoint
schema: "schema.graphql" # Schema file
grpc:
package: "com.example.service" # gRPC package
proto: "proto/service.proto" # Proto file path or URL
services: # gRPC service names
- "UserService"
- "AuthService"
integrations:
changelog:
path: "CHANGELOG.md" # Path relative to repository root
integrations:
runbooks:
- title: "Incident Response" # Required
path: "docs/runbook.md" # Optional, file path
severity: "critical" # Optional: critical, high, medium, low
integrations:
licenses:
- title: "Stripe API" # Required
vendor: "Stripe" # Optional
purchased: "2024-01-15" # Optional, ISO date
expires: "2025-01-14" # Optional, ISO date
seats: 1 # Optional, minimum 1
cost: "$2000/year" # Optional
contract: "STRIPE-2024" # Optional
notes: "Auto-renewal" # Optional
FieldRequiredDescription
typeYesslackchannel, teamLinks, custom, catalog-discovery-url, catalog-discovery-file
targetYesValue for the extra (e.g., #channel-name)

Shoehorn can import Backstage catalog-info.yaml files. The following Backstage kinds are supported:

Backstage KindShoehorn Type
Componentservice
APIapi
Resourceresource
Systemsystem
Domaindomain
Group / Userteam
Templatelibrary
Locationcatalog-source

Backstage fields are automatically mapped:

  • metadata.name -> service.id
  • metadata.title -> service.name
  • spec.owner -> owner
  • spec.lifecycle -> lifecycle
  • metadata.tags -> tags
  • metadata.links -> links
  • spec.dependsOn -> relations[type=depends_on]
  • spec.consumesApis -> relations[type=consumes_api]
  • spec.providesApis -> relations[type=provides_api]
Terminal window
curl -X POST https://shoehorn.example.com/api/v1/manifest/validate \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/yaml" \
--data-binary @.shoehorn/manifest.yml

Navigate to Catalog > Validate Manifest and paste or upload your YAML.

See Manifest Validation for details on what the validator checks.

The analyze endpoint provides quality scoring and recommendations:

Terminal window
curl -X POST https://shoehorn.example.com/api/v1/manifest/analyze \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/yaml" \
--data-binary @.shoehorn/manifest.yml

The response includes:

  • Quality score (0-100)
  • Category scores: Documentation, Relationships, Interfaces, Metadata
  • Issues: Warnings and errors
  • Recommendations: Suggested improvements