Quick Start Guide
Get signing and verifying in under a minute. No manual setup needed.
Zero-Config Quick Start
quickstart(name, domain, ...) creates a persistent agent with keys on disk (default algorithm: pq2025). If ./jacs.config.json already exists, it loads it; otherwise it creates a new agent. Returned AgentInfo includes config/key paths (config_path/public_key_path/private_key_path in Python, configPath/publicKeyPath/privateKeyPath in Node) plus key directory metadata so you can locate key material immediately. Rust/CLI quickstart requires an explicit password source (JACS_PRIVATE_KEY_PASSWORD, or JACS_PASSWORD_FILE in CLI). Python/Node can auto-generate a password if needed; set JACS_SAVE_PASSWORD_FILE=true if you want that generated password persisted to ./jacs_keys/.jacs_password.
Password bootstrap
Rust CLI quickstart requires exactly one explicit password source:
# Recommended
export JACS_PRIVATE_KEY_PASSWORD='use-a-strong-password'
# CLI convenience (file contains only the password)
export JACS_PASSWORD_FILE=/secure/path/jacs-password.txt
If both JACS_PRIVATE_KEY_PASSWORD and JACS_PASSWORD_FILE are set, CLI fails fast to avoid ambiguity.
Python/Node quickstart can auto-generate a secure password if JACS_PRIVATE_KEY_PASSWORD is unset. Set JACS_SAVE_PASSWORD_FILE=true if you want the generated password persisted to ./jacs_keys/.jacs_password. In production, set JACS_PRIVATE_KEY_PASSWORD explicitly.
One call and you're signing.
pip install jacs
import jacs.simple as jacs
info = jacs.quickstart(name="my-agent", domain="my-agent.example.com")
print(info.config_path, info.public_key_path, info.private_key_path)
signed = jacs.sign_message({"action": "approve", "amount": 100})
result = jacs.verify(signed.raw)
print(f"Valid: {result.valid}, Signer: {result.signer_id}")
npm install @hai.ai/jacs
const jacs = require('@hai.ai/jacs/simple');
const info = await jacs.quickstart({
name: 'my-agent',
domain: 'my-agent.example.com',
});
console.log(info.configPath, info.publicKeyPath, info.privateKeyPath);
const signed = await jacs.signMessage({ action: 'approve', amount: 100 });
const result = await jacs.verify(signed.raw);
console.log(`Valid: ${result.valid}, Signer: ${result.signerId}`);
cargo install jacs-cli
# Info mode -- prints agent ID and algorithm
jacs quickstart --name my-agent --domain my-agent.example.com
# Sign JSON from stdin
echo '{"action":"approve"}' | jacs quickstart --name my-agent --domain my-agent.example.com --sign
# Sign a file
jacs quickstart --name my-agent --domain my-agent.example.com --sign --file mydata.json
Pass algorithm="ring-Ed25519" (or { algorithm: 'ring-Ed25519' } in JS, --algorithm ring-Ed25519 in CLI) to override the default (pq2025).
That's it -- you're signing. For most use cases, the quick start above is all you need. Jump to Which integration should I use? to find the right framework adapter, or read on for manual agent setup.
macOS Homebrew install (Rust CLI)
brew tap HumanAssisted/homebrew-jacs
brew install jacs
MCP server (Rust CLI)
The MCP server is built into the jacs binary. No separate install step needed.
# Start the MCP server (stdio transport)
jacs mcp
Advanced: Explicit Agent Setup
For full control over agent creation, you can set up an agent manually with a config file and JACS_PRIVATE_KEY_PASSWORD environment variable. This is optional since quickstart(...) already creates a persistent agent.
Install
cargo install jacs-cli
Initialize
# Create configuration and agent in one step
jacs init
# Or step by step:
# 1. Create config
jacs config create
# 2. Create agent with keys
jacs agent create --create-keys true
# 3. Verify
jacs agent verify
Sign a document
jacs document create -f mydata.json
Install
npm install @hai.ai/jacs
Load and use
const jacs = require('@hai.ai/jacs/simple');
// Load from config file
await jacs.load('./jacs.config.json');
const signed = await jacs.signMessage({ action: 'approve', amount: 100 });
const result = await jacs.verify(signed.raw);
console.log(`Valid: ${result.valid}`);
Install
pip install jacs
Load and use
import jacs.simple as jacs
# Load from config file
jacs.load("./jacs.config.json")
signed = jacs.sign_message({"action": "approve", "amount": 100})
result = jacs.verify(signed.raw)
print(f"Valid: {result.valid}")
Programmatic Agent Creation (v0.6.0+)
For scripts, CI/CD, and server environments where you need agents created programmatically with explicit parameters (without interactive prompts), use create(). For most cases, quickstart(...) above is simpler and also creates a persistent agent.
import jacs.simple as jacs
agent = jacs.create(
name="my-agent",
password="Str0ng-P@ssw0rd!", # or set JACS_PRIVATE_KEY_PASSWORD
algorithm="pq2025",
)
print(f"Agent: {agent.agent_id}")
const jacs = require('@hai.ai/jacs/simple');
const agent = await jacs.create({
name: 'my-agent',
password: process.env.JACS_PRIVATE_KEY_PASSWORD,
algorithm: 'pq2025',
});
console.log(`Agent: ${agent.agentId}`);
info, err := jacs.Create("my-agent", &jacs.CreateAgentOptions{
Password: os.Getenv("JACS_PRIVATE_KEY_PASSWORD"),
Algorithm: "pq2025",
})
#![allow(unused)] fn main() { use jacs::simple::{CreateAgentParams, SimpleAgent}; let params = CreateAgentParams { name: "my-agent".into(), password: std::env::var("JACS_PRIVATE_KEY_PASSWORD").unwrap(), algorithm: "pq2025".into(), ..Default::default() }; let (agent, info) = SimpleAgent::create_with_params(params)?; }
Password requirements: At least 8 characters, with uppercase, lowercase, a digit, and a special character.
Algorithm note: pq-dilithium is deprecated in v0.6.0. Use pq2025 (ML-DSA-87, FIPS-204) instead.
Understanding What Happened
When you completed the quick start, several important things occurred:
1. Agent Creation
- A unique identity (UUID) was generated for your agent
- Cryptographic key pair was created for signing
- Agent document was created and self-signed
- Public key was stored for verification
2. Configuration Setup
- Storage directories were configured
- Cryptographic algorithm was selected
- Agent identity was linked to configuration
3. Task Creation
- Task document was structured according to JACS schema
- Document was signed with your agent's private key
- SHA-256 hash was calculated for integrity
- Signature metadata was embedded in the document
Verify Everything Works
Let's verify that the documents are properly signed and can be validated:
# Verify agent signature
jacs agent verify
# Verify a specific document
jacs document verify -f ./jacs_data/[document-id].json
# Sign a document
jacs document sign -f ./jacs_data/[document-id].json
// Verify agent signature (async)
const isValid = await agent.verifyAgent();
console.log('Agent signature valid:', isValid);
// Verify task signature
const taskValid = await agent.verifyDocument(signedTask);
console.log('Task signature valid:', taskValid);
# Verify agent signature
is_valid = agent.verify_agent()
print(f'Agent signature valid: {is_valid}')
# List all documents
documents = agent.list_documents()
print(f'Documents: {len(documents)}')
# Verify task signature
task_valid = agent.verify_document(signed_task)
print(f'Task signature valid: {task_valid}')
# Get document details
task_details = agent.get_document(signed_task["jacsId"])
print(f'Task details: {task_details}')
Next Steps: Multi-Agent Workflow
Now let's create a second agent and demonstrate inter-agent communication:
# Create a second agent configuration
cp jacs.config.json reviewer.config.json
# Edit reviewer.config.json to set jacs_agent_id_and_version to null
# Create reviewer agent (uses JACS_CONFIG_PATH environment variable)
JACS_CONFIG_PATH=./reviewer.config.json jacs agent create --create-keys true
# Create an agreement on a document
jacs agreement create -f ./document.json \
--agents [agent-1-id],[agent-2-id] \
--question "Do you agree to collaborate on this content task?"
# Sign the agreement as first agent
jacs agreement sign -f ./document.json
# Sign as second agent (using reviewer config)
JACS_CONFIG_PATH=./reviewer.config.json jacs agreement sign -f ./document.json
# Verify agreement is complete
jacs agreement check -f ./document.json
// Create second agent with separate config file
const reviewerConfig = { ...config };
reviewerConfig.jacs_agent_id_and_version = null;
fs.writeFileSync('./reviewer.config.json', JSON.stringify(reviewerConfig, null, 2));
const reviewer = new JacsAgent();
await reviewer.load('./reviewer.config.json');
// Create agreement between agents
const signedAgreement = await agent.createAgreement(
signedTask,
[agentDoc.jacsId, reviewerDoc.jacsId],
'Do you agree to collaborate on this content task?'
);
// Both agents sign the agreement
const signed1 = await agent.signAgreement(signedAgreement);
const signed2 = await reviewer.signAgreement(signed1);
// Check agreement status
const status = await agent.checkAgreement(signed2);
console.log('Agreement status:', JSON.parse(status));
# Create second agent with separate config file
reviewer_config = config.copy()
reviewer_config["jacs_agent_id_and_version"] = None
with open('reviewer.config.json', 'w') as f:
json.dump(reviewer_config, f, indent=2)
reviewer = jacs.JacsAgent()
reviewer.load("./reviewer.config.json")
reviewer.generate_keys()
reviewer_doc = reviewer.create_agent({
"name": "Content Reviewer Bot",
"description": "AI agent specialized in content review"
})
# Create agreement between agents
agreement = {
"title": "Content Collaboration Agreement",
"question": "Do you agree to collaborate on this content task?",
"context": f"Task: {signed_task['jacsId']}",
"agents": [agent_doc["jacsId"], reviewer_doc["jacsId"]]
}
signed_agreement = agent.create_agreement(agreement)
# Both agents sign the agreement
agent.sign_agreement(signed_agreement["jacsId"])
reviewer.sign_agreement(signed_agreement["jacsId"])
# Verify all signatures
agreement_valid = agent.verify_agreement(signed_agreement["jacsId"])
print(f'Agreement complete: {agreement_valid}')
What You've Accomplished
Congratulations! You've successfully:
✅ Created JACS agents with cryptographic identities
✅ Generated and signed documents with verifiable integrity
✅ Established multi-agent agreements with cryptographic consent
✅ Verified signatures and document authenticity
✅ Created an audit trail of all interactions
Key Takeaways
- Everything is verifiable: All documents have cryptographic signatures
- Agents are autonomous: Each has its own identity and keys
- Agreements enable trust: Multi-party consent before proceeding
- Audit trails are automatic: Complete history of all interactions
- JSON is universal: Documents work everywhere
Where to Go Next
Now that you have the basics working:
- Verify Signed Documents - Verify any document from CLI, Python, or Node.js -- no agent required
- A2A Quickstart - Make your agent discoverable by other A2A agents in minutes
- Framework Adapters - Add auto-signing to LangChain, FastAPI, CrewAI, or Anthropic SDK in 1-3 lines
- Multi-Agent Agreements - Cross-trust-boundary verification with quorum and timeout
- Rust Deep Dive - Learn the full Rust API
- Node.js Integration - Add MCP support
- Python MCP - Build authenticated MCP servers
- Production Security - Harden runtime settings and key management
- Real Examples - See production patterns
Troubleshooting
Agent creation fails: Check that the data and key directories exist and are writable Signature verification fails: Ensure public keys are properly stored and accessible Agreement signing fails: Verify all agent IDs are correct and agents exist Documents not found: Check the data directory configuration
Need help? Check the GitHub issues or review the detailed implementation guides.