CLI Reference¶
Every command accepts -v / --verbose for debug-level logging and --help for detailed usage. --output-format is a global flag taking text (the default), json or markdown.
What --output-format does and does not promise
Read this before you parse Pacto's output in a script.
jsondescribes a successful result. When a command cannot produce its result at all — an unreachable reference, a missingpacto.lock— the error goes to stderr as plain text and stdout stays empty, whatever--output-formatsaid. But a verdict of "no" is a result, not a failure:pacto validateon an invalid contract andpacto diffon a breaking change both print their whole JSON document to stdout and exit 1. So the exit code does not tell you whether there is anything to parse — an empty stdout does. Read stdout when it is non-empty; read the exit code for the verdict.markdownis implemented bypacto diffonly, for posting a diff as a CI comment. Every other command silently renders text instead.- Key casing is not uniform.
pacto validateemits capitalised keys ("Path","Valid","Errors"); every other command emits camelCase ("path","root","upToDate"). Match the command you are calling. - An unrecognised value is ignored, not rejected.
--output-format yamlprints text and no warning — there is no YAML output — so a typo is indistinguishable from success.
The interactive and side-effecting commands (login, logout, update,
mcp, dashboard) inherit the flag from the root command and always emit text.
Global flags¶
--config string config file path
-h, --help help for pacto
--no-anim disable animations
--no-cache disable OCI bundle cache
--output-format string output format (text, json, markdown) (default "text")
-v, --verbose enable verbose output
Exit codes¶
Pacto exits 0 or 1 and nothing else. 0 means the command produced its
result and the result was acceptable; 1 means anything else. Because there is
no third code, the exit status alone never distinguishes "the check failed"
from "the command could not run".
Exits 1 |
Exits 0 |
|---|---|
pacto diff where the overall classification is BREAKING |
a POTENTIAL_BREAKING or NON_BREAKING diff |
pacto validate reporting at least one error |
validation that reported only warnings |
pacto lock --check on a stale lockfile, or with none at all (LOCK_MISSING) |
a lockfile that is up to date |
| any command that could not run — an unresolvable reference, an unreadable bundle, an unknown flag | pacto impact run on declared-only sources, whatever it classifies (see below) |
Two rows deserve emphasis, because both silently break a CI gate:
- A
pacto diffagainst a reference that does not exist exits1exactly like a breaking change does. pacto impactexits non-zero only when the change is breaking and a live source shows an incompatible consumer. With declared-only sources there are no consumers to find, so it printsClassification: BREAKINGand still exits0.
Use stdout, not the exit code, to tell a verdict from a failure. A command that produced a verdict writes it to stdout and puts a one-line summary on stderr. A command that could not run writes nothing to stdout:
| Invocation | Exit | stdout | stderr |
|---|---|---|---|
pacto diff --output-format json OLD NEW (breaking) |
1 |
the full JSON result | breaking changes detected |
pacto diff --output-format json oci://…/absent:1.0.0 NEW |
1 |
empty | old contract: artifact not found: … |
So the rule for a script is: branch on stdout when it is non-empty, and treat an empty stdout with a non-zero exit as a tool failure rather than a verdict.
JSON key casing is not uniform
pacto validate emits Path, Valid and Errors in PascalCase; every other
command emits camelCase (oldPath, classification). One parser will not read
both without allowing for it.
OCI version resolution¶
All commands that accept oci:// references support automatic version resolution. When a reference omits the tag (e.g. oci://ghcr.io/acme/svc-pacto instead of oci://ghcr.io/acme/svc-pacto:1.0.0), pacto queries the registry for available tags and selects the highest semver version.
For dependency references declared with a compatibility constraint, only tags satisfying the constraint are considered. For example, a dependency with compatibility: "^2.0.0" and available tags 1.0.0, 2.0.0, 2.3.0, 3.0.0 resolves to 2.3.0.
Non-semver tags (e.g. latest, main) are ignored during resolution. Digest-pinned references (@sha256:...) and explicitly tagged references are used as-is.
Constraints apply to the CLI's dependency graph, not dashboard discovery
compatibility constraints are applied by the CLI when resolving a contract's
declared dependencies (e.g. pacto graph). The dashboard's version
discovery selects the highest semver tag and does not apply per-dependency
compatibility constraints. Root-contract pulls (a tagless top-level oci://
ref) also select the highest semver tag with no constraint.
pacto completion¶
Generate the autocompletion script for pacto for the specified shell. See each sub-command's help for details on how to use the generated script.
Flags:
pacto dashboard¶
Launches an operational dashboard that aggregates data from all available sources (local filesystem, Kubernetes, OCI registries).
The dashboard is the exploration and observability layer of the Pacto system. It visualizes the same contracts the CLI manages and the operator verifies, organised around four workflows: an operational Overview, the Services inventory, the Operational Graph, and Change analysis.
Each positional argument is a pacto source reference: - oci://registry/repo → OCI registry source (can be repeated) - ./path/to/dir → local filesystem source (at most one)
When no arguments are given, sources are auto-detected: - local: enabled if pacto.yaml is found in the working directory - k8s: enabled if a valid kubeconfig is found and the cluster is reachable - oci: auto-discovered from K8s status.contract.resolvedRef, or via PACTO_DASHBOARD_REPO env var
Materialized bundles on disk (~/.cache/pacto/oci) are used internally by the OCI source to enrich version data (hash, classification, timestamps) without appearing as a separate source. The --no-cache flag skips pre-existing cache at startup but still allows same-session materialization (e.g. fetch-all-versions).
When running alongside the Kubernetes operator, OCI repositories are automatically discovered from the status.contract.resolvedRef fields of Pacto CRD resources. This provides full contract bundles, version history, interfaces, and diffs — without needing explicit OCI arguments. The result is a hybrid view: runtime truth from the operator combined with contract truth from OCI.
Services are grouped by name across sources and merged using priority rules: - Kubernetes for runtime state (contract status, checks, endpoints) - OCI for contract content and version history - Local for in-progress contract changes
Examples:
# Start dashboard with auto-detected sources
pacto dashboard
# Start from a specific directory
pacto dashboard ./services
# Include OCI repositories
pacto dashboard oci://ghcr.io/org/order-service oci://ghcr.io/org/payment-service
# Mix local and OCI sources
pacto dashboard ./services oci://ghcr.io/org/payment-service
# Custom port
pacto dashboard --port 9090
# Specify Kubernetes namespace (default: all namespaces)
pacto dashboard --namespace production
Flags:
--cors-origin string explicit cross-origin allowed to call the API (default: same-origin only)
--diagnostics enable source diagnostics panel in the dashboard UI
-h, --help help for dashboard
--host string bind address for the dashboard server (default "127.0.0.1")
--namespace string Kubernetes namespace (empty = all namespaces)
--port int port for the dashboard server (default 3000)
--trace-source stringArray named offline OTLP/JSON trace source as NAME=PATH, where NAME is its stable data-source identity (repeatable; also PACTO_DASHBOARD_TRACE_SOURCES)
--traces stringArray OTLP/JSON trace file to fold observed dependencies from (repeatable; also PACTO_DASHBOARD_TRACES)
It auto-detects sources: pass OCI repositories as arguments, or run it next to the operator (with a kubeconfig) and it discovers OCI repositories from each Pacto resource's status.contract.resolvedRef. Use --no-cache for a cold start (it skips scanning pre-existing cached bundles; bundles fetched during the session are still cached), and --diagnostics to expose the /api/debug/* endpoints.
For the source model, contract-first merge priority (local > oci > cache) and version-tracking design, see Dashboard architecture. For a tour of what the dashboard surfaces, see For platform engineers; to run it as a container, see Dashboard container.
pacto diff¶
Compares two contracts (local paths or oci:// references) and produces a classified change set (BREAKING, POTENTIAL_BREAKING, NON_BREAKING).
Examples:
# Compare a remote contract with a local one
pacto diff oci://ghcr.io/acme/svc-pacto:1.0.0 my-service
# Markdown output for CI comments
pacto diff --output-format markdown oci://ghcr.io/acme/svc-pacto:1.0.0 my-service
Flags:
-h, --help help for diff
--new-set stringArray set a value on the new contract (e.g. --new-set service.version=2.0.0)
--new-values stringArray values file to merge into the new contract (can be repeated)
--old-set stringArray set a value on the old contract (e.g. --old-set service.version=1.0.0)
--old-values stringArray values file to merge into the old contract (can be repeated)
Exit code: 1 when the overall classification is BREAKING — and also 1 when the diff could not be produced at all, so a non-zero exit is not by itself a contract verdict. See Exit codes for how to tell the two apart. A POTENTIAL_BREAKING result exits 0, so a CI gate that wants to stop on it has to read the classification rather than the exit code.
The diff engine performs deep comparison of referenced OpenAPI specs, detecting changes at the path, method, parameter, request body, and response level. The optional docs/ directory is ignored entirely — documentation changes never produce diff entries or affect compatibility classification.
When both bundles include an sbom/ directory with recognized SBOM files (.spdx.json or .cdx.json), pacto diff reports package-level changes — added, removed, or modified packages (version and license). SBOM changes are informational and do not affect the overall classification or exit code.
When dependencies change between the old and new contracts (version upgrades, additions, or removals), a dependency graph diff section is displayed showing the tree of affected nodes.
See Change Classification for the full rules.
pacto doc¶
Reads a pacto.yaml in the given directory (or oci:// reference) and generates structured Markdown documentation.
Examples:
# Print documentation to stdout
pacto doc my-service
# Write documentation to a file
pacto doc my-service -o docs/
# Serve documentation in the browser
pacto doc my-service --serve
# Serve on a custom port
pacto doc my-service --serve --port 9090
# Launch an interactive API explorer (Scalar UI)
pacto doc my-service --ui swagger
# Select a specific interface
pacto doc my-service --ui swagger --interface public-api
# Point try-it-out requests to a running backend
pacto doc my-service --ui swagger --target http://localhost:3000
# Per-interface target mapping
pacto doc my-service --ui swagger --target public-api=http://localhost:3000 --target admin-api=http://localhost:3001
Flags:
-h, --help help for doc
--interface string interface name to display (used with --ui)
-o, --output string output directory for generated Markdown; a NAME.html value writes a static documentation site to a NAME/ directory instead
--port int port for the documentation server (used with --serve or --ui) (default 8484)
--serve serve the offline dashboard-grade documentation site over a local HTTP server
--set stringArray set a contract value (e.g. --set service.version=2.0.0)
--target stringArray target server URL for try-it-out requests; supports interface=url mapping (used with --ui)
--ui string UI type for interactive API explorer (e.g. swagger)
-f, --values stringArray values file to merge into the contract (can be repeated; last wins)
The header line reports the contract's own state, not a runtime measurement: pacto doc reads a bundle and never observes a cluster. A contract that has never been runtime-evaluated therefore reads status NotEvaluated, and one that declares no workload reads compliance REFERENCE. Both are the expected result for a freshly scaffolded contract — see Compliance states.
Markdown prints to stdout by default. -o DIR writes DIR/<service>.md. -o NAME.html writes a self-contained static documentation site (a directory) that reuses the dashboard UI offline.
--serve serves that static site locally. --ui swagger launches an interactive API explorer.
--serve, --ui and -o are mutually exclusive. Use --interface to pick one OpenAPI interface with --ui. --target and --target iface=url point try-it-out at a backend.
Sibling dependencies are resolved in parallel. OCI bundles cache under ~/.cache/pacto/oci/. --no-cache bypasses the cache.
pacto evidence¶
Produce and verify the signed, versioned envelopes that carry a Pacto EvidenceSet from a remote or disconnected environment to a platform that ingests it. Keys are Ed25519; the wire format is defined by pkg/evidenceenvelope.
Flags:
pacto evidence keygen¶
Writes the private seed to <keyId>.key (base64, 0600) and the public key into --out. With --producer, the public key is written as <producer>__<keyId>.pub, which binds the key to that producer in the trust store — hand that file to the platform. Sign with the SAME --producer and --key-id. With no --producer, a bare <keyId>.pub binds the key to a producer named after the key id (the single-producer default).
Flags:
--force overwrite existing key files instead of failing
-h, --help help for keygen
--key-id string key id (defaults to a fingerprint of the public key)
--out string directory to write the keypair into (default ".")
--producer string producer id to bind the key to (writes <producer>__<keyId>.pub)
pacto evidence send¶
Reads a signed envelope JSON file and POSTs it to an ingestion host's --url. Prints the host's JSON response and exits non-zero on a non-2xx status.
Flags:
pacto evidence serve¶
Starts an HTTP host that accepts signed evidence envelopes at POST /api/evidence/v1/envelopes, verifies them against --trust, evaluates the carried evidence against its resolved contract and publishes accepted records to the contract registry as OCI 1.1 referrers of the exact contract revision each report is about. Every --subject is an immutable oci://<repo>@sha256:<digest> reference; the registry is the only durable store, so the host keeps no local state and survives restarts. GET .../health is an always-200 liveness probe; .../ready reports 503 while a subject cannot be resolved or its referrers enumerated; .../producers advertises trusted producer ids; .../targets exposes the latest accepted targets. Registry credentials come from the same sources as pacto pull. Exactly one server may write to a subject set. Serves until interrupted.
Flags:
-h, --help help for serve
--listen-address string host:port to listen on (supersedes --port)
--port int port to listen on (127.0.0.1); superseded by --listen-address (default 8686)
--producer stringArray advertised trusted producer id (repeatable)
--subject stringArray exact contract revision evidence is stored on: oci://<repo>@sha256:<digest> (repeatable, required)
--trust string trust store: a public-key file or a directory of <keyId>.pub files
pacto evidence sign¶
Reads an EvidenceSet JSON file, wraps it in an Ed25519-signed envelope and prints the envelope JSON. Only --issued-at is non-deterministic (it defaults to now), so pinning it is enough to make re-signing the same evidence produce a byte-identical envelope.
Flags:
-h, --help help for sign
--id string envelope id (defaults to a hash over the API version, producer id, sequence and evidence, so two producers reporting identical evidence never collide)
--issued-at string issued-at timestamp (RFC3339; defaults to now)
--key string path to the private key file
--key-id string producer key id (must match the trust-store entry)
--producer string producer id
--producer-version string producer version (optional)
--sequence uint producer-scoped monotonic sequence; each report must be strictly greater than the producer's last
--ttl duration validity window; 0 disables expiry (default 24h0m0s)
pacto evidence verify¶
Decodes an envelope and verifies its signature, freshness and trust against a --trust public-key file or directory of <keyId>.pub files. Exits non-zero when verification fails.
Flags:
-h, --help help for verify
--trust string trust store: a public-key file or a directory of <keyId>.pub files
pacto explain¶
Parses a pacto.yaml in the given directory (or oci:// reference) and produces a human-readable summary of the service contract.
Examples:
Flags:
-h, --help help for explain
--set stringArray set a contract value (e.g. --set service.version=2.0.0)
-f, --values stringArray values file to merge into the contract (can be repeated; last wins)
What it covers. The text output summarises identity, workload, state, capabilities, interfaces, dependencies and readiness. It does not render configurations or policies — read those with pacto doc, or from pacto.yaml directly. metadata is carried by --output-format json only; the text output omits it.
Readiness output. When the contract declares a readiness section (a pactoVersion: "2.0" feature), explain adds a Readiness block: the derived Score, the Gate result (PASS/FAIL with score / minScore), Earned and Total Weight, the partial credit multiplier, the assessment expires date with countdown (or an Expired state), and a per-check table showing each check's declared status (done/partial/not-done/deferred), category, weight, earned weight, and evidence. The Readiness block also includes a revision-history table when history[] is present. --output-format json includes the same data plus doneCount, partialCount, notDoneCount, deferredCount, and expired (boolean). Readiness status is time-dependent — the score is 0 when the current date is past the assessment-level expires.
pacto fleet¶
Compose contracts, contract revisions and operational targets from local bundles and ingested evidence into a versioned, navigable graph, then search, inspect, traverse and explain it. Every answer reports its as-of time and completeness.
Flags:
--cache include every bundle in the local OCI cache as an offline baseline revision
--evidence-url stringArray base URL of an Evidence Server to consume its read-only operational-graph contribution over HTTP (repeatable)
--freshness duration mark target evidence older than this as stale (0 disables)
-h, --help help for fleet
--k8s include live Pacto CRs from the current Kubernetes cluster as targets
--local stringArray local bundle root(s) to scan (repeatable) (default [.])
--namespace string namespace to read Pacto CRs from with --k8s (empty = all namespaces)
--oci stringArray registry reference to include as a published-baseline revision (repeatable)
--target-state stringArray offline target-state fixture file(s) supplying targets — a demo/test adapter, not the signed EvidenceSet protocol (repeatable)
--traces stringArray OTLP/JSON trace file supplying runtime-observed dependency edges, folded into the snapshot as observed relationships (repeatable)
pacto fleet explain¶
Explain the deterministic reasons for a service or target state
Flags:
pacto fleet get¶
Inspect a logical service or an operational target
Flags:
pacto fleet graph¶
Traverse the operational graph from an explicit root. Give a service name to aggregate across its revisions, or --revision/--target to root an exact revision (never 'latest').
Flags:
--direction string traversal direction (dependencies, dependents) (default "dependencies")
-h, --help help for graph
--max-depth int maximum transitive depth (0 = unlimited)
--revision string root an exact contract revision key
--target string root the revision linked to this target key or name
--transitive traverse transitively (cycle-safe)
pacto fleet reconcile¶
Reconciles what the fleet's contracts declare against what runtime traces prove. Reports matched dependencies, declared-but-not-observed (dormant or unseen — not proof of a dead dependency) and observed-but-not-declared (shadow dependencies).
Examples:
Flags:
-h, --help help for reconcile
--traces string OTLP/JSON trace file supplying observed dependencies (required)
pacto fleet search¶
Search logical services in the fleet
Flags:
--compliance string filter to services with a target of this compliance
--has-capability only services declaring a capability
--has-dependency only services declaring a dependency
-h, --help help for search
--label stringArray filter by label key=value (repeatable)
--limit int maximum results (0 = 100, capped at 500)
--not-ready only services whose readiness gate does not pass (below minScore, expired or undeclared)
--offset int result offset for paging
--owner string filter by owner (team, DRI or contact)
--ready only services whose readiness gate passes (score >= minScore, not expired)
--scope string correlate to a target with this scope
--source string filter by observing source
--status string filter by aggregate status (Compliant, Invalid, NonCompliant, NotEvaluated, Reference, Unknown, Warning)
--workload string filter by workload (service, job, scheduled)
pacto fleet snapshot¶
Emit the whole fleet snapshot
Flags:
pacto fleet status¶
Report services and targets needing attention
Flags:
-h, --help help for status
--invalid report structurally invalid contracts
--limit int maximum results (0 = 200)
--missing-readiness report revisions without a readiness assessment
--needs-attention report every attention category
--non-compliant report non-compliant targets
--stale report targets with stale evidence
--unknown report targets with unknown compliance
--unresolved-deps report unresolved declared dependencies
pacto generate¶
Invokes a pacto-plugin-<name> binary to generate deployment manifests, documentation, or other artifacts from a contract directory or oci:// reference.
Examples:
Flags:
-h, --help help for generate
--option stringArray plugin option as key=value (can be repeated)
-o, --output string output directory (default: <plugin>-output/)
--set stringArray set a contract value (e.g. --set service.version=2.0.0)
-f, --values stringArray values file to merge into the contract (can be repeated; last wins)
pacto generate <plugin> invokes the pacto-plugin-<plugin> binary. See Plugins for plugin discovery, the plugin registry, and the official plugins bundled with Pacto.
pacto graph¶
Resolves the dependency tree from a pacto.yaml in the given directory (or oci:// reference) and displays the graph, cycles, and version conflicts.
Examples:
Flags:
-h, --help help for graph
--only-references Show only config/policy reference edges (no dependencies)
--set stringArray set a contract value (e.g. --set service.version=2.0.0)
-f, --values stringArray values file to merge into the contract (can be repeated; last wins)
--with-references Include config/policy reference edges alongside dependencies
Dependencies resolved from local paths are annotated with [local]. Shared dependencies (referenced by multiple parents) are annotated with (shared).
Reports cycles, version conflicts, and unreachable dependencies.
Sibling dependencies are resolved in parallel. OCI bundles are cached locally in ~/.cache/pacto/oci/ for faster subsequent operations. Use --no-cache to bypass the cache.
pacto impact¶
Composes a semantic contract diff (old→new) with the operational graph to answer what a change's real blast radius is: which consumers are affected, how strong the evidence is and whether their declared compatibility still holds.
Exit status is non-zero when the change is BREAKING and at least one ACTIVE consumer is incompatible with the new version (mirrors pacto diff). Active means the snapshot knows of somewhere that consumer is deployed — at least one operational target. A consumer that is incompatible on paper but is running nowhere the snapshot can see does not fail the command, so a declared-only run over --local bundles alone exits 0 no matter how incompatible it says the consumers are. The Active targets line in the output is the tell: no line, no non-zero exit. Supply targets with --target-state (or query a live fleet with pacto fleet) to make the exit code mean something.
Examples:
# Impact of upgrading a local service against the local fleet
pacto impact ./svc-v1 ./svc-v2 --local .
# Include observed (runtime) evidence and emit JSON
pacto impact oci://ghcr.io/acme/svc:1.0.0 ./svc --include-observed --output-format json
Flags:
--freshness duration mark target evidence older than this as stale (0 disables)
-h, --help help for impact
--include-observed let observed (runtime) relationships raise consumer confidence
--local stringArray local bundle root(s) to scan (repeatable) (default [.])
--new-set stringArray set a value on the new contract (e.g. --new-set service.version=2.0.0)
--new-values stringArray values file to merge into the new contract (can be repeated)
--old-set stringArray set a value on the old contract (e.g. --old-set service.version=1.0.0)
--old-values stringArray values file to merge into the old contract (can be repeated)
--target-state stringArray offline target-state fixture file(s) supplying targets (repeatable)
--traces string OTLP/JSON trace file; its observed edges corroborate and surface consumers (implies --include-observed)
pacto init¶
Creates a new directory with pacto.yaml and the bundle directory structure (interfaces/, configuration/).
Examples:
Flags:
Scaffolds three files: a valid pacto.yaml, a placeholder OpenAPI spec at interfaces/openapi.yaml, and a configuration JSON Schema at configuration/schema.json.
<name> is the service name, not a path: it becomes the directory and service.name, which must match ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$. pacto init fleet/checkout-web therefore scaffolds a bundle that does not validate — service.name gets the whole path and fails SCHEMA_VIOLATION. To scaffold inside a directory, cd there first and pass the bare name.
All three are required by the scaffolded contract, because its interfaces: and configurations: sections point at the other two files. Deleting a directory without also deleting the section that references it fails validation with FILE_NOT_FOUND. A contract that declares neither section needs only pacto.yaml, so drop the section and the directory together.
The scaffold does not pass validate --readiness, by design
Its two placeholder readiness claims are not-done, which scores 0 against the
scaffolded minScore: 80 and fails with READINESS_GATE_UNMET. Plain
pacto validate passes, because the gate is opt-in. Fill the claims in as the
work lands — the placeholder is the starting position of a real assessment, not a
template to delete.
pacto lock¶
Resolves the full transitive dependency and reference closure and writes a committed pacto.lock pinning each to its OCI digest. With --check, verifies the existing lock without writing.
Examples:
Flags:
--check verify pacto.lock is up to date without writing (non-zero exit on drift)
-h, --help help for lock
--set stringArray set a contract value (e.g. --set service.version=2.0.0)
--update re-resolve dependencies to the newest version within their constraint
--update-name stringArray re-resolve only the named dependency, preserving all other pins (repeatable)
-f, --values stringArray values file to merge into the contract (can be repeated; last wins)
See Lockfile for the lock model, drift enforcement, and how .pactoignore keeps a pacto.lock out of a pushed bundle.
pacto login¶
Stores credentials for an OCI registry in ~/.config/pacto/config.json.
Examples:
Flags:
-h, --help help for login
-p, --password string registry password
-u, --username string registry username
Credentials are stored in ~/.config/pacto/config.json (or $XDG_CONFIG_HOME/pacto/config.json), keeping them separate from Docker's configuration.
GitHub Container Registry (ghcr.io)¶
For GitHub registries (ghcr.io and docker.pkg.github.com), pacto can automatically reuse credentials from the GitHub CLI — no pacto login required.
If you already have gh installed and authenticated, pacto will use gh auth token to obtain a token transparently. To verify your setup:
To push container images or packages, your token needs the write:packages scope. If you authenticated gh without it, refresh your scopes:
After this, pacto push oci://ghcr.io/... will work without any additional login step.
If gh is not installed or not authenticated, pacto silently falls back to the next credential source in the chain.
pacto logout¶
Removes credentials for an OCI registry from ~/.config/pacto/config.json.
Examples:
Flags:
pacto mcp¶
Starts a Model Context Protocol (MCP) server exposing Pacto tools for AI agents. Supports stdio (default) and HTTP transports.
When a bundle reference (local directory or oci:// ref) is given, the server also exposes one executable tool per OpenAPI operation in the bundle's openapi interfaces, plus a pacto_skill tool for any skills/*.md domain knowledge. Read-only (GET/HEAD) operations are exposed by default; pass --allow-writes to expose mutating operations.
With --root, the server instead exposes a read-only contract catalog: the given roots plus their dependency closure, resolved once at startup and then frozen, so a registry tag that moves later does not change the session. Roots that do not resolve stay visible as partial knowledge. Discovery is not authorization and nothing in the catalog executes.
A bundle reference, --root and --fleet select different servers and cannot be combined.
Examples:
# Start MCP server over stdio (default)
pacto mcp
# Start MCP server over HTTP
pacto mcp -t http
# Expose a bundle's OpenAPI operations as agent tools
pacto mcp ./my-service --base-url https://api.example.com
# Include mutating operations and an auth credential
pacto mcp oci://ghcr.io/acme/svc:1.0.0 --base-url https://api.example.com \
--auth bearerAuth=$TOKEN --allow-writes
# Expose a contract catalog discovered from explicit roots
pacto mcp --root oci://ghcr.io/acme/platform:1.4.0 --root ./experimental-platform
Flags:
--allow-writes expose mutating operations (POST/PUT/PATCH/DELETE) as tools
--auth stringArray credential for a security scheme as name=value (repeatable)
--base-url string base URL for live invocation (overrides the OpenAPI servers[] URL)
--cache include the local OCI cache as offline baseline revisions (--fleet)
--evidence-url stringArray base URL of an Evidence Server to consume over HTTP for --fleet (repeatable)
--fleet expose read-only operational-graph (fleet) query tools
--freshness duration mark target evidence older than this as stale (--fleet)
-h, --help help for mcp
--k8s include live Pacto CRs from the current Kubernetes cluster (--fleet)
--local stringArray local bundle root(s) for --fleet (repeatable) (default [.])
--namespace string namespace for --k8s (empty = all namespaces)
--oci stringArray registry reference to include as a published-baseline revision for --fleet (repeatable)
--port int port for HTTP transport (default 8585)
--root stringArray contract root to discover a read-only catalog from: a local bundle path or an oci:// reference (repeatable)
--target-state stringArray offline target-state fixture file(s) for --fleet — a demo/test adapter (repeatable)
-t, --transport string transport type: stdio or http (default "stdio")
The default server exposes the four authoring tools below. Three flags select a different server, each with its own tools -- see Server modes immediately after this table:
| Tool | Description |
|---|---|
pacto_create |
Create a new contract from intent-level inputs (name, description, interfaces, runtime semantics). Supports dry run. |
pacto_edit |
Edit an existing contract — add/remove interfaces and dependencies, change runtime, update metadata. Supports dry run. |
pacto_check |
Validate a contract and return errors, warnings, and actionable improvement suggestions. |
pacto_schema |
Return the Pacto format explanation and full JSON Schema reference. |
These four authoring tools operate on local contract directories (they read and write pacto.yaml on disk) and do not resolve oci:// refs.
Server modes¶
The default server exposes the authoring tools above. Three flags select a different server instead, and they cannot be combined — passing more than one is an error, never a silent choice:
| Invocation | Server |
|---|---|
pacto mcp |
Authoring tools. |
pacto mcp <bundle-ref> |
Authoring tools plus the bundle's OpenAPI operations as executable agent tools, alongside a pacto_skill tool for any bundled skills. |
pacto mcp --fleet |
Authoring tools plus read-only operational-graph query tools. |
pacto mcp --root <ref> [--root <ref>] |
A read-only contract catalog discovered from the named roots, and nothing else: catalog mode registers no authoring tools, so nothing reachable in it writes to disk. |
--root is repeatable and takes a local bundle directory or an oci:// reference. The roots and their dependency closure are resolved once, at startup, through the same reference parsing, credentials and cache the rest of the CLI uses; after that the session is frozen, so a tag that moves in a registry does not change any answer. Roots that do not resolve stay visible with a classified reason and the catalog reports itself as partial. Nothing is crawled, nothing is refreshed and nothing is persisted.
See MCP Integration for detailed setup with Claude and other AI tools, Agent capabilities for serving a bundle's operations as tools, and Contract catalog discovery for the catalog surface.
pacto otel¶
Observe runtime dependencies from OpenTelemetry traces
Flags:
pacto otel observe¶
Reads an OTLP/JSON trace export and derives the service dependency edges its outbound spans prove. By default it prints the observed edges as text; add --output-format json for machine-readable output. With --evidence it emits one EvidenceSet per calling service -- a JSON array, and each set's ContractRef is empty because traces do not name a contract revision. Signing is therefore not a pipe: pacto evidence sign reads one EvidenceSet from a file, so write the array out, split it, and set each ContractRef to the revision it describes before signing (pacto evidence sign) and reporting (pacto evidence send).
Examples:
pacto otel observe traces.json
pacto otel observe traces.json --evidence --output-format json > sets.json
Flags:
--evidence emit signable EvidenceSets instead of raw edges
-h, --help help for observe
--source string collector/source name recorded as provenance (default "otel")
pacto pack¶
Validates the contract in the given directory and creates a tar.gz archive of the bundle, ready for distribution.
Examples:
Flags:
-h, --help help for pack
-o, --output string output file path (default: <name>-<version>.tar.gz)
--set stringArray set a contract value (e.g. --set service.version=2.0.0)
-f, --values stringArray values file to merge into the contract (can be repeated; last wins)
The contract is validated before packing. If validation fails, no archive is created.
Files matched by .pactoignore are excluded from the archive — see Packaging ignore.
pacto pull¶
Pulls a contract bundle from the specified OCI reference and extracts it to a local directory.
Examples:
# Pull a specific version
pacto pull oci://ghcr.io/acme/my-service-pacto:1.0.0
# Pull the latest available version
pacto pull oci://ghcr.io/acme/my-service-pacto
Flags:
pacto push¶
Validates the contract (including remote policy and config refs), builds an OCI artifact, and pushes it to the specified registry reference.
Examples:
# Push with auto-tag (uses contract version)
pacto push oci://ghcr.io/acme/my-service-pacto -p my-service
# Push with explicit tag
pacto push oci://ghcr.io/acme/my-service-pacto:latest -p my-service
# Force overwrite an existing artifact
pacto push oci://ghcr.io/acme/my-service-pacto -p my-service --force
Flags:
-f, --force overwrite existing artifact in registry
-h, --help help for push
-p, --path string path to contract directory (default: current directory)
--set stringArray set a contract value (e.g. --set service.version=2.0.0)
--values stringArray values file to merge into the contract (can be repeated; last wins)
If the artifact already exists in the registry, pacto push prints a warning and exits successfully without pushing. Use --force to overwrite.
--values has no -f shorthand on push
On every other override-taking command -f is the shorthand for --values. On pacto push, -f is --force, so --values must be spelled out in full here.
pacto update¶
Downloads and installs the specified version of pacto. If no version is given, updates to the latest release.
Examples:
Flags:
Note
pacto update is not available on dev builds. If you built from source without version injection, install a release build first.
Update notifications¶
When a newer version is available, pacto displays a notification after any command:
The check runs asynchronously and adds no latency. Results are cached for 24 hours in ~/.config/pacto/update-check.json.
Notifications are suppressed when:
- Running a dev build
- Using
--output-format jsonor--output-format markdown(the notice shows only for text output) - The
PACTO_NO_UPDATE_CHECK=1environment variable is set
pacto validate¶
Validates a pacto.yaml in the given directory (or oci:// reference) against the specification, running the three validation layers: structural, cross-field, and policy.
Examples:
# Validate a local contract
pacto validate my-service
# Validate from current directory
pacto validate
# Validate from an OCI registry
pacto validate oci://ghcr.io/acme/my-service-pacto:1.0.0
# JSON output
pacto validate --output-format json my-service
# Also enforce the readiness gate (fail if score < minScore)
pacto validate --readiness my-service
Flags:
-h, --help help for validate
--readiness also enforce the readiness gate: fail if the derived readiness score is below the declared (or default 100) minScore. Opt-in because gate evaluation is time-dependent (check expiry is compared against the run time), which would otherwise make plain validation non-deterministic
--set stringArray set a contract value (e.g. --set service.version=2.0.0)
-f, --values stringArray values file to merge into the contract (can be repeated; last wins)
The --readiness gate is opt-in because it is time-dependent: it compares the assessment's single readiness.expires date against the run time, which would make plain validate non-deterministic. Expiry is declared once for the whole assessment — individual claims carry no expires field, and adding one fails to load with PARSE_ERROR. Without the flag, validation only checks the contract's structure and rules (readiness checks are still validated for shape, but the freshness gate is not enforced). See the readiness reference for the score and gate semantics.
Exit code: Non-zero if validation fails.
pacto version¶
Prints the current pacto version.
Examples:
Flags:
Environment variables¶
Boolean variables are parsed the way Go parses a boolean: 1, t, T,
true, TRUE and True enable them. Anything else — including yes and
on — reads as off, silently. The two exceptions are called out in the table.
| Variable | Description |
|---|---|
PACTO_CACHE_DIR |
Cache directory for the pacto dashboard bundle scan. The core CLI cache location is controlled by XDG_CACHE_HOME (see below). |
PACTO_NO_CACHE |
Boolean. Disable OCI bundle caching (equivalent to --no-cache) |
PACTO_NO_ANIM |
Any non-empty value disables spinners and animations (equivalent to --no-anim). PACTO_NO_ANIM=0 also disables them. |
PACTO_NO_UPDATE_CHECK |
Exactly 1 disables automatic update checks. No other value has any effect. |
PACTO_REGISTRY_USERNAME |
Registry username for authentication |
PACTO_REGISTRY_PASSWORD |
Registry password for authentication |
PACTO_REGISTRY_TOKEN |
Registry token for authentication |
PACTO_INSECURE_REGISTRIES |
Comma-separated registry hosts the Evidence Server may reach over plain HTTP instead of HTTPS. Scoped per host, so HTTPS registries are unaffected, and scoped to the evidence commands — pacto push and pacto pull do not read it. Loopback hosts are already plain HTTP without being listed. Intended for a controlled in-cluster registry, never the public internet: it disables transport encryption, so credentials and payloads travel in the clear. |
PACTO_EVIDENCE_SOURCE_URL |
Base URL of an Evidence Server whose read-only operational-graph contribution pacto dashboard should consume. Set by the operator when it wires a managed Evidence Server; unset means no evidence source configured, which is not the same as an unavailable one. |
XDG_CONFIG_HOME |
Override config directory (default: ~/.config). Affects pacto login credentials and update check cache |
XDG_CACHE_HOME |
Override cache directory (default: ~/.cache). Affects OCI bundle cache location |
Dashboard environment variables¶
The following variables configure the dashboard when set (see also Dashboard Container). Each mirrors the flag named beside it: an explicitly passed flag wins, and otherwise the variable overrides that flag's default.
| Variable | Flag | Description |
|---|---|---|
PACTO_DASHBOARD_REPO |
(positional args) | Comma-separated OCI repositories, used only when no positional oci:// argument is given |
PACTO_DASHBOARD_HOST |
--host |
Bind address (default: 127.0.0.1) |
PACTO_DASHBOARD_PORT |
--port |
HTTP port (default: 3000) |
PACTO_DASHBOARD_NAMESPACE |
--namespace |
Kubernetes namespace filter (empty = all) |
PACTO_DASHBOARD_DIAGNOSTICS |
--diagnostics |
Boolean. Expose the /api/debug/* endpoints and the source diagnostics panel |
PACTO_DASHBOARD_CORS_ORIGIN |
--cors-origin |
One explicit origin allowed to call the API. Unset means same-origin only. |
PACTO_DASHBOARD_TRACES |
--traces |
OTLP/JSON trace files to fold observed dependencies from |
PACTO_DASHBOARD_TRACE_SOURCES |
--trace-source |
Named offline trace sources as NAME=PATH |
The two list variables split on whitespace, not commas
PACTO_DASHBOARD_TRACES and PACTO_DASHBOARD_TRACE_SOURCES go through the
same generic flag binding as every other dashboard variable, which splits a
multi-valued string on spaces. PACTO_DASHBOARD_TRACES="a.json b.json" supplies
two files; PACTO_DASHBOARD_TRACES=a.json,b.json supplies one, named
a.json,b.json. PACTO_DASHBOARD_REPO is the odd one out — it is read
directly and does split on commas.
Neither mistake stops the dashboard: a trace file it cannot read is skipped and the server still starts, so the symptom is missing observed dependencies rather than an error. Check the snapshot's reported limitations if the operational graph looks emptier than you expect.
Authentication¶
Pacto follows this credential resolution chain:
- Environment variables (
PACTO_REGISTRY_TOKEN, orPACTO_REGISTRY_USERNAME+PACTO_REGISTRY_PASSWORD) - Pacto config (
~/.config/pacto/config.json, written bypacto login— where--username/--passwordare persisted) - GitHub CLI (
gh auth token, forghcr.ioanddocker.pkg.github.comonly) - Docker config (
~/.docker/config.json) and credential helpers (including cloud-registry helpers for ECR, GCR and ACR) - Anonymous fallback
For GitHub registries, step 3 means you can skip pacto login entirely if you have gh authenticated with the write:packages scope (see pacto login above).
No credentials are ever stored in contract files.