CLI Validator
The shoehorn validate command validates catalog manifests and Forge mold definitions before you commit, push, or apply them. Use it locally, in pre-commit hooks, and in CI to catch errors early.
There are two validators:
| Command | What it validates | Needs server? |
|---|---|---|
shoehorn validate [file] | Shoehorn or Backstage catalog manifests | Yes (calls the Shoehorn API) |
shoehorn validate mold [file] | Forge mold YAML definitions | No — fully offline |
Both commands support reading from a file, a directory path, or stdin via -, and can emit plain text or JSON.
Validating Catalog Manifests
Section titled “Validating Catalog Manifests”shoehorn validate validates Shoehorn or Backstage-format manifest files. Format is auto-detected.
# Validate a manifest file (text output)shoehorn validate catalog-info.yaml
# Validate with JSON outputshoehorn validate .shoehorn/service.yml --format json
# Validate from stdincat catalog-info.yaml | shoehorn validate -| Flag | Default | Description |
|---|---|---|
--format | text | Output format: text or json |
Exit codes
Section titled “Exit codes”| Code | Meaning |
|---|---|
0 | Manifest is valid |
1 | Validation errors found, or I/O error |
Example output
Section titled “Example output”Text (valid):
v catalog-info.yaml is validText (invalid):
x catalog-info.yaml has validation errors:
- spec.owner: is required - metadata.name: must be lowercase and kebab-caseJSON:
{ "file": "catalog-info.yaml", "valid": false, "errors": [ { "field": "spec.owner", "message": "is required" }, { "field": "metadata.name", "message": "must be lowercase and kebab-case" } ]}- The file (or stdin) is capped at 10 MB to prevent memory exhaustion.
- The command uses your active CLI profile credentials (
shoehorn auth login) because it calls the Shoehorn validation API. Use--profileto validate against a specific environment.
Validating Forge Molds
Section titled “Validating Forge Molds”shoehorn validate mold validates Forge mold definitions offline — no server is contacted. It checks YAML syntax, required fields, step structure, action and adapter names, and approval flow constraints.
# Validate a moldshoehorn validate mold .shoehorn/molds/create-repo.yaml
# JSON output for CI parsingshoehorn validate mold my-mold.yaml --format json
# Treat warnings as failuresshoehorn validate mold my-mold.yaml --strict
# From stdincat my-mold.yaml | shoehorn validate mold -| Flag | Default | Description |
|---|---|---|
--format | text | Output format: text or json |
--strict | false | Fail (non-zero exit) if any warnings are reported |
What the mold validator checks
Section titled “What the mold validator checks”Errors (always fail the command):
- YAML syntax is parseable
- Top-level fields:
version,metadata.nameare present - At least one of
stepsoractionsis defined - Each step has an
idandname, and exactly one ofactionoradapter(not both) - No duplicate step IDs across
stepsandrollback.steps - Action IDs are at least two dot-separated parts (e.g.
github.repo.create) and the provider is one ofgithub,deployment,system,catalog,repo - Adapter names are one of the known adapters:
http,postgres,slack,github,docker,kubernetes,terraform,webhook,email,s3,gcs,file,git,catalog,log - Approval flow constraints:
auto_approve_afteris at least3600seconds (1 hour) when set- At most
10approval steps - Each approval step has a
nameand at least one approver, with at most50approvers per step
Warnings (only fail with --strict):
- Missing recommended
metadata.displayName,metadata.description, ormetadata.category - Action IDs that use a valid provider but aren’t on the known built-in actions list (treated as custom actions)
Example output
Section titled “Example output”Text (valid with a warning):
v create-repo.yaml is valid
warnings: - metadata.description: is recommended for discoverabilityText (invalid):
x create-repo.yaml has errors:
errors: - steps[0].id: is required - steps[1]: must have either action or adapter, not both - approvalFlow.auto_approve_after: must be at least 3600 seconds (1 hour), got 600JSON:
{ "file": "create-repo.yaml", "valid": false, "errors": [ { "field": "steps[0].id", "message": "is required" }, { "field": "steps[1]", "message": "must have either action or adapter, not both" } ], "warnings": [ { "field": "metadata.description", "message": "is recommended for discoverability" } ]}Exit codes
Section titled “Exit codes”| Code | Meaning |
|---|---|
0 | Mold is valid (and, with --strict, has no warnings) |
1 | Errors found, --strict mode found warnings, or I/O error |
Using the Validator in CI
Section titled “Using the Validator in CI”Because both commands return a non-zero exit code on failure and support JSON output, they drop into any CI system. A minimal GitHub Actions job:
name: Validate catalog
on: [pull_request]
jobs: validate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Install shoehorn CLI run: | curl -fsSL https://github.com/shoehorn-dev/shoehorn-cli/releases/latest/download/shoehorn-linux-amd64 \ -o /usr/local/bin/shoehorn chmod +x /usr/local/bin/shoehorn
- name: Validate catalog manifests env: SHOEHORN_TOKEN: ${{ secrets.SHOEHORN_TOKEN }} run: | shoehorn auth login --server https://shoehorn.example.com shoehorn validate catalog-info.yaml --format json
- name: Validate molds (offline, strict) run: | for f in .shoehorn/molds/*.yaml; do shoehorn validate mold "$f" --strict doneThe mold validator runs fully offline, so it doesn’t need SHOEHORN_TOKEN — you can run it on any branch, including from forks.
Related
Section titled “Related”- CLI Getting Started — install and authenticate the CLI
shoehorn convert— convert between Shoehorn, Backstage, and Mold formats