Skip to main content

ZAP Python

Docs: ZAP Python SDK · part of the ZAP Protocol

zap-proto is the Python implementation of ZAP (Zero-Copy App Proto): a zero-copy binary wire format plus a small RPC layer for AI-agent communication.

The core — the wire codec, router envelope, JSON framing, RPC client/server, identity, and consensus — is pure standard library. import zap pulls no third-party dependency.

Installation

pip install zap-proto
# or
uv add zap-proto

Optional extras:

pip install "zap-proto[crypto]"  # real ML-KEM-768 / ML-DSA-65 / X25519
pip install "zap-proto[app]"     # the FastMCP-style decorator app (pydantic)

Wire format (the core)

The zero-copy codec is byte-for-byte compatible with the canonical Go runtime (zap-proto/go) — the same 16-byte ZAP\x00 header, the same fixed-offset struct layout. A buffer this library writes is read by Go and vice versa.

from zap import Builder, parse

# Build a message: field @0 uint32, @8 text, @16 bytes.
b = Builder()
obj = b.start_object(24)
obj.set_uint32(0, 0xDEADBEEF)
obj.set_text(8, "zap")
obj.set_bytes(16, b"\x01\x02\x03\x04")
obj.finish_as_root()
buf = b.finish()

# Read it back with zero copy.
root = parse(buf).root()
assert root.uint32(0) == 0xDEADBEEF
assert root.text(8) == "zap"
assert root.bytes(16) == b"\x01\x02\x03\x04"

Lists (flat fixed-stride and variable-element) and nested objects are supported; the reader rejects out-of-bounds and backward pointers that would alias the wire header, and clamps list lengths — so an adversarial buffer that Go rejects is rejected here too.

RPC

A real request/response transport over TCP, dispatching the Zap interface method ordinals declared in zap.zap.

Server (decorator app — needs [app])

from zap import ZAP, PromptMessage

app = ZAP("my-agent", version="1.0.0")

@app.tool
def search(query: str, limit: int = 10) -> list[dict]:
    """Search for content in the knowledge base"""
    return [{"title": f"Result for {query}", "score": 0.95}]

@app.resource("file://{path}")
def read_file(path: str) -> str:
    """Read a file from disk"""
    return open(path).read()

@app.prompt
def greeting(name: str) -> list[PromptMessage]:
    """Generate a personalized greeting"""
    return [PromptMessage(role="assistant", content=f"Hello, {name}!")]

if __name__ == "__main__":
    app.run(port=9999)  # serves real ZAP RPC

Client

from zap import Client

with Client("localhost:9999") as client:
    info = client.connect()
    tools = client.list_tools()
    result = client.call_tool("search", {"query": "hello world"})
    print(result.content)            # bytes
    content = client.read_resource("file:///tmp/test.txt")
    print(content.text)

Router client

ZapClient talks to the local zapd router over its Unix domain socket (byte-compatible with zap-proto/zapd's frame codec). Used by hanzo-tools-browser's zapd_consumer.

from zap import ZapClient, frame

c = ZapClient.connect(id="consumer:hanzo-mcp/123", role="consumer")
providers = c.providers_list(kind="browser")
reply = c.route(to=providers[0].id, payload=frame.encode_cmd("Target.getTargets", {}))

Post-quantum cryptography (needs [crypto])

Real ML-KEM-768 (FIPS 203) + ML-DSA-65 (FIPS 204) via pqcrypto, classical X25519 via cryptography, mixed with HKDF-SHA256. There is no silent fallback: if a backend is missing, every operation raises CryptoError.

from zap import HybridKeyExchange

alice = HybridKeyExchange.generate()
bob = HybridKeyExchange.generate()

a_x_pub, a_k_pub = alice.initiate()
b_x_pub, ciphertext, bob_secret = bob.respond(a_x_pub, a_k_pub)
alice_secret = alice.finalize(b_x_pub, ciphertext)

assert alice_secret == bob_secret  # both sides agree

Capabilities

zap.cap is the capability runtime — signed, attenuable tokens of authority, a faithful port of zap-proto/go/cap. A Cap grants a holder a permissions bitmask over a target, issued by an issuer; caps form a chain and Verifier.verify_chain walks back to a root.

from zap import cap

signer = cap.Ed25519Signer.generate()
root = cap.issue(
    cap.Issuance(
        kind=int(cap.CapKind.IAM_SESSION),
        permissions=cap.PERM_ATTENUATE,  # may exercise *and* delegate
        expires_at=2_000_000_000,
    ),
    signer,
)
# Narrower child: permissions intersect, expiry only shrinks, parent must carry
# PERM_ATTENUATE (or be a CapKind.DELEGATE cap).
child = cap.attenuate(root, child_holder, cap.PERM_AUDIT, None, 0, signer)

issue / attenuate enforce the SPEC §2.3 delegation gate at mint time; Verifier.verify / verify_chain enforce the full invariants with fail-closed scheme dispatch (reserved tag 0x00 and unknown tags refused, never downgraded). cap.id is SHA-256(canonical_bytes ‖ Sig) and canonical_bytes is the SPEC §3 signed scope — both byte-identical to the Go, Rust, and TypeScript runtimes (pinned by a cross-language known-answer test). Schemes: Ed25519 (mandatory bootstrap), ML-DSA-65 (FIPS 204), secp256k1 ECDSA — all real; a missing crypto backend raises SchemeUnavailable (fail-closed). Wire / canonical / CapID are pure stdlib; signing needs the [crypto] extra. The capability layer ships in all four reference runtimes (Go, Python, Rust, TypeScript).

Promise pipelining

zap.pipeline is the canonical Target-based pipelining model — the byte-for-byte Python peer of Go's rpc.Session / rpc.Pipeliner and TypeScript's Session / Pipeliner. A call carries a promise_id; a dependent call sets target to a prior call's promise_id, and the server substitutes that prior call's resolved body as the dependent's payload before dispatch — so the dependent ships without waiting for the first answer to round-trip.

from zap import Session, Pipeliner, build_request

sess = Session()
srv = Pipeliner(dispatch)              # dispatch(envelope) -> response envelope

p = sess.next()                        # A: authenticate (target = NO_TARGET)
a = srv.handle(build_request(sess.origin(p, AUTH_ORDINAL, cap_token, auth_req)))
q = sess.next()                        # B: pipeline on A's answer
b = srv.handle(build_request(sess.pipeline(q, p, GET_ORDINAL, cap_token, b"")))

The Pipeliner queues a dependent whose target has not resolved yet, refuses (STATUS_BAD_REQUEST) one whose target answered non-OK or was finished, and never hangs. The build_request / build_response envelope is byte-identical to Go's rpc.BuildRequest / BuildResponse and TypeScript's buildRequest / buildResponse, so a pipelined exchange round-trips between all three. (Rust's zap-rpc implements the richer capnp PromisedAnswer superset.)

Agent consensus

from zap import AgentConsensus, Query, Response, DID, DIDMethod

consensus = AgentConsensus()
agent = DID(method=DIDMethod.KEY, id="z6MkAgent...")

query = Query.create("What is the capital of France?", agent)
consensus.submit_query(query)

Related packages

License

MIT

Metadata

Release files for zap-proto 1.4.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for zap-proto 1.4.1
File Size Uploaded
zap_proto-1.4.1.tar.gz 99.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for zap-proto 1.4.1
File Interpreter ABI Platform
zap_proto-1.4.1-py3-none-any.whl Python 3 none any Details

Total release size: 161.4 kB

Release files / zap_proto-1.4.1.tar.gz

Download URL zap_proto-1.4.1.tar.gz
Size 99.8 kB
Tags Source
SHA-256 checksum
How to use checksums
32965a0c1d10c6532b294e531497e519292bf63638c00f1d83211268330777c7
BLAKE2b-256 checksum
How to use checksums
7d7b37543decb0ec4d55781307a5a00a52e974f0a114cc9b042dfd42b0a57154
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Release files / zap_proto-1.4.1-py3-none-any.whl

Download URL zap_proto-1.4.1-py3-none-any.whl
Size 61.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
21b440ed1c5d265edc5fa267dc88b042f240b7a2e8b8509aaec1d8a3fb41fea6
BLAKE2b-256 checksum
How to use checksums
b7ebbec558b662a24149d8a266b34bb655e6ce08c08118cd2bb2aa866b4e5421
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Release history Release notifications | RSS feed

This release

1.4.1 This release

2 release files

1.4.0

2 release files

1.2.0

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page