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 guarantees
Read this before you parse Pacto's output in a script.
jsondescribes a successful result. When a command fails to produce its result, for example because a reference is unreachable orpacto.lockis missing, the error goes to stderr as plain text and stdout stays empty, whatever--output-formatsays. A negative verdict is still a result:pacto validateon an invalid contract andpacto diffon a breaking change both print their whole JSON document to stdout and exit 1. An empty stdout tells you there is nothing to parse. Read stdout when it is non-empty, and read the exit code for the verdict.- Only
pacto diffimplementsmarkdown, for posting a diff as a CI comment. Every other command renders text. - Keys are camelCase in every command (
"path","valid","errors","upToDate"). Before v4,init,validate,pack,pullandpushemitted capitalised keys ("Path","Valid"). - An unrecognised value is rejected.
--output-format yamlexits 1 withunsupported output format "yaml"before the command runs.
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, 1 or 2, apart from pacto run (below). 0 means the
command produced its result and the result was acceptable. 1 means the check
failed or the command could not run, so the exit status alone cannot
distinguish "the check failed" from "the command could not run". 2 means
pacto impact could not show that a breaking change is safe, and no other
command exits 2 for its own result. pacto run exits with the exit code of
the command it wraps, whatever it is, or 1 when that command exits 0 and
the final verdict fails --fail-on.
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 |
pacto impact where the gate is blocked: a BREAKING change reaches a consumer that does not accept the new version and runs on a known target |
pacto impact where the gate is clear: the change is not BREAKING, or the snapshot is complete and no service depends on the changed one |
| any command that could not run, for example on an unresolvable reference, an unreadable bundle or an unknown flag |
Exits 2 |
|---|
pacto impact where the gate is unverified: a BREAKING change that nothing is shown to block, on a partial answer or with consumers none of which is shown to be safe |
Two cases affect CI gates:
- A
pacto diffagainst a missing reference exits1, the same as a breaking change. pacto impactexits1only when the change is breaking and a source that knows where services run shows an incompatible consumer on a target. Sources that know no targets, such as--localalone, cannot show that, so a breaking change with consumers exits2. A job that gates on deployed impact alone can treat2as a pass; any other job fails on it.
Use stdout 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 leaves stdout empty:
| 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: … |
In a script, branch on stdout when it is non-empty, and treat an empty stdout
with exit 1 as a tool failure.
OCI version resolution¶
All commands that accept oci:// references support automatic version resolution. When a reference omits the tag (for example oci://ghcr.io/acme/svc-pacto with no :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.
Resolution ignores non-semver tags such as latest and main. Digest-pinned references (@sha256:...) and explicitly tagged references are used as-is.
Constraints apply to the CLI's dependency graph
The CLI applies compatibility constraints when it resolves a contract's
declared dependencies, for example in pacto graph. The dashboard's
version discovery selects the highest semver tag and ignores per-dependency
compatibility constraints. Root-contract pulls (a tagless top-level oci://
ref) also select the highest semver tag with no constraint.
pacto agent¶
Runs until interrupted. Watches TCP listeners and outbound connection outcomes with an eBPF program, attributes each socket to the workload that created it (a Kubernetes pod, a container, a systemd unit or a pacto run session, from its cgroup, or from its network namespace when the cgroup names none) and publishes a snapshot every --publish-interval. --sink kubernetes writes the node's NodeRuntimeObservation status (pods only; what the Pacto operator's node agent DaemonSet runs); --sink stdout prints one JSON snapshot per line.
--sink local and --sink evidence check workloads against their contracts on this host. The workloads come from --bindings (a YAML list of {match: {unit|container|cgroup|session|pid}, contract, host, interfaces: {name: port}, dependencies: {name: host:port}}) and with --docker from running containers labelled dev.pacto.contract=
Needs Linux 5.11 or later with BTF, or 5.8 or later with BTF and root or CAP_SYS_RESOURCE; root (or BPF, PERFMON and SYS_PTRACE); and the host's /proc and cgroupfs.
Examples:
pacto agent --sink stdout --publish-interval 5s
pacto agent --sink kubernetes --cgroup-root /host/sys/fs/cgroup
pacto agent --sink local --docker --cgroup-root /host/sys/fs/cgroup
pacto agent --sink evidence --bindings bindings.yaml --evidence-url https://evidence.example.com \
--evidence-key agent.key --evidence-key-id k1 --evidence-producer host-1
Flags:
--bindings string with --sink local or evidence: YAML file binding workloads to contracts
--cgroup-root string where the host cgroup v2 hierarchy is mounted; empty attributes by network namespace only (default "/sys/fs/cgroup")
--docker with --sink local or evidence: check running containers labelled dev.pacto.contract (Docker Engine API on /var/run/docker.sock)
--docker-label-filter stringArray with --docker: only check containers that also carry this label (key=value or key; repeatable, all must match), e.g. com.docker.compose.project=demo
--enable-probing also probe the wire protocol of every interface found listening
--evidence-key string with --sink evidence: private key file envelopes are signed with
--evidence-key-id string with --sink evidence: key id (must match the server's trust entry)
--evidence-producer string with --sink evidence: producer id
--evidence-url string with --sink evidence: Evidence Server base URL
-h, --help help for agent
--namespace string namespace the NodeRuntimeObservation is written to with --sink kubernetes (default $POD_NAMESPACE)
--node-name string name of this host; with --sink kubernetes also the NodeRuntimeObservation name (default $NODE_NAME)
--proc-root string where the host /proc is mounted (a pod needs hostPID, a container --pid=host) (default "/proc")
--publish-interval duration how often a snapshot is published (whole seconds) (default 30s)
--resync-interval duration how often workloads, network namespaces and listeners are re-read from /proc (default 1m0s)
--ringbuf-size uint32 kernel ring buffer size in bytes; a power of two and a multiple of the page size (default 262144)
--sink string where snapshots go: one of [kubernetes stdout local evidence] (default "stdout")
--stabilization-window duration how long a negative must persist before it is reported (default 2m0s)
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 over the fleet snapshot: the same
operational graph the CLI's pacto fleet commands query, served as a web UI.
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 contract 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 - cache: enabled if the OCI bundle cache (~/.cache/pacto/oci) holds bundles - k8s: enabled if a kubeconfig or in-cluster config resolves - oci: from the positional arguments, the PACTO_DASHBOARD_REPO env var, or the status.contract.resolvedRef of the cluster's Pacto resources
When running alongside the Kubernetes operator, OCI repositories are automatically discovered from the status.contract.resolvedRef fields of Pacto CRD resources on every refresh. The result combines runtime state from the operator with contract content from OCI.
Every source contributes to one snapshot, rebuilt in the background, and each answer carries the as-of time and the completeness of the sources behind it.
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)
--delivery-namespace string namespace Pacto delivery runs in, whose published identity policy (agent, break-glass and human groups, team prefix) says who is an agent and who may answer (default "pacto-delivery")
--delivery-trust string the trust config delivery records are verified with, so History reads signed records (the recorder's PEM public key or a YAML trust config; default $PACTO_DELIVERY_TRUST)
-h, --help help for dashboard
--host string bind address for the dashboard server (default "127.0.0.1")
--mira-url string Mira's address, to link the health-check citations of delivery verdicts
--namespace string Kubernetes namespace (empty = all namespaces)
--oidc-ca-file string PEM bundle of the CAs that sign the issuer's certificate, trusted on top of the system roots (also PACTO_DASHBOARD_OIDC_CA_FILE)
--oidc-client-id string OpenID Connect client id of the dashboard
--oidc-display-name string the identity provider's name on the sign-in button, as in Sign in with Keycloak (default OIDC; also PACTO_DASHBOARD_OIDC_DISPLAY_NAME)
--oidc-extra-scopes strings scopes to ask for beyond openid, profile and groups
--oidc-groups-claim string ID token claim the API server takes the groups from; must match its claim mapping (default groups)
--oidc-groups-prefix string prefix the API server puts before every group; must match its claim mapping
--oidc-internal-issuer-url string address the dashboard reaches the issuer at when it differs from the public issuer URL browsers use, such as an in-cluster Service; ID tokens must still name the public issuer (also PACTO_DASHBOARD_OIDC_INTERNAL_ISSUER_URL)
--oidc-issuer-url string OpenID Connect issuer people sign in with before the dashboard shows anything; every view then shows what the signed-in person's Kubernetes RBAC lets them read, and every action runs as them (also PACTO_DASHBOARD_OIDC_ISSUER_URL; the client secret comes from PACTO_DASHBOARD_OIDC_CLIENT_SECRET)
--oidc-redirect-url string the dashboard's /auth/callback as browsers reach it (https)
--oidc-username-claim string ID token claim the API server takes the username from; must match its claim mapping (default sub)
--oidc-username-prefix string prefix the API server puts before the username; must match its claim mapping (default the issuer URL and #, none for the email claim; - for none)
--port int port for the dashboard server (default 3000)
--session-idle-timeout duration a session without a request for this long ends (default 1h)
--session-max-age duration a session ends this long after sign-in, renewed or not (default 12h)
--token-login let people sign in by pasting a Kubernetes bearer token, for a cluster whose API server trusts no identity provider; a token session never decides on a held change (also PACTO_DASHBOARD_TOKEN_LOGIN)
--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).
For a tour of what the dashboard surfaces, see For platform engineers; to run it as a container, see Dashboard container.
pacto delivery¶
Pacto delivery decides which version each environment (a Stage) runs. Every change is an Operation: plan it to see what the promoter will do and who must agree, propose it, and a person approves only when the contracts say a consumer would break, Pacto cannot see enough or the Stage asks for approval on every promote.
There is no approve tool for agents. approve is for people.
Flags:
--delivery-namespace string namespace Pacto delivery runs in, whose published identity policy (agent, break-glass and human groups, team prefix) says who is an agent and who may answer (default "pacto-delivery")
-h, --help help for delivery
-n, --namespace string namespace of the Stage and its Operations (default "default")
--trust string the trust config delivery records are verified with: the recorder's PEM public key, or a YAML file of keys and the streams each may sign (default $PACTO_DELIVERY_TRUST)
pacto delivery approve¶
Record your decision on a held operation, as the person your kubeconfig signs you in as. When the promoter asks for a fresh login (delivery.promoter.authFreshness), the command instead makes you log in again in your browser (prompt=login, max_age=0) with its own OpenID Connect client and sends the Approval with that login's token, never your kubeconfig's: an agent running in your shell cannot approve as you without you typing your password at that moment. The token is not stored.
Flags:
--decision string approve, reject or accept-unknown (default "approve")
-h, --help help for approve
--note string why, for the record
--oidc-ca-file string PEM bundle of the CAs that sign the issuer's certificate, trusted on top of the system roots (also PACTO_DELIVERY_OIDC_CA_FILE)
--oidc-client-id string OpenID Connect client used only for approvals, never by a kubeconfig (a confidential client's secret comes from PACTO_DELIVERY_OIDC_CLIENT_SECRET) (default "pacto-approve")
--oidc-extra-scopes strings scopes to ask for beyond openid, profile and groups
--oidc-issuer-url string OpenID Connect issuer the cluster trusts, to log in again with (also PACTO_DELIVERY_OIDC_ISSUER_URL)
--oidc-redirect-port int loopback port the identity provider sends the browser back to (default: a free port)
pacto delivery blame¶
Say who put a version in place on a Stage: who asked, for whom, who approved and what every gate said
Flags:
--digest string the version to blame (defaults to the one the Stage runs)
-h, --help help for blame
--stage string the Stage (required)
pacto delivery cancel¶
Cancel an operation that has not moved the pointer yet
Flags:
pacto delivery candidates¶
List the versions a Stage may be promoted to: what pacto publish published that its candidate source offers
Flags:
pacto delivery describe¶
Show what an operation type checks, when a person is needed and how it is undone
Flags:
pacto delivery explain¶
Explain an operation: where it is, every verdict with its citation and how to run it again
Flags:
pacto delivery get¶
Show an operation: phase, outcome, verdicts and the question a person is asked
Flags:
pacto delivery history¶
List what happened on a Stage, from its signed records when the recorder runs, otherwise from the cluster
Flags:
--all walk every Stage in the namespace given with -n, or in every namespace you can list
-h, --help help for history
--stage string the Stage (this or --all)
pacto delivery plan¶
Predict what the promoter will do: verdicts, the approval floor, the one question for a person and what must move first
Flags:
--cause-verdict pacto delivery explain --output-format json a verdict (JSON, as pacto delivery explain --output-format json prints it) you cite as the cause; the promoter runs it again and refuses a cause that does not hold
--from string where the Stage is now: a digest, or a level for delivery.pacto.trianalab.io/autonomy (defaults to its pointer, or to its current level)
-h, --help help for plan
--on-behalf-of string the person an agent acts for (asserted, not verified)
--reason string why, for the record
--record string for delivery.pacto.trianalab.io/acknowledge: the record id (sha256:...) of the upstream stand-in, as the Stage's Ready message names it
--stage string the Stage to change (required)
--to string where to move: for a pointer type a version (3.0.0), a tag or an artifact digest (sha256:...), where a version or tag must name exactly one version pacto publish published that the Stage may take (list them with pacto delivery candidates); for delivery.pacto.trianalab.io/autonomy a level (observe, advise, auto-nonbreaking or autonomous)
--type string operation type (default "delivery.pacto.trianalab.io/promote")
--undoes string for a rollback: the name of the operation it undoes
pacto delivery propose¶
Propose an operation; with --intent-digest it fails with PlanStale if anything moved since the plan or the reason or on-behalf-of differs
Flags:
--cause-verdict pacto delivery explain --output-format json a verdict (JSON, as pacto delivery explain --output-format json prints it) you cite as the cause; the promoter runs it again and refuses a cause that does not hold
--from string where the Stage is now: a digest, or a level for delivery.pacto.trianalab.io/autonomy (defaults to its pointer, or to its current level)
-h, --help help for propose
--intent-digest string the intent digest from your plan; propose refuses if it no longer matches, so pass the same --to, --reason and --on-behalf-of
--name string the Operation name (generated when empty)
--on-behalf-of string the person an agent acts for (asserted, not verified)
--reason string why, for the record
--record string for delivery.pacto.trianalab.io/acknowledge: the record id (sha256:...) of the upstream stand-in, as the Stage's Ready message names it
--stage string the Stage to change (required)
--to string where to move: for a pointer type a version (3.0.0), a tag or an artifact digest (sha256:...), where a version or tag must name exactly one version pacto publish published that the Stage may take (list them with pacto delivery candidates); for delivery.pacto.trianalab.io/autonomy a level (observe, advise, auto-nonbreaking or autonomous)
--type string operation type (default "delivery.pacto.trianalab.io/promote")
--undoes string for a rollback: the name of the operation it undoes
pacto delivery record¶
Work with the signed records of operations
Flags:
pacto delivery record verify¶
Verify every record of a Stage's stream against the trust config and check the chain
Flags:
--all verify every Stage's stream in the namespace given with -n, or in every namespace you can list
-h, --help help for verify
--stage string the Stage (this or --all)
pacto delivery types¶
List the operation types you may propose
Flags:
pacto delivery undo¶
Plan how to undo an operation; it proposes nothing and prints the command that would
Flags:
-h, --help help for undo
--stage string the operation's Stage, needed only when the Operation was deleted and must be found in the records
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 when the diff could not be produced. A non-zero exit alone is therefore no contract verdict. See Exit codes for how to tell the two apart. A POTENTIAL_BREAKING result exits 0, so a CI gate that stops on it must read the classification.
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: documentation changes produce no diff entries and leave the compatibility classification unchanged.
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 leave the overall classification and exit code unchanged.
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 (Swagger 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 the interactive API explorer (one of: 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. pacto doc reads a bundle and observes no 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. To read configurations and policies, use pacto doc or open pacto.yaml. 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)
--root stringArray contract root whose whole dependency closure joins the snapshot: a local bundle path or an oci:// reference (repeatable)
--target-state stringArray offline target-state fixture file(s) supplying targets, for demos and tests; production targets arrive as signed EvidenceSets (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 in the trace window, so possibly still in use) 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¶
Reports what needs attention: non-compliant, unknown, invalid and stale targets, revisions without readiness, unresolved dependencies and dependencies whose provider version is outside the declared range. With no category flag it reports every category.
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
--unsatisfied-ranges report dependencies whose provider version is outside the declared range (DEPENDENCY_RANGE_UNSATISFIED)
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 which consumers a change really affects, how strong the evidence is and whether their declared compatibility still holds.
When no fleet source holds the changed service, the new revision is added to the snapshot so the services that depend on it are found.
The answer ends in a release gate, and the exit status follows it: 0 clear: the change is not BREAKING, or the snapshot is complete and no service depends on the changed one. 1 blocked: the change is BREAKING and a consumer that does not accept the new version runs on a known target. 2 unverified: the change is BREAKING and nothing is shown to block it, but the answer cannot clear it: the answer is partial, or consumers depend on the service and none is shown to be safe. A run over --local bundles alone knows no targets, so a BREAKING change with consumers exits 2. A command that could not run also exits 1, with nothing on stdout. Add --target-state (or a live source) so the gate can tell deployed impact apart.
Pacto finds consumers only in the sources you pass, such as --local, --root, --oci, --cache, --k8s, --evidence-url and --traces. With --local alone Pacto sees only the contracts in those folders, so "No affected consumers" is not evidence of safety.
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:
--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 impact
--include-observed let observed (runtime) relationships raise consumer confidence
--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)
--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)
--oci stringArray registry reference to include as a published-baseline revision (repeatable)
--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)
--root stringArray contract root whose whole dependency closure joins the snapshot: a local bundle path or an oci:// reference (repeatable)
--target-state stringArray offline target-state fixture file(s) supplying targets, for demos and tests; production targets arrive as signed EvidenceSets (repeatable)
--traces string OTLP/JSON trace file; its observed edges corroborate and surface consumers (implies --include-observed)
pacto init¶
Writes the contract for the service in dir (default: the current folder).
An empty or new folder gets a blank contract with the bundle structure (interfaces/, configuration/). A folder that already holds a service gets a contract read from its Dockerfile and Kubernetes manifests, and a list of what Pacto found and what it could not tell (Unknown). The workload's environment, including the ConfigMaps it reads, becomes a configuration schema with each value as its default. A URL in it that names another service in the cluster becomes a dependency: with that service's contract in --fleet, its bundle and a range from its version; without it, a placeholder range that the comment above it and Unknown name. A readiness, liveness or startup probe becomes a health check.
The contract also gets a publish section, for pacto publish. To describe the service and leave delivery out, pass --describe-only: the contract then has no publish section and needs no signing key. --delivery also writes the cluster pieces: the Pacto resource that checks the running service, and per environment a Stage with the Flux OCIRepository and Kustomization it applies through. Each Stage starts at observe: it plans every new version and moves nothing, and the OCIRepository stays pinned to the tag you deploy, so GitOps keeps applying what it did. The last environment's Stage also asks a person to approve every promote.
--owner is the team's bare name, such as billing: usually the team label on the workload. An AI agent is a service too: its tools are an mcp interface, the model it calls is a dependency and its eval suite is a checks entry; see https://pacto.run/latest/contract-reference/checks/#an-agent-is-a-service.
Several folders are each pactified, with a summary at the end. --cluster drafts a contract for every workload in the namespaces that no Pacto describes yet, in <out>/<namespace>/<name>: its manifests are read from the cluster, and the services its pods were seen calling become dependencies pinned to the version seen running, for you to widen. Drafts are only written, never published, and a draft that is not valid fails the command.
It only adds files and missing .pactoignore lines; any other file already there is yours and is left as it is, so running it twice is safe. --plan shows exactly what would be added and changes nothing.
Examples:
pacto init my-service
pacto init --plan
pacto init --describe-only --owner billing
pacto init --delivery --owner payments --fleet ../contracts
pacto init --delivery --no-transparency-log --insecure-registry
pacto init --delivery --registry-secret registry-creds
pacto init services/checkout services/payments --plan
pacto init --cluster --namespace shop --out drafts
Flags:
--cluster draft a contract for every workload in the cluster that no Pacto describes, reading the current kubeconfig context
--delivery also write the cluster pieces: the Pacto resource, a Stage per environment and its Flux OCIRepository and Kustomization
--describe-only write a contract that only describes the service: no publish section, so no signing key
--env strings environments for --delivery, in promotion order (default [test,prod])
--fleet strings folders of other services' contracts to find the services that use this one
-h, --help help for init
--insecure-registry with --delivery: the Flux OCIRepositories read the registry over plain HTTP (a local registry only)
--name string service name (default: the workload's name, then the folder's)
--namespace strings with --cluster: a namespace to read; repeat it for more (default: every namespace)
--no-transparency-log write transparencyLog: false under publish.sign, so signatures stay out of the public transparency log (offline signing, a throwaway key)
--out string with --cluster: the folder the drafts go in, one <namespace>/<name> folder each
--owner string the team that owns the service, as a bare name such as billing (default: the workload's team label)
--plan show what would be added and change nothing
--registry string where to publish, as host/path (default: read from the workload's image)
--registry-secret string with --delivery: the docker-registry Secret, in each environment's namespace, that Flux and the Pacto resource log in to a private registry with
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: 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 fails validation: 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. If you delete a directory, also delete the section that references it, or validation fails with FILE_NOT_FOUND. A contract that declares neither section needs only pacto.yaml, so drop the section and the directory together.
The scaffold fails validate --readiness on purpose
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, so keep it
and update it.
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 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 reuse credentials from the GitHub CLI, so you can skip pacto login.
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 missing or unauthenticated, pacto moves on 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 exposes a read-only contract catalog: the given roots plus their dependency closure, resolved once at startup and then frozen, so the session keeps its startup view even when a registry tag moves. Roots that fail to resolve stay visible as partial knowledge. The catalog grants no authorization and executes nothing.
With --fleet, the server exposes the read-only operational-graph query tools over one snapshot. The shared fleet source flags (--local, --target-state, --evidence-url, --traces, --oci, --cache, --k8s, --namespace and --freshness) compose that snapshot and are read in --fleet mode only.
With --delivery, the server exposes the Pacto delivery tools (pacto_delivery_*) over the ambient cluster: operation types, plan, get, explain, history, blame, undo plans and record checks, plus propose and cancel only when the apiserver says the caller is an agent (a service account, or an agent by the identity policy Pacto delivery publishes). It has no approve tool.
Over HTTP, --auth-issuer and --resource make every request carry a bearer token the server verifies (issuer, audience, expiry) and publish protected-resource metadata (RFC 9728); a bind beyond loopback needs them and refuses --auth and --allow-writes, which would lend this process's service credential to every caller. With --delivery the server then exchanges each caller's token for one the apiserver accepts (RFC 8693, --exchange-client-id) and builds the tools for that caller on every request, so an agent proposes as itself and a person gets the read-only tools. With --fleet the server names each caller with the claim mapping (--oidc-username-claim, --oidc-username-prefix, --oidc-groups-claim and --oidc-groups-prefix) and asks Kubernetes RBAC about that user; the API server does not confirm it, so the mapping must match its claimMappings.
With --publish, the authoring server also exposes pacto_publish_plan and pacto_publish, which publish a contract's version exactly as pacto publish does, with this process's registry credentials.
A bundle reference, --root, --fleet, --delivery and --publish 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
--audience string with --auth-issuer: the audience incoming tokens must carry (default --resource)
--auth stringArray credential for a security scheme as name=value (repeatable)
--auth-issuer string OpenID issuer whose bearer tokens every HTTP request must carry
--base-url string base URL for live invocation (overrides the OpenAPI servers[] URL)
--cache include every bundle in the local OCI cache as an offline baseline revision
--delivery expose the Pacto delivery tools over the ambient cluster
--delivery-namespace string in --delivery mode: namespace Pacto delivery runs in, whose published identity policy (agent, break-glass and human groups, team prefix) says who is an agent and who may answer (default "pacto-delivery")
--delivery-trust string in --delivery mode: the trust config delivery records are verified with (the recorder's PEM public key or a YAML trust config; default $PACTO_DELIVERY_TRUST)
--evidence-url stringArray base URL of an Evidence Server to consume its read-only operational-graph contribution over HTTP (repeatable)
--exchange-audience string with --delivery over HTTP: the audience to exchange for, one the apiserver accepts (default "pacto-cli")
--exchange-client-id string with --delivery over HTTP: the server's own OAuth client, which exchanges each caller's token for the cluster (RFC 8693); its secret comes from PACTO_MCP_EXCHANGE_CLIENT_SECRET
--fleet expose read-only operational-graph (fleet) query tools
--freshness duration mark target evidence older than this as stale (0 disables)
-h, --help help for mcp
--host string bind address for HTTP transport; beyond loopback it needs --auth-issuer (default "127.0.0.1")
--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)
--oidc-groups-claim string ID token claim the API server takes the groups from; must match its claim mapping (default groups)
--oidc-groups-prefix string prefix the API server puts before every group; must match its claim mapping
--oidc-username-claim string ID token claim the API server takes the username from; must match its claim mapping (default sub)
--oidc-username-prefix string prefix the API server puts before the username; must match its claim mapping (default the issuer URL and #, none for the email claim; - for none)
--port int port for HTTP transport (default 8585)
--publish expose pacto_publish_plan and pacto_publish beside the authoring tools
--resource string with --auth-issuer: this endpoint's URL as clients reach it, served as protected-resource metadata (RFC 9728)
--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) supplying targets, for demos and tests; production targets arrive as signed EvidenceSets (repeatable)
--traces stringArray OTLP/JSON trace file supplying runtime-observed dependency edges, folded into the snapshot as observed relationships (repeatable)
-t, --transport string transport type: stdio or http (default "stdio")
The default server exposes the four authoring tools below. A bundle reference and four flags select a different server, each with its own tools. See Server modes 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 or 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 accept no oci:// refs.
Server modes¶
The default server exposes the authoring tools above. A bundle reference, --root, --fleet, --publish and --delivery each select a different server. Passing more than one is an error:
| 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 --publish |
Authoring tools plus pacto_publish_plan and pacto_publish, which publish a version to your registry. Stdio only. |
pacto mcp --delivery |
Authoring tools plus the delivery tools over the cluster your kubeconfig points at: read delivery state and, for an agent, ask for or cancel a change. There is no approve tool. |
pacto mcp --root <ref> [--root <ref>] |
A read-only contract catalog discovered from the named roots. Catalog mode registers only catalog tools, and none of them 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 every answer reflects startup state even if a registry tag moves. A root that fails to resolve stays visible with a classified reason, and the catalog reports itself as partial. The catalog reads only the named roots and their closure, never refreshes and persists nothing.
Fleet tool arguments¶
The arguments each fleet query tool takes. Arguments are optional unless marked:
| Tool | Arguments |
|---|---|
pacto_fleet_search |
text, owner, status, compliance, workload, scope, source, ready, not_ready, has_capability, has_dependency, limit |
pacto_fleet_get |
service (a logical service) or target (an operational target by key or name) |
pacto_fleet_graph |
service, revision or target to root the traversal, then direction, transitive and max_depth (0 = unlimited) |
pacto_fleet_status |
needs_attention for every category, or any of invalid, non_compliant, unknown, stale, unresolved_deps, unsatisfied_ranges, missing_readiness; plus limit. No category, including empty input, reports every category |
pacto_fleet_explain |
subject (required): a service name or a target key or name |
pacto_impact |
old_ref and new_ref (both required), plus include_observed and traces |
Argument names differ from flag names: the substring filter is text. Every tool above closes its schema, so an unknown argument is an error.
See MCP Integration for setup and the MCP reference for serving a bundle's operations as tools and 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 as a JSON array. Each set's ContractRef is empty because traces carry no contract revision. 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 publish¶
Publishes every artifact the contract's publish section declares (pactoVersion 2.1), the contract bundle and the deploy artifact Flux applies, all tagged with service.version. Docker or the declared command builds. Pacto pushes each artifact to a new tag, signs every digest with Sigstore (built in) and attaches the SBOM files the build wrote. A breaking change since the last published version is refused below a major bump (a minor before 1.0).
--plan shows what is missing and changes nothing. Running publish again from the same commit finishes what is missing and changes nothing else. --propose hands the deploy artifact to Pacto delivery as a promote on a Stage, once the Stage records it as published, meaning Flux polled the candidate OCIRepository and verified the signature. It waits up to --propose-timeout for that.
Examples:
# What would be published, and what refuses it
pacto publish --plan
# The same, for the contract in ./payments
pacto publish --plan ./payments
# Publish, then propose the version on the test Stage
pacto publish --propose test/payments
Flags:
-h, --help help for publish
-p, --path string path to contract directory, the same as [dir] (default: current directory)
--plan show what is missing and what refuses it; change nothing
--propose string after publishing, propose the deploy artifact on <namespace>/<stage> (needs delivery.enabled on the pacto-operator chart)
--propose-timeout duration how long --propose waits for the Stage to record the version as published (default 10m0s)
--revision string source revision stamped on every artifact (default: the git commit of the contract directory, which must have no uncommitted changes)
--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)
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. Pushing the same content again succeeds without writing anything; different content under an existing reference is refused unless --force.
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 tag already holds the same content, pacto push succeeds and writes nothing. If it holds different content, pacto push refuses with a non-zero exit and writes nothing. 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 run¶
Starts the command and watches the TCP sockets of its whole process tree: the interfaces bound with --bind must be listened on, the dependencies bound with --dep reached. Every --interval it prints the contract's compliance and findings in --output-format; once the command exits it prints a final round from the last view taken while the command ran, and exits with the command's exit code. With --fail-on it exits 1 instead of 0 when the final verdict is that bad or worse.
The command runs in a process group of its own, so a Ctrl-C reaches it once. When pacto run owns the terminal, the command's group takes it over: it reads the terminal and gets Ctrl-C and Ctrl-Z straight from it, and pacto run takes the terminal back once it exits. Otherwise SIGINT and SIGTERM sent to pacto run are passed on to the command's whole group.
Pacto leaves the command's stdin, stdout and stderr untouched. Rounds go to stderr, each in a single write, or with --report to a file: the file is truncated when the run starts and every round is appended to it in a single write, so a reader following it sees whole rounds (with json, one object per line).
With root (or BPF, PERFMON, SYS_PTRACE and write access to its own cgroup) on Linux 5.11 or later with BTF and cgroup v2 (or 5.8 or later with BTF and root or CAP_SYS_RESOURCE), the command starts inside a new cgroup pacto-run-<pid> and an eBPF program sees every listener and every connection outcome of the tree, failures included (collector pacto-run+ebpf). Otherwise it falls back to polling /proc every second and says so (collector pacto-run): listeners are seen in full, so a missing one is still confirmed, but a connection is seen only while it is open at a poll and a failed connection never, so a dependency is reported reachable or unknown, never unreachable. If the program attached but the command cannot start inside the new cgroup, the run falls back to polling too and says so. Elsewhere than Linux the command runs unobserved and every runtime assertion is unsupported.
A negative is reported once it persists for --stabilization-window. Health and metrics capabilities are probed on --host at their bound interface's port. With --evidence-url every round is also signed and sent to an Evidence Server, which needs the contract pinned as oci://...@sha256:<digest>.
Examples:
pacto run --contract ./payments --bind api=8080 --dep postgres=127.0.0.1:5432 -- ./payments-server
pacto run --contract oci://ghcr.io/acme/payments:1.4.0 --bind api=8080 --fail-on noncompliant \
--stabilization-window 30s --output-format json --report rounds.jsonl -- java -jar payments.jar
Flags:
--bind stringArray interface=port the command serves the interface on (repeatable)
--cgroup-root string cgroup v2 directory the session cgroup is created in (default: the caller's own cgroup under /sys/fs/cgroup)
--contract string contract bundle directory or oci:// reference (required)
--dep stringArray dependency=host:port the command reaches the dependency at (repeatable)
--enable-probing also probe the wire protocol of every interface found listening
--evidence-key string private key file envelopes are signed with
--evidence-key-id string key id (must match the server's trust entry)
--evidence-producer string producer id
--evidence-url string Evidence Server base URL
--fail-on string exit 1 when the command exits 0 but the final verdict is this bad or worse: one of [none noncompliant unknown] (default "none")
-h, --help help for run
--host string address capability and protocol probes dial (default "127.0.0.1")
--interval duration how often a round is evaluated and printed (whole seconds) (default 10s)
--proc-root string where /proc is mounted (default "/proc")
--report string file every round is appended to instead of stderr (truncated when the run starts)
--ringbuf-size uint32 kernel ring buffer size in bytes; a power of two and a multiple of the page size (default 262144)
--stabilization-window duration how long a negative must persist before it is reported (default 2m0s)
pacto tui¶
Opens a full-screen terminal UI over the same fleet snapshot pacto fleet queries. Navigate services, revisions, targets, owners and sources, then run pacto's verbs against the selection, which becomes the command's argument.
Read verbs run in-process against the loaded snapshot. Write verbs shell out to this same binary so they own the terminal, and every one of them asks for confirmation first. Pass --read-only to hide the write verbs entirely.
Requires an interactive terminal. In a pipeline or CI, use the plain commands.
Examples:
# Browse the local fleet
pacto tui --local .
# Browse a live cluster plus the local bundles, without write verbs
pacto tui --local . --k8s --read-only
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 tui
--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)
--read-only hide every write verb
--root stringArray contract root whose whole dependency closure joins the snapshot: a local bundle path or an oci:// reference (repeatable)
--target-state stringArray offline target-state fixture file(s) supplying targets, for demos and tests; production targets arrive as signed EvidenceSets (repeatable)
--traces stringArray OTLP/JSON trace file supplying runtime-observed dependency edges, folded into the snapshot as observed relationships (repeatable)
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 works only on release 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.
The output has one PASS, FAIL or SKIP line per stage, in order: load, lock, structural, cross-field, policy, environments, guarantees, readiness and closure. The environments stage checks each environment's file against the schema of every configuration it names. Each error sits under its stage with its file:line:column when Pacto can locate it. A failed load or lock stage skips every stage after it, and a failed structural or cross-field stage skips the stages after it up to policy. Any failed stage skips environments. The guarantees, readiness and closure stages run even when an earlier stage fails. The last line, Next:, names the one command to run now. With --output-format json the same comes as stages and next.
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 check the readiness gate (fail if score < minScore)
pacto validate --readiness my-service
# Also check every dependency against this contract's policies
pacto validate --closure my-service
Flags:
--closure also check every contract in the dependency closure against the policies this contract resolves. Fails when a dependency cannot be resolved and warns about deprecated interfaces of direct dependencies. Fetches each dependency once
-h, --help help for validate
--readiness also check 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 checks the contract's structure and rules. It still checks the shape of readiness claims and skips the freshness gate. See the readiness reference for the score and gate semantics.
A contract with a mistyped value fails like this:
svc is invalid
PASS load
SKIP lock no pacto.lock
FAIL structural
svc/pacto.yaml:6:1: ERROR [SCHEMA_VIOLATION] workload: at '/workload': value must be one of 'service', 'job', 'scheduled' (did you mean "service"?)
SKIP cross-field structural failed
SKIP policy structural failed
SKIP environments structural failed
SKIP guarantees no dependency declares requires
SKIP readiness not requested (--readiness)
SKIP closure not requested (--closure)
Next: fix workload at svc/pacto.yaml:6:1 [SCHEMA_VIOLATION], then run pacto validate svc
Errors within a stage are listed in file order. An unknown field or an enum value close to a known one carries a did you mean hint. A failed lock stage names the pacto lock command that repairs it. When every stage passes, Next is pacto impact PUBLISHED_REF <dir>, which shows the services the change breaks; replace PUBLISHED_REF with the oci:// reference of the version you run today. In JSON, stages lists each stage with its status, reason and errors, each error carries line and column when known, file is the file they point into, and next holds the command. errors and warnings still list every stage's findings. With --set or -f an error in pacto.yaml carries no line or column, because those flags validate a merged document whose lines differ from the file. An error in an environment's file keeps them.
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 and 0, f, F, false, FALSE and
False disable them. Any other value, including yes and on,
reads as off with no warning. The two opt-outs PACTO_NO_ANIM and
PACTO_NO_UPDATE_CHECK are the exception: for them any other non-empty value
reads as on.
| 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 |
Boolean. Disables spinners and animations (equivalent to --no-anim). |
PACTO_NO_UPDATE_CHECK |
Boolean. Disables automatic update checks. |
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 that Pacto reaches over plain HTTP. It applies to every registry access: pacto push, pacto pull, dependency and policy resolution and the Evidence Server. Scoped per host, so HTTPS registries are unaffected. Loopback hosts use plain HTTP without being listed. Use it only for a controlled in-cluster registry: 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. The operator sets it when it wires a managed Evidence Server. Unset means no evidence source configured, which the dashboard reports separately from an unavailable source. |
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_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, where NAME is the source's identity (what the fleet, the API and the dashboard's Data Source list call it) and PATH is the trace file location. Identity and location are separate, so reordering the configuration or moving the file keeps the source's name. Two sources whose files share a basename stay two sources. A name must be unique across every Data Source the dashboard assembles. |
The two list variables split on whitespace
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 read directly and splits on
commas.
The dashboard starts either way: it skips a trace file it cannot read, so the symptom is missing observed dependencies with no 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, which persists--usernameand--password) - 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).
Pacto stores no credentials in contract files.