Service catalog drift detection for multi-service repositories.
svccat reads your declared service manifest and compares it against what actually exists in the repo, flagging missing services, undeclared additions, and stale metadata before they become operational toil. It runs in your terminal and in CI, so your declared architecture stays honest.
cargo install svccatThis puts a svccat binary on your PATH. (Or clone the repo and run
cargo build --release; the binary lands at target/release/svccat.)
After installing, see svccat work immediately with the built-in demo, which runs a narrated walkthrough against a throwaway sample repo (no setup, nothing touched in your own files):
svccat demoThen point it at your own repo:
cd my-monorepo
svccat init # scaffold services.yaml from the services already in the repo
svccat check # report drift between the manifest and the repoAnd gate CI on a clean catalog:
svccat check --fail-on-drift # exits 1 when drift is foundInside GitHub Actions, svccat check automatically emits inline PR annotations.
Commands are grouped by task. Run svccat <command> --help for the full flags of any
command.
Set up a manifest
svccat initscaffolds aservices.yamlfrom your repo (--forceto overwrite), inferring each service'slanguageandplatformfrom files it finds on disksvccat import --from backstage|docker-compose|openapiseeds it from another sourcesvccat lintvalidates the manifest for structural issuessvccat install-hooksinstalls a pre-commit hook (--hook pre-pushfor pre-push)svccat completions bashprints a shell completion script (alsozsh,fish)
Check for drift
svccat checkinspects drift in the current reposvccat check --fail-on-driftexits 1 on any drift (CI gate)svccat check --depth 2also discovers services nested one level deepersvccat check --team platformlimits the check to one team's servicessvccat check --since HEAD~1 --fail-on-new-driftexits 1 only on new driftsvccat check --pingverifies that each serviceurlis reachable
Add --format <fmt> to change the output, where <fmt> is one of compact, csv,
json, sarif, markdown, junit, github-annotation, slack, teams, or datadog.
Fix drift
svccat fixadds undeclared services to the manifest, inferringlanguageandplatformfor each (--pruneremoves missing ones,--dry-runpreviews)
Visualize and report
svccat graphrenders a Mermaid diagram (--format dot|plantuml|markdown,--team,--filter)svccat reportwrites a full ownership and drift report (--format html,--history N,--badge)svccat scorecardscores each service on completeness, drift, and policysvccat statsprints a field-coverage summary with ASCII bar charts
Snapshots and diffs
svccat export --format json > snap.jsonsaves a catalog snapshot (formats:json,csv,markdown,backstage-yaml,spdx-json)svccat diff before.json after.jsoncompares two snapshotssvccat snapshot save|list|delete|diff <name>manages named drift snapshots
SBOM export
svccat export --format spdx-json --output sbom.spdx.jsonemits an SPDX 2.3 JSON document: one package per service,supplierfromteam, andDESCRIBESplusDEPENDS_ONrelationships fromdepends_onsvccat snapshot save pre-migration --sbomwrites.svccat/snapshots/pre-migration.spdx.jsonbeside the snapshot;snapshot deleteremoves both
Watch and serve
svccat watchre-runs drift detection on every file change (--notify,--interval 30)svccat serveserves a live HTML report at http://localhost:7777 (--port,--refresh)
Audit, policy, and CI
svccat auditruns lint + drift + score in one pass (add--ping)svccat policychecks required/recommended fields (add--fail-on-violations)svccat ciruns lint + drift + policy in one CI-friendly pass
Query the catalog
svccat search authsearches by substring;svccat search team:platformby fieldsvccat depsanalyzes inter-service dependencies (--format mermaid|json)svccat tag add|remove <service> <tag>edits tags
Multiple repositories
svccat workspace checkchecks drift across every repo in a[workspace]section ofsvccat.toml, with aggregated reporting and cross-repo dependency analysis
Manifest is auto-detected: svccat tries svccat.yaml, svccat.yml, services.yaml,
services.yml in order. Most commands accept --output <file> and --format json.
# svccat.yaml (or services.yaml)
version: "1"
discovery: # optional: where to look for services
paths: ["services/*", "microservices/*"]
markers: [Cargo.toml, go.mod, package.json, pyproject.toml, Dockerfile]
ignore: ["services/vendor/*"]
policy: # optional: fields every service must declare (error if missing)
require_fields: [url, language, platform]
services:
- name: api-gateway # required
language: Go
platform: Cloud Run
role: Rate-limiting reverse proxy # required (error if missing)
url: https://gateway.example.com # enables --ping health checks
team: platform # optional ownership
oncall: platform@example.com
docs: docs/api-gateway.md # optional: warn if the file is missing
depends_on: [auth-service] # rendered as graph edges; validated for cyclesDeclared services are matched to the repo by path:, then submodule:, then by name
against discovered directories. When discovery.paths is empty, svccat tries
services/*, microservices/*, apps/*, and packages/*.
| Kind | Severity | Description |
|---|---|---|
declared_missing_from_repo |
error | Declared in the manifest but its directory is missing. |
undeclared_in_repo |
warning | A service directory exists but is not in the manifest. |
missing_field |
error / warning | A recommended field is absent (role = error; language, platform = warning). |
missing_referenced_file |
warning | A docs: or ci: path is declared but the file is missing. |
policy_violation |
error | A field required by policy.require_fields is absent. |
dangling_dependency |
error | A depends_on entry references an undeclared service. |
circular_dependency |
error | A cycle was detected in the depends_on graph. |
Errors and warnings both count toward --fail-on-drift.
svccat ships as both a binary and a library, so you can call into the same modules the CLI uses:
use std::path::Path;
use svccat::{discovery, drift, manifest::Manifest};
let manifest = Manifest::load(Path::new("services.yaml"))?;
let discovered = discovery::discover_services(Path::new("."), &manifest);
let report = drift::analyze(&manifest, &discovered, Path::new("."));
println!("{} errors, {} warnings", report.error_count(), report.warning_count());See examples/demo.rs (cargo run --example demo) and the API docs
on docs.rs/svccat.
svccat <command> --helpdocuments every command and flag.- CHANGELOG.md for release history.
- SECURITY.md for the threat model and supported versions.
svccat is free and open source. If it saves you some toil, you can buy me a coffee:
Bug reports and pull requests welcome. Please run cargo clippy -- -D warnings and
cargo fmt before opening a PR.
MIT. See LICENSE.