JACS Python Library
Cryptographic identity, signing, and verification for AI agents from Python.
This source version requires Python 3.11–3.14, including optional integrations. Published 0.15.0 wheels support Python 3.10–3.14; use the source requirement when building this checkout.
Published 0.15.0:
jacsremains a supported native Python library. Wheel platforms, installed-package checks and provenance are recorded in the release inventory. Its separate native workspace remains buildable through the root Makefile and CI.
python -m pip install jacs==0.15.0
Supported wheels need no Rust toolchain.
First use of the jacs command
The first jacs command downloads the matching CLI release, verifies SHA-256,
and caches it by version and platform. Importing or using the library downloads
nothing. No musl CLI archive is published; unsupported platforms or verification
failures exit nonzero. The fallback is cargo install jacs-cli.
If the Python shim shadows Cargo's binary, invoke ~/.cargo/bin/jacs directly
(or %USERPROFILE%\.cargo\bin\jacs.exe on Windows). With CARGO_HOME set, use
its bin directory instead.
Full documentation | Python Quick Start
Quick start
import jacs.simple as jacs
info = jacs.quickstart(name="my-agent", domain="my-agent.example.com")
signed = jacs.sign_message({"action": "approve", "amount": 100})
result = jacs.verify(signed.raw)
print(f"Valid: {result.valid}, Signer: {result.signer_id}")
quickstart() creates a persistent agent with encrypted keys on disk. If
jacs.config.json exists, it loads it. Preserve the password through your host
secret source or keychain for later processes; an automatically generated
password is otherwise retained only in-process. See the
password guide.
Core operations
| Operation | Description |
|---|---|
quickstart(name, domain) |
Create or load a persistent agent |
load() |
Load an existing agent from config |
sign_message() |
Sign JSON-serializable data |
sign_file() |
Sign a file with optional embedding |
verify() |
Verify a signed document |
verify_standalone() |
Verify without loading an agent |
create_agreement_v2() |
Create a standalone Agreement v2 document |
sign_agreement_v2() |
Sign as signer, witness, or notary |
verify_agreement_v2() |
Inspect Agreement v2 hashes, signatures and claimed status |
export_agent() |
Export agent JSON for sharing |
audit() |
Run a security audit |
Public human-approved document verification
The wheel build profile enables human-approval-vendored: the existing native
WebAuthn verifier with OpenSSL compiled into the extension, without a separate
OpenSSL installation. maturin develop uses this same profile. This configures
new builds; it does not claim that an older published wheel has the method.
Release gates check the installed artifact and reject external OpenSSL linkage.
Browser WASM does not provide this verifier.
from jacs import SimpleAgent
report = SimpleAgent.verify_human_approved_document(
bundle_json, expected_json, authority_json, provenance_json
)
This static method needs no agent, signing key, configuration, or network
lookup. All four arguments are JSON strings. Read stored public evidence into
bundle_json; select the expected human/action/credential and the two public
key pins from your application's trusted state, not from the bundle. The
complete report is a dict. Success confirms retained proof and document
integrity, not permission to execute now: current remains
not_evaluated. Live authorization, revocation and one-use checks stay with
the relying application.
Request authentication and signed events
The instance-based SimpleAgent exposes the transport protocol helpers. Build
the header from the exact request values that will be sent:
import json
from jacs import SimpleAgent
agent, _ = SimpleAgent.ephemeral() # default pq2025
body = '{"action":"approve"}'
authorization = agent.build_request_auth_header(
"POST",
"https://api.example.com/v1/jobs?mode=strict",
body,
"jobs-api",
)
assert authorization.startswith("JACS v2.")
envelope = agent.sign_response(json.dumps({"decision": "allow"}))
signer_id = json.loads(envelope)["jacsSignature"]["agentID"]
server_keys = json.dumps({signer_id: agent.get_public_key_pem()})
verified = json.loads(agent.unwrap_signed_event(envelope, server_keys))
assert verified["verified"] is True
assert verified["data"]["decision"] == "allow"
build_request_auth_header() accepts bytes for arbitrary request bodies or str
(encoded as UTF-8), and binds the exact bytes with method, absolute URL
including query, audience, signer/key, issue time, and nonce. Do not serialize
the body again after building the header. sign_response() emits a 2.0.0
envelope whose jacs-response-v2 signature covers both payload and metadata.
unwrap_signed_event() is fail-closed: plain events, legacy payload-only
envelopes, unknown signers, and mutations raise instead of returning data.
For multi-replica consumers,
await unwrap_signed_event_with_replay_store(agent, envelope, server_keys, store)
requires an application-owned shared atomic replay store implementing the
Python store protocol. It fails closed on
duplicates, expiry or store failure. See replay-store deployment
and the signed-event contract
before releasing verified payloads.
The server_keys object is a trust decision, not discovery: each key must be
pinned or resolved under the application's configured policy. Successful
verification proves possession of that key; it does not independently prove a
person, organization, domain, or other real-world identity.
The old no-argument build_auth_header() remains available for source
compatibility and emits a WARN because it does not bind the request. Migrate
clients and servers together to JACS v2; strict deployments can reject the
legacy method with JACS_REJECT_UNBOUND_AUTH_HEADER=true.
Text and image provenance
Python exposes the same inline text and image signing surface as the CLI:
import jacs.simple as jacs
from jacs import MissingSignatureError
jacs.load("./jacs.config.json")
# Markdown/text: append and verify an inline signature block.
jacs.sign_text("README.md")
text = jacs.verify_text("README.md")
print(text.status) # 'signed' | 'missing_signature' | 'malformed'
try:
jacs.verify_text("README.md", strict=True)
except MissingSignatureError:
print("not signed")
jacs.verify_text("README.md", key_dir="./trusted-keys/")
# Images: embed and verify a signature in PNG, JPEG, or WebP metadata.
jacs.sign_image("photo.png", "signed.png")
image = jacs.verify_image("signed.png")
print(image.status) # 'valid'
payload = jacs.extract_media_signature("signed.png")
The same methods are available on the instance-based JacsClient for multi-agent processes. These signatures prove that an agent signed specific canonical bytes at its claimed time; they do not prove first creation or legal ownership.
Verify without an agent
result = jacs.verify_standalone(signed_json, key_directory="./keys")
JACS uses a shared signed-document format across bindings. See the release evidence for installed-consumer checks and their limits.
Agreement v2
Use Agreement v2 to inspect native compatibility agreement documents:
from jacs import SimpleAgent
agent, info = SimpleAgent.ephemeral() # default pq2025
agent_id = info["agent_id"]
agreement = agent.create_agreement_v2({
"title": "Refund approval",
"description": "Approval for a bounded refund.",
"terms": "Refund up to $25 for order 123.",
"status": "proposed",
"parties": [{"agentId": agent_id, "agentType": "ai", "role": "signer"}],
"signaturePolicy": {"partyQuorum": "all", "witnessRequired": 0, "notaryRequired": 0},
"controllers": [agent_id],
})
signed = agent.sign_agreement_v2(agreement, "signer")
report = agent.verify_agreement_v2(signed)
assert report["mathematicalChecksValid"]
assert report["status"] == "final"
assert report["policyAccepted"] is False
Agreement v2 inspection checks signatures and claimed status; valid and
policyAccepted remain false because this is not application consent-policy
acceptance. Do not authorize an action from these mathematical checks alone.
The same methods are available on jacs.simple after quickstart() or load().
Verifying another agent's agreement signature requires that agent's public key, so distinct agents must share a data_directory or exchange public keys; ephemeral agents verify only their own signatures.
The older create_agreement() / sign_agreement() / check_agreement() methods remain for simple jacsAgreement sidecars on existing documents.
Framework adapters
pip install "jacs[langchain,langgraph]" # LangChain / LangGraph
pip install jacs[fastapi] # FastAPI / Starlette
pip install jacs[anthropic] # Anthropic / Claude SDK
pip install jacs[a2a] # A2A protocol
pip install jacs[all] # Everything
Current-source A2A routes serve five direct-root discovery documents, or six for explicit ES256. Verify the card/JWKS and any root-signed compatibility binding under your trust policy; discovery and cache freshness do not establish authority. The guide covers renewal and expiry. New source behavior is not publication evidence.
Instance-based API
For multiple agents in one process:
from jacs.client import JacsClient
client = JacsClient.quickstart(name="my-agent", domain="example.com")
signed = client.sign_message({"action": "approve"})
See the API reference, framework adapters, and native development guide.
Links
Metadata
Release files for jacs 0.16.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| jacs-0.16.0.tar.gz | 1.8 MB | With provenance | Details for jacs-0.16.0.tar.gz |
Built distributions (wheels)
| File | Actions Reset | |||
|---|---|---|---|---|
| jacs-0.16.0-cp311-abi3-musllinux_1_2_x86_64.whl | CPython 3.11 | abi3 | Linux musl 1.2+ x86-64 | Details for jacs-0.16.0-cp311-abi3-musllinux_1_2_x86_64.whl |
| jacs-0.16.0-cp311-abi3-manylinux_2_28_x86_64.whl | CPython 3.11 | abi3 | Linux glibc 2.28+ x86-64 | Details for jacs-0.16.0-cp311-abi3-manylinux_2_28_x86_64.whl |
| jacs-0.16.0-cp311-abi3-manylinux_2_28_aarch64.whl | CPython 3.11 | abi3 | Linux glibc 2.28+ ARM64 | Details for jacs-0.16.0-cp311-abi3-manylinux_2_28_aarch64.whl |
| jacs-0.16.0-cp311-abi3-macosx_11_0_arm64.whl | CPython 3.11 | abi3 | macOS 11.0+ ARM64 | Details for jacs-0.16.0-cp311-abi3-macosx_11_0_arm64.whl |
| jacs-0.16.0-cp311-abi3-macosx_10_12_x86_64.whl | CPython 3.11 | abi3 | macOS 10.12+ x86-64 | Details for jacs-0.16.0-cp311-abi3-macosx_10_12_x86_64.whl |
Total release size: 64.6 MB
Release files / jacs-0.16.0.tar.gz
| Download URL | jacs-0.16.0.tar.gz |
|---|---|
| Size | 1.8 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f8d1cf260a3ee887e0cbb84d389e1d52a00f16b847b6ee4cb14d2f2b01492d85
|
|
BLAKE2b-256 checksum How to use checksums |
ca5b0ebca57c6361cc8b918520eb9c3a0a47025d60b29e4f6e4b41819817b4ac
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.
Transparency logRelease files / jacs-0.16.0-cp311-abi3-musllinux_1_2_x86_64.whl
| Download URL | jacs-0.16.0-cp311-abi3-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 11.9 MB |
| Tags | CPython 3.11 Linux musl 1.2+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
7a3edad07d105a1c7b1915393ea1857c78bf90d3691d78c0a6f92629de84ee60
|
|
BLAKE2b-256 checksum How to use checksums |
b60b7335f366aa5bfddcd35eb0a7b8ecfe0fc02eff1ea17e1de1a2bd8d2ceaec
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.
Transparency logRelease files / jacs-0.16.0-cp311-abi3-manylinux_2_28_x86_64.whl
| Download URL | jacs-0.16.0-cp311-abi3-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 13.3 MB |
| Tags | CPython 3.11 Linux glibc 2.28+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
fdf3e9f6d929dc1a6f810130c73073c5ad1afc19fd80afc9843fb7ff737e6f4c
|
|
BLAKE2b-256 checksum How to use checksums |
cba2c3725ddc75bad016982e0e298cb7563bfe3d982ac9cb173dfd7b9979640a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.
Transparency logRelease files / jacs-0.16.0-cp311-abi3-manylinux_2_28_aarch64.whl
| Download URL | jacs-0.16.0-cp311-abi3-manylinux_2_28_aarch64.whl |
|---|---|
| Size | 13.5 MB |
| Tags | CPython 3.11 Linux glibc 2.28+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
a8e2170089c852b4ce7f201ecd0fe77dc2f4a71f9268d3829f275e000521496a
|
|
BLAKE2b-256 checksum How to use checksums |
22338519084dda5925f42765cf1b663d04289cc98ef0d0ae8abb06a71ead9201
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.
Transparency logRelease files / jacs-0.16.0-cp311-abi3-macosx_11_0_arm64.whl
| Download URL | jacs-0.16.0-cp311-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 11.9 MB |
| Tags | CPython 3.11 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
e0144d144c1ac7af1c9c2d0d9d9f0656d7109dd9cc5e237c9daa1facc4242a01
|
|
BLAKE2b-256 checksum How to use checksums |
b553c662113edc12575ed65834498dfc0c25faa5a0f59d75c2b57a707c657ade
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.
Transparency logRelease files / jacs-0.16.0-cp311-abi3-macosx_10_12_x86_64.whl
| Download URL | jacs-0.16.0-cp311-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 12.2 MB |
| Tags | CPython 3.11 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
62e627303572d34b0e631f0682f5a85a1c8e87e4da279595d3a2a1d62f77bb41
|
|
BLAKE2b-256 checksum How to use checksums |
fe6f425f31417938ddf7bdb0f0b3bcad33d9554eef8efaf7735219c97c02ec0d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.
Transparency logSecurity for jacs 0.16.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 6 files in this release have been uploaded with provenance metadata.
Attestation for jacs-0.16.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 3, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.