JACS
Sign it. Prove it. -- Agent trust infrastructure for a world where AI agents cross organizational boundaries.
Cryptographic signatures for AI agent outputs so anyone can verify who said what, whether it was changed, and hold agents accountable. No server. No account. Three lines of code.
pip install jacs | npm install @hai.ai/jacs | cargo install jacs-cli
Quick Start
Zero-config -- one call creates a persistent agent with keys on disk.
Password Setup
Persistent agents use encrypted private keys. Rust/CLI flows require an explicit password source before quickstart(...). Python/Node quickstart can auto-generate one, but production deployments should still set it explicitly.
# Option A (recommended): direct env var
# Option B (CLI convenience): path to a file containing only the password
Set exactly one explicit source for CLI. If both are set, CLI fails fast to avoid ambiguity.
For Python/Node library usage, set JACS_PRIVATE_KEY_PASSWORD in your process environment (recommended).
Python
=
=
=
Node.js
const jacs = require;
.;
Rust / CLI
# Install (requires Rust toolchain)
# Or download a prebuilt binary from GitHub Releases
# https://github.com/HumanAssisted/JACS/releases
# Start the built-in MCP server (stdio transport)
jacs mcp is local stdio-only transport. No separate install step needed.
Homebrew (macOS)
# Install JACS CLI
# Install HAI SDK CLI separately
Signed your first document? Next: Verify it without an agent | Pick your framework integration | Full quick start guide
Verify a Signed Document
No agent needed. One command or one function call.
= # Python, no agent
const r = verifyStandalone(signedJson, { keyDirectory: './keys' }); // Node.js, no agent
Full verification guide -- CLI, Python, Node.js, DNS, verification links.
Which Integration Should I Use?
Find the right path in under 2 minutes. Full decision tree
| I use... | Start here | Docs |
|---|---|---|
| Python + LangChain/LangGraph | from jacs.adapters.langchain import jacs_signing_middleware |
LangChain Guide |
| Python + CrewAI | from jacs.adapters.crewai import jacs_guardrail |
CrewAI Guide |
| Python + FastAPI | from jacs.adapters.fastapi import JacsMiddleware |
FastAPI Guide |
| Node.js + Express | require('@hai.ai/jacs/express') |
Express Guide |
| Node.js + Vercel AI SDK | require('@hai.ai/jacs/vercel-ai') |
Vercel AI Guide |
| Node.js + LangChain.js | require('@hai.ai/jacs/langchain') |
LangChain.js Guide |
| MCP Adapter (Python, partial) | from jacs.mcp import create_jacs_mcp_server |
Python MCP Guide |
| MCP Adapter (Node.js, partial) | require('@hai.ai/jacs/mcp') |
Node.js MCP Guide |
| A2A Protocol | client.get_a2a() / client.getA2A() |
A2A Guide |
| Rust / CLI (canonical MCP server) | cargo install jacs-cli |
Rust Guide |
| Any language (standalone) | import jacs.simple as jacs |
Simple API |
MCP Support Matrix
| MCP surface | Rust jacs-mcp |
Node jacs/mcp |
Python jacs.adapters.mcp |
Go |
|---|---|---|---|---|
Canonical full jacs_* server |
Yes | No | No | No |
| Transport proxy / protocol glue | N/A | Yes | Yes | Demo only |
| Middleware / framework adapter | N/A | Yes | Yes | No |
| Language-native tool registration | Canonical | Partial compatibility layer | Partial compatibility layer | No |
| Demo / example only | No | No | No | Yes |
The canonical full MCP contract is exported from Rust at jacs-mcp/contract/jacs-mcp-contract.json. Node and Python adapters are tested against that snapshot so contract drift is explicit.
Who Is JACS For?
Platform teams building multi-agent systems where agents from different services -- or different organizations -- need to trust each other's outputs.
Compliance and security engineers in regulated industries (finance, healthcare, government) who need cryptographic proof of agent actions, not just log files.
AI framework developers adding provenance to LangChain, CrewAI, FastAPI, Express, Vercel AI, or MCP pipelines without changing their existing architecture.
Researchers and labs running public-facing agents that need verifiable identity without exposing operator information.
When You DON'T Need JACS
Honesty builds trust, so here is when JACS is probably overkill:
- Single developer, single service. If all your agents run inside one process you control and you trust your own logs, standard logging is fine.
- Internal-only prototypes. If data never leaves your organization and you are not in a regulated environment, the overhead of cryptographic signing adds no value yet.
- Simple checksums. If you only need to detect accidental corruption (not prove authorship), SHA-256 hashes are simpler.
JACS adds value when data crosses trust boundaries -- between organizations, between services with different operators, or into regulated audit trails.
The Trust Blind Spot
A 2026 survey of 29 multi-agent reinforcement learning publications found that zero addressed authentication, integrity, or trust between agents (Wittner, "Communication Methods in Multi-Agent RL," arxiv.org/abs/2601.12886). Every paper optimized for communication efficiency while assuming a fully trusted environment.
That assumption holds in a research lab. It does not hold in production, where agents cross organizational boundaries, outputs are consumed by downstream systems, and regulatory auditors expect cryptographic proof.
JACS provides the missing trust layer: identity (who produced this?), integrity (was it changed?), and accountability (can you prove it?).
Post-Quantum Ready
JACS supports ML-DSA-87 (FIPS-204) post-quantum signatures alongside classical algorithms (Ed25519 and RSA-PSS). The pq2025 algorithm preset is the default across quickstart/create paths.
A2A Interoperability
Every JACS agent is an A2A agent -- zero additional configuration. JACS implements the Agent-to-Agent (A2A) protocol with cryptographic trust built in. For details on how signing, A2A, and attestation relate, see the Trust Layers Guide.
Built-in trust policies control how your agent handles foreign signatures: open (accept all), verified (require key resolution, default), or strict (require local trust store entry).
=
=
=
const = require;
const client = await ;
const card = client.;
const signed = await client.;
For trust bootstrap flows, use a signed agent document plus an explicit public key exchange:
=
=
A2A Guide | Python A2A | Node.js A2A
Cross-Language Compatibility
A document signed by a Rust agent can be verified by a Python or Node.js agent, and vice versa. The signature format is language-agnostic -- any JACS binding produces and consumes the same signed JSON.
Cross-language interoperability is tested on every commit with both Ed25519 and post-quantum (ML-DSA-87) algorithms. Rust generates signed fixtures, then Python and Node.js verify and countersign them. See the test suites: jacs/tests/cross_language/, jacspy/tests/test_cross_language.py, jacsnpm/test/cross-language.test.js.
Use Cases
Prove that pipeline outputs are authentic. A build service signs every JSON artifact it emits. Downstream teams and auditors verify with a single call; tampering or forgery is caught immediately. Full scenario
Run a public agent without exposing the operator. An AI agent signs every message but only publishes the public key via DNS. Recipients verify origin and integrity cryptographically; the operator's identity never touches the internet. Full scenario
Add cryptographic provenance in any language. Finance, healthcare, or any regulated environment: sign every output with sign_message(), verify with verify(). The same three-line pattern works identically in Python, Node.js, Rust, and Go. Full scenario
Links
v0.9.2 | Apache 2.0 with Common Clause