Skip to content

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.

  • json describes a successful result. When a command fails to produce its result, for example because a reference is unreachable or pacto.lock is missing, the error goes to stderr as plain text and stdout stays empty, whatever --output-format says. A negative verdict is still a result: pacto validate on an invalid contract and pacto diff on 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 diff implements markdown, 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, pull and push emitted capitalised keys ("Path", "Valid").
  • An unrecognised value is rejected. --output-format yaml exits 1 with unsupported 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 diff against a missing reference exits 1, the same as a breaking change.
  • pacto impact exits 1 only 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 --local alone, cannot show that, so a breaking change with consumers exits 2. A job that gates on deployed impact alone can treat 2 as 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=, dev.pacto.bind.<interface>=<port> and dev.pacto.dep.<dependency>=. Interfaces and dependencies are judged from the kernel's view, health and metrics capabilities by probing the bound port; a negative is reported once it persists for --stabilization-window. --sink local prints every target's compliance and findings each interval in --output-format; --sink evidence signs each target's evidence and sends it to an Evidence Server, which needs contracts pinned as oci://...@sha256:<digest>. Envelope sequences start at the wall clock in nanoseconds and count up, so they keep increasing across restarts as long as the clock does.

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.

pacto agent [flags]

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.

pacto completion [flags]

Flags:

  -h, --help   help for completion

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.

pacto dashboard [sources...] [flags]

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.

pacto delivery [flags]

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.

pacto delivery approve <operation> [flags]

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

pacto delivery blame [flags]

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

pacto delivery cancel <operation> [flags]

Flags:

  -h, --help   help for cancel

pacto delivery candidates

List the versions a Stage may be promoted to: what pacto publish published that its candidate source offers

pacto delivery candidates [flags]

Flags:

  -h, --help           help for candidates
      --stage string   the Stage (required)

pacto delivery describe

Show what an operation type checks, when a person is needed and how it is undone

pacto delivery describe <type> [flags]

Flags:

  -h, --help   help for describe

pacto delivery explain

Explain an operation: where it is, every verdict with its citation and how to run it again

pacto delivery explain <operation> [flags]

Flags:

  -h, --help   help for explain

pacto delivery get

Show an operation: phase, outcome, verdicts and the question a person is asked

pacto delivery get <operation> [flags]

Flags:

  -h, --help   help for get

pacto delivery history

List what happened on a Stage, from its signed records when the recorder runs, otherwise from the cluster

pacto delivery history [flags]

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

pacto delivery plan [flags]

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

pacto delivery propose [flags]

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

pacto delivery record [flags]

Flags:

  -h, --help   help for record

pacto delivery record verify

Verify every record of a Stage's stream against the trust config and check the chain

pacto delivery record verify [flags]

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

pacto delivery types [flags]

Flags:

  -h, --help   help for types

pacto delivery undo

Plan how to undo an operation; it proposes nothing and prints the command that would

pacto delivery undo <operation> [flags]

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).

pacto diff <old> <new> [flags]

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.

pacto doc [dir | oci://ref] [flags]

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.

pacto evidence [flags]

Flags:

  -h, --help   help for evidence

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).

pacto evidence keygen [flags]

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.

pacto evidence send <envelope.json> [flags]

Flags:

  -h, --help         help for send
      --url string   ingestion host envelope endpoint URL

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.

pacto evidence serve [flags]

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.

pacto evidence sign <evidence.json> [flags]

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.

pacto evidence verify <envelope.json> [flags]

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.

pacto explain [dir | oci://ref] [flags]

Examples:

  pacto explain my-service

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.

pacto fleet [flags]

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

pacto fleet explain <subject> [flags]

Flags:

  -h, --help   help for explain

pacto fleet get

Inspect a logical service or an operational target

pacto fleet get [service] [flags]

Flags:

  -h, --help            help for get
      --target string   inspect an operational target by key or name

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').

pacto fleet graph <service> [flags]

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).

pacto fleet reconcile [flags]

Examples:

  pacto fleet reconcile --traces traces.json --local .

Flags:

  -h, --help            help for reconcile
      --traces string   OTLP/JSON trace file supplying observed dependencies (required)

Search logical services in the fleet

pacto fleet search [text] [flags]

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

pacto fleet snapshot [flags]

Flags:

  -h, --help   help for snapshot

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.

pacto fleet status [flags]

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.

pacto generate <plugin> [dir | oci://ref] [flags]

Examples:

  pacto generate schema-infer my-service --option file=config.yaml -o out/

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.

pacto graph [dir | oci://ref] [flags]

Examples:

  pacto graph my-service
  pacto graph --with-references
  pacto graph --only-references

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.

pacto impact <old> <new> [flags]

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.

pacto init [dir...] [flags]

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.

pacto lock [dir] [flags]

Examples:

  pacto lock
  pacto lock --update
  pacto lock --update-name auth
  pacto lock --check

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.

pacto login <registry> [flags]

Examples:

  pacto login ghcr.io -u my-username

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:

# Check if gh is authenticated
gh auth status

# Verify the token is available
gh auth token

To push container images or packages, your token needs the write:packages scope. If you authenticated gh without it, refresh your scopes:

gh auth refresh --scopes write:packages

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.

pacto logout <registry> [flags]

Examples:

  pacto logout ghcr.io

Flags:

  -h, --help   help for logout

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.

pacto mcp [bundle-ref] [flags]

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

pacto otel [flags]

Flags:

  -h, --help   help for otel

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).

pacto otel observe <traces.json> [flags]

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.

pacto pack [dir] [flags]

Examples:

  pacto pack my-service

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.

pacto publish [dir] [flags]

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.

pacto pull <ref> [flags]

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:

  -h, --help            help for pull
  -o, --output string   output directory (default: service name)

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.

pacto push <ref> [flags]

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>.

pacto run --contract <dir|oci ref> [flags] -- command [args...]

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.

pacto tui [flags]

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.

pacto update [version] [flags]

Examples:

  # Update to the latest release
  pacto update

  # Update to a specific version
  pacto update v1.1.0

Flags:

  -h, --help   help for update

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:

A new version of pacto is available: v1.0.0 -> v1.2.0
Run 'pacto update' to update.

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 json or --output-format markdown (the notice shows only for text output)
  • The PACTO_NO_UPDATE_CHECK=1 environment 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.

pacto validate [dir | oci://ref] [flags]

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.

pacto version [flags]

Examples:

  pacto version

Flags:

  -h, --help   help for version

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:

  1. Environment variables (PACTO_REGISTRY_TOKEN, or PACTO_REGISTRY_USERNAME + PACTO_REGISTRY_PASSWORD)
  2. Pacto config (~/.config/pacto/config.json, written by pacto login, which persists --username and --password)
  3. GitHub CLI (gh auth token, for ghcr.io and docker.pkg.github.com only)
  4. Docker config (~/.docker/config.json) and credential helpers (including cloud-registry helpers for ECR, GCR and ACR)
  5. 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.