Skip to main content

PACT Passport — agent ID. Self-certifying identity, holder-bound capabilities, audit receipts.

Project description

PACT Passport

The agent ID.

Tests PyPI Python License

Self-certifying identity, holder-bound capabilities, and unilateral audit receipts for agent-to-agent systems. Three message types — REQ, RES, RES_CHUNK. Everything else is built at the edges.

Status: v0.7.x — Python module renamed pactpact_passport (v0.7.0) to avoid silent shadowing with pact-python, the widely-used contract-testing library. Post-quantum claim softened per external review. CI/release workflows on Node 24. All v0.6 substrate features intact: three-tier trust gradient (passport / visa / refusal) on top of the v0.5 capability layer; spec v1.1 → v1.3; Bugs 1–10 from the v0.1 case-study battery + paper-revision experiments closed at the reference-implementation level; cross-machine Stage 2 runs pending.

  • Migration from v0.6.x: from pact import Xfrom pact_passport import X. PyPI package name (pact-passport) and CLI binary (pact) unchanged.
  • V-tier visa machinery + emit-only protocol_advertisement field (PACT itself never reads or acts on a received advertisement — see spec §16.5).
  • Bugs 6 / 7 / 8 / 9 closed in v0.6.0; Bug 10 (Windows-only gap in the Bug 7 stream-partition fix) closed in v0.6.1 after the CI matrix caught it.
  • 282 tests passing across macOS / Linux / Windows (CI matrix green; some POSIX-only tests skipped on Windows).
  • Stage 2 adversarial probe harness (25 pre-registered probes) ready for cross-machine runs.
  • Full case-study details in docs/EXPERIMENTS.md Part 2.

Breaking changes (v0.5.2 → v0.6): see CHANGELOG.md for the full v0.2 → v0.5.1 history.

  • build_req(cap_envelope=...) without an explicit cap_id now auto-derives cap_id from the envelope, or raises ValueError if the envelope lacks one (v0.5.2; was silent pass).
  • REQs with deadlines further than max_deadline_seconds (default 3600s) in the future are rejected with new fault code deadline_too_far (v0.5.2; bump the constructor arg for long-running streaming intents).
  • DelegationLink gains required-from-v1.3 action_at_step + caveats_at_step fields; pre-v1.3 chains verify at K=2 only with DeprecationWarning. v1.4 will drop pre-v1.3 support — re-issue long-lived multi-hop capabilities before then (v0.6.0, Bug 9 / spec §16.1).
  • cancelled receipt outcome emits on streaming partition; downstream code assuming {completed, failed} only must add a cancelled branch (v0.6.0, #30 / Bug 7).

Overview

PACT Passport is a Python implementation of a minimal trust substrate for agent-to-agent interaction. It sits below orchestration protocols like MCP and A2A as the layer that answers who is this agent, what can they do, and what did they do. Three primitives — self-certifying identity, holder-bound capability tokens, signed messages — plus unilateral audit receipts. No central authority, no shared secrets, no registry.

The reference implementation is ~4,600 LOC in src/pact_passport/. The wire protocol is specified in spec/PACT_v1.md — sufficient for independent implementations. Deterministic test vectors at tests/vectors/pact_v1_vectors.json.

Guarantees

Property Mechanism
Authenticity Every message + receipt signed Ed25519 (PyNaCl). verify_message is fail-closed on malformed input.
Identity agent_id = sha256(alg || base64(pubkey)). Self-certifying; no CA.
Key rotation KERI-style pre-rotation via next_key_digest. First post-rotation message proves continuity.
Authorization Holder-bound capability tokens with append-only caveat chain. Stolen tokens require the holder's private key to present (holder_proof).
Replay safety Mandatory idempotency_key per REQ. Durable cache survives process restart.
Causal ordering refs[] field carries sender-asserted back-references; a cooperative sender forms a causal DAG over message history.
Liveness Mandatory deadline with server-side enforcement and configurable upper bound (default 3600s).
Audit Each side writes its own signed receipt unilaterally. outcome ∈ {completed, failed, cancelled} including stream partition.
Trust gradient Three tiers: passport (full identity), visa (session-scoped attenuated capability for passport-less peers), refusal (opaque, no information leak). v0.6+.

Primitives

Primitive What it is Source
Identity Ed25519 keypair with self-certifying agent_id derived from the pubkey, plus a next_key_digest commitment for KERI-style rotation. src/pact_passport/identity.py
Capability Signed, holder-bound token. Caveats append-only; verifier re-derives action + caveats at each chain step (Macaroons-style). Multi-hop delegation at any depth verifies inline via cap_envelope. src/pact_passport/capability.py
Visa Session-scoped, attenuated capability bound to an ephemeral key. Issued by a gatekeeper to a passport-less counterparty; binds the session, not the identity. src/pact_passport/visa.py
Message REQ / RES / RES_CHUNK (streaming). Mandatory deadline + idempotency_key. refs[] carries sender-asserted causal back-references. src/pact_passport/message.py
Receipt Each side writes its own signed receipt unilaterally — no coordination required. Both receipts share task_ref, so the pair reconstructs a bilateral trace post-hoc. outcome ∈ {completed, failed, cancelled}. src/pact_passport/receipt.py

Non-goals

  • Cross-organization capability chains. v0.6 enforces strict issuer must be self. Cross-org via a trusted_issuers set is post-v0.7.
  • Application-level caveat enforcement. Caveats validate structurally at issue/attenuate; handler-side enforcement is post-v0.7.
  • Cross-machine revocation propagation. Issuer-local only — no CRL, no push-REVOKE.
  • Post-quantum signatures. Ed25519 throughout. Crypto is isolated to one module (crypto.py) — but a real PQ migration changes agent_id derivation, signature/token sizes, the spec, and test vectors. Not a one-line swap; the surface is just contained.
  • Per-token cost accounting. Rate limits via max_invocations only. Token economics belong one layer up.

Install

pip install pact-passport

Or directly from this repo:

pip install git+https://github.com/bene-art/pact-passport.git

Optional extras:

pip install pact-passport[cbor]    # CBOR encoding support
pip install pact-passport[fast]    # Async uvicorn server
pip install pact-passport[lak]     # local-agent-kit integration

The Python module is pact_passport (matches the PyPI distribution name). Import as from pact_passport import PACTAgent. v0.6.x and earlier installed the module as pact, which silently shadowed the pact-python contract-testing library when both were installed — see CHANGELOG migration notes for v0.7.0.

Quick Start

CLI

# Terminal 1: Create and serve an agent
pact init alice
pact serve --agent alice --capabilities get_weather

# Terminal 2: Create another agent, discover, and ask
pact init bob
pact discover
pact ask alice get_weather '{"city": "Chicago"}'
pact receipts

Python API

from pact_passport import PACTAgent

agent = PACTAgent("alice", capabilities=["get_weather"])

@agent.handle("get_weather")
def weather(payload):
    return {"temp": 72, "condition": "clear"}

agent.serve()

Demo

python examples/demo.py

Runs two agents in-process, exchanges a capability-scoped task, and verifies receipts.

CLI Commands

Command Purpose
pact init <name> Create agent identity with pre-rotation key commitment
pact serve Start HTTP server + mDNS broadcast. Flags: --agent NAME, --capabilities a,b,c (comma-separated).
pact discover Find agents on local network
pact ask <target> <action> [payload] Send a task (auto-handshake on first contact)
pact grant <holder> <action> Issue a capability token
pact revoke <cap_id> Revoke a capability
pact caps List issued capabilities
pact rotate Rotate keys using pre-rotation
pact doctor Validate keys, event log, permissions
pact trace <msg_id> Walk the causal message DAG
pact receipts List audit receipts
pact identity Show public identity document
pact peers List known peers

Architecture

crypto.py                All PyNaCl in one module (crypto surface isolated; PQ migration is non-trivial but contained)
identity.py              Ed25519 identity, agent_id, key event log, rotation
capability.py            Token issue, attenuate, verify, multi-hop delegation chains (Macaroons-style re-derivation)
visa.py                  V-tier visa machinery: issuance policy, holder-proof binding, peer-network-id rate limits
message.py               REQ/RES builder, signer, verifier
receipt.py               Unilateral signed audit receipts
store.py                 Filesystem storage (~/.pact/)
transport/
  server.py              HTTP server with CBOR content negotiation
  async_server.py        Optional async server via uvicorn
  client.py              HTTP client with CBOR support
  discovery.py           mDNS via zeroconf
agent.py                 PACTAgent high-level API
cli.py                   `pact` command (13 subcommands)
contrib/
  lak_channel.py         local-agent-kit integration

Features by Release

Last 4 releases below; see CHANGELOG.md for v0.1 → v0.5.4 history.

Release Feature Status
v0.6.0 V-tier visa machinery + emit-only protocol_advertisement field + Bugs 6/7/8/9 closed (per-link parent_cap_id at K≥3, cancelled-receipt on stream partition, rate-limit cap_token binding, rogue-delegator chain re-derivation). Spec v1.1.0-draft → v1.3.0-draft. Stage 2 adversarial probe harness staged. Wire changes — see breaking changes above. Done
v0.6.1 Bug 10 fix: stream-partition transport handler now catches ConnectionError (parent class), covering ConnectionAbortedError (Windows WinError 10053) in addition to BrokenPipeError / ConnectionResetError (POSIX). Caught by CI matrix on the v0.6.0 release push. README polish + EXPERIMENTS.md Part 2 documenting Bugs 6–10. No wire changes. Done
v0.7.0 Python module renamed pactpact_passport to avoid silent shadowing with pact-python (Pact Foundation contract-testing lib, installs as pact too). Post-quantum claim softened per external review. CI/release actions bumped to Node 24 ahead of GitHub's 2026-06-16 force-upgrade. PyPI package name and CLI binary unchanged. Import-path breaking change — see CHANGELOG.md for migration. Done
v0.7.1 README-only patch: v0.7.0's README didn't reflect its own rename (stale src/pact/ paths in Overview + Primitives table; stale Status line still saying v0.6.1; missing v0.7.0 entry in Features-by-Release). No code change. Done

Tests

pip install -e ".[dev,cbor,fast]"
pytest -v

282 tests, 0 xfails. Coverage:

  • Cryptography, identity, key rotation, doctor validation — Ed25519 round-trip, key event log, KERI pre-rotation, store-permission checks.
  • Capabilities — issue, attenuate, verify, multi-hop chains at K ∈ {3, 5, 7, 10}, cap_envelope, append-only caveats, chain re-derivation (Macaroons-style).
  • Messages — REQ / RES / RES_CHUNK, signing, deadline enforcement, idempotency, sender-asserted refs[].
  • Receipts — completed / failed / cancelled, including stream-partition cancellation across POSIX + Windows exception variants.
  • Transport — HTTP, CBOR content negotiation, async (uvicorn), mDNS discovery, slow-loris read-timeout.
  • Integration — two-agent + three-agent delegation, V-tier visa battery (V1–V7), protocol_advertisement no-consumption proof, deep-delegation regression.
  • Stress — 5 race-conditions under concurrent dispatch, PACT_CHAOS=1 chaos mode.
  • CLI smokeinit / identity / caps / grant / revoke / receipts / peers / doctor.
  • End-to-endPACTAgent.ask() happy path / unknown target / failed-receipt-on-error.

Stage 2 adversarial probe harness (25 pre-registered probes) runs standalone, not under pytest — see tests/stage2/.

Platform support

Platform Status
macOS green (CI matrix: macos-latest × Python 3.11 / 3.12 / 3.13)
Linux green (CI matrix: ubuntu-latest × Python 3.11 / 3.12 / 3.13)
Windows 11 green (CI matrix: windows-latest × Python 3.11 / 3.12 / 3.13; some POSIX-only tests skipped)

Concurrency stress mode

Set PACT_CHAOS=1 to inject random delays at race-prone code paths. Useful for catching idempotency / rate-limit races that would otherwise surface 1-in-1000:

PACT_CHAOS=1 pytest -v

Specification

  • Concept document: docs/PACT_Specification.md
  • Formal v1 spec: spec/PACT_v1.md — sufficient for independent implementation
  • Test vectors: tests/vectors/pact_v1_vectors.json — deterministic, reproducible
  • Case study (v0.1.3 + paper-revision through v0.6.1): docs/EXPERIMENTS.md — Part 1 covers 23 stress experiments and 5 bugs in the v0.1.3 era; Part 2 covers paper-revision experiments and 5 additional bugs (Bugs 6–10), including one caught by CI matrix on the v0.6.0 release push.

Theoretical Foundations

Paper Contribution
Saltzer, Reed, Clark — End-to-End Arguments (1984) Push verification to agents, not transport
Waldo et al. — A Note on Distributed Computing (1994) Failure is explicit, never abstracted away
Lamport — Time, Clocks, and the Ordering of Events (1978) Causal ordering via message DAG
Birgisson et al. — Macaroons (2014) Attenuable, context-bound capability tokens
Smith — KERI (2019) Self-certifying identity with pre-rotation
Miller — Robust Composition (2006) Capability discipline, no ambient authority

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pact_passport-0.8.0.tar.gz (105.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pact_passport-0.8.0-py3-none-any.whl (80.0 kB view details)

Uploaded Python 3

File details

Details for the file pact_passport-0.8.0.tar.gz.

File metadata

  • Download URL: pact_passport-0.8.0.tar.gz
  • Upload date:
  • Size: 105.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pact_passport-0.8.0.tar.gz
Algorithm Hash digest
SHA256 ef8e8d0b2999af2a492fa2c5a5984201dd7a63f3b93cea1b29c0c7b14a7750a1
MD5 765ad17a8be6636622e10538431711b1
BLAKE2b-256 783d4d5e2182dc446fe3ffb7631e62e9c83bbcced933c26fa38276264a0af1f3

See more details on using hashes here.

Provenance

The following attestation bundles were made for pact_passport-0.8.0.tar.gz:

Publisher: release.yml on bene-art/pact-passport

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pact_passport-0.8.0-py3-none-any.whl.

File metadata

  • Download URL: pact_passport-0.8.0-py3-none-any.whl
  • Upload date:
  • Size: 80.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pact_passport-0.8.0-py3-none-any.whl
Algorithm Hash digest
SHA256 423115c92ab6d97d9788eb50b321d49fed92f6fbf6f341b85a0ff49d77c02186
MD5 f5a4354a4d5ddfb6277fe90ad893cbe9
BLAKE2b-256 1c23a0907b833e0960e189b18f88722b3f09d2f31622aa940a6ca4213c3f405f

See more details on using hashes here.

Provenance

The following attestation bundles were made for pact_passport-0.8.0-py3-none-any.whl:

Publisher: release.yml on bene-art/pact-passport

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page