Skip to main content

JACS Python Library

Cryptographic identity, signing, and verification for AI agents from Python.

Registry status (observed 2026-07-11): PyPI serves jacs==0.11.3; this branch is source 0.13.0. Pin the package when exact cross-language contracts matter.

pip install jacs

Prebuilt native bindings are distributed via maturin. A normal install does not require compiling Rust.

First use of the jacs command

Installing the Python library does not download a CLI. The first invocation of the jacs command downloads the matching cli/vX.Y.Z GitHub Release into an exact-version and platform-specific user cache. It fetches sha256sums.txt first (with a validated per-asset checksum fallback), verifies SHA-256, rejects unsafe archive paths, and then executes the cached binary. Linux musl is not a published CLI target, so musl systems fail clearly instead of downloading the glibc build. Unsupported platforms or failed verification exit nonzero with the fallback command cargo install jacs-cli. In an active virtual environment the Python shim may remain first on PATH; invoke Cargo's installed binary directly as ~/.cargo/bin/jacs (or .cargo\\bin\\jacs.exe under your Windows user profile). If CARGO_HOME is set, use its bin/jacs executable instead.

Importing or using the Python library performs no CLI download.

Full documentation | 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 keys on disk. If jacs.config.json exists, it loads it; otherwise it creates a new agent.

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() Verify Agreement v2 hash, policy, transcript, and 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.

Rust defaults remain unchanged. A minimal custom extension can omit the feature using cargo build -p jacspy --features extension-module,a2a,agreements,attestation; it does not expose this method. human-approval alone remains available for custom builds intentionally using a system OpenSSL installation.

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. Feature-enabled tests require JACS_TEST_HUMAN_APPROVAL=1 pytest tests/test_human_approved_document.py.

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(algorithm="ed25519")
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.

Multi-replica consumers should release signed-event payloads through their own shared atomic replay store:

from jacs import unwrap_signed_event_with_replay_store

# store.scope must be "shared". consume(key, ttl_seconds) returns True only
# for the first atomic consumer and False for a duplicate.
verified = await unwrap_signed_event_with_replay_store(
    agent,
    envelope,
    server_keys,
    store,
)

Native verification and freshness checks run before the store is called and return no payload. The helper validates the exact-input digest, consumes the native replay key once, rechecks expiry, and only then returns data with its authenticated signer, timestamp, algorithm, and document ID. Store failures, timeouts, invalid results, process-local stores, duplicates, and expiry all fail closed with a stable ReplayError.code.

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", out="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")

Cross-language interop is tested on every commit. Documents signed in Rust or Node.js verify in Python, and Python-signed documents verify in the other bindings.

Agreement v2

Use Agreement v2 for new multi-agent consent workflows:

from jacs import SimpleAgent

agent, info = SimpleAgent.ephemeral(algorithm="ed25519")
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")
assert agent.verify_agreement_v2(signed)["valid"]

The same operations are available as module-level functions once an agent is loaded (quickstart() / create() / load()), matching Node's @hai.ai/jacs/simple surface:

import jacs.simple as jacs

jacs.quickstart(name="my-agent", domain="agent.example.com")
agent_id = jacs.get_agent_info().agent_id

agreement = jacs.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 = jacs.sign_agreement_v2(agreement, "signer")
assert jacs.verify_agreement_v2(signed)["valid"]

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]    # 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

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 DEVELOPMENT.md for the full API reference, advanced usage, framework adapter examples, and testing utilities.

Metadata

Release files for jacs 0.13.0

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

Source distribution (sdist)

Source distribution for jacs 0.13.0
File Size Uploaded Provenance Actions
jacs-0.13.0.tar.gz 1.9 MB With provenance Details for jacs-0.13.0.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for jacs 0.13.0
File Actions
jacs-0.13.0-cp310-abi3-musllinux_1_2_x86_64.whl CPython 3.10 abi3 Linux musl 1.2+ x86-64 Details for jacs-0.13.0-cp310-abi3-musllinux_1_2_x86_64.whl
jacs-0.13.0-cp310-abi3-manylinux_2_28_x86_64.whl CPython 3.10 abi3 Linux glibc 2.28+ x86-64 Details for jacs-0.13.0-cp310-abi3-manylinux_2_28_x86_64.whl
jacs-0.13.0-cp310-abi3-manylinux_2_28_aarch64.whl CPython 3.10 abi3 Linux glibc 2.28+ ARM64 Details for jacs-0.13.0-cp310-abi3-manylinux_2_28_aarch64.whl
jacs-0.13.0-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details for jacs-0.13.0-cp310-abi3-macosx_11_0_arm64.whl
jacs-0.13.0-cp310-abi3-macosx_10_12_x86_64.whl CPython 3.10 abi3 macOS 10.12+ x86-64 Details for jacs-0.13.0-cp310-abi3-macosx_10_12_x86_64.whl

Total release size: 54.4 MB

Release files / jacs-0.13.0.tar.gz

Download URL jacs-0.13.0.tar.gz
Size 1.9 MB
Tags Source
SHA-256 checksum
How to use checksums
91e1183c66f2ce24a47234fa0c3072a9cb76ced2d86f501623a6173263e3d1ae
BLAKE2b-256 checksum
How to use checksums
32e3a651fcc19c1c0e5f38893ca39d473144b7ba3318456c0239b41db2498a67
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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 Sep 10, 2026.

Transparency log

Release files / jacs-0.13.0-cp310-abi3-musllinux_1_2_x86_64.whl

Download URL jacs-0.13.0-cp310-abi3-musllinux_1_2_x86_64.whl
Size 9.9 MB
Tags CPython 3.10 Linux musl 1.2+ x86-64 abi3
SHA-256 checksum
How to use checksums
7e471a32f22dc5fa15564bb967d208da5a77e25bc273575b9820457bb298fac6
BLAKE2b-256 checksum
How to use checksums
66136826318c464924f4c134e903ef42c08aadbfd6a9989a970e200caf3e5704
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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 Sep 10, 2026.

Transparency log

Release files / jacs-0.13.0-cp310-abi3-manylinux_2_28_x86_64.whl

Download URL jacs-0.13.0-cp310-abi3-manylinux_2_28_x86_64.whl
Size 11.0 MB
Tags CPython 3.10 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
dcce57a9a3e2819489f00e307386b31c1792c489acbebe74bc4282f51c770b8b
BLAKE2b-256 checksum
How to use checksums
a9d52992afcaf9953f8619254cdb7bd9b40c2088d7fe7a268b4e23208c3d0a2e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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 Sep 10, 2026.

Transparency log

Release files / jacs-0.13.0-cp310-abi3-manylinux_2_28_aarch64.whl

Download URL jacs-0.13.0-cp310-abi3-manylinux_2_28_aarch64.whl
Size 11.4 MB
Tags CPython 3.10 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
4a5ea8cca23016202d2fde6df32d448b103c9a0021fd4c10babe852c8b865a60
BLAKE2b-256 checksum
How to use checksums
03c62a267c181849abc62fdb094f374840ad061e1d1d930c4dcb7e694e46aa46
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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 Sep 10, 2026.

Transparency log

Release files / jacs-0.13.0-cp310-abi3-macosx_11_0_arm64.whl

Download URL jacs-0.13.0-cp310-abi3-macosx_11_0_arm64.whl
Size 10.1 MB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
b088c6333e9ee996ec535145509ca147dd1aebe16c4f99e592ca090ea5052cad
BLAKE2b-256 checksum
How to use checksums
19aba3d9492caa7e0039b1fc684b2b8b2956b050c6b88a6c4a3df5ee463070bb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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 Sep 10, 2026.

Transparency log

Release files / jacs-0.13.0-cp310-abi3-macosx_10_12_x86_64.whl

Download URL jacs-0.13.0-cp310-abi3-macosx_10_12_x86_64.whl
Size 10.1 MB
Tags CPython 3.10 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
1c4bfb001442c4648892b486a2a1969c8bc69b1df34878de79bdeaa6ccbb4bcc
BLAKE2b-256 checksum
How to use checksums
954700f532f08b6252d3b1e2875f2deb8b8ed1298f7227f9562bae0cdef23790
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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 Sep 10, 2026.

Transparency log

Security for jacs 0.13.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.

Select from 6 files

Attestation for jacs-0.13.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 Sep 10, 2026.

Transparency log

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

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