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:

  1. Verify Signed Documents - Verify any document from CLI, Python, or Node.js -- no agent required
  2. A2A Quickstart - Make your agent discoverable by other A2A agents in minutes
  3. Framework Adapters - Add auto-signing to LangChain, FastAPI, CrewAI, or Anthropic SDK in 1-3 lines
  4. Multi-Agent Agreements - Cross-trust-boundary verification with quorum and timeout
  5. Rust Deep Dive - Learn the full Rust API
  6. Node.js Integration - Add MCP support
  7. Python MCP - Build authenticated MCP servers
  8. Production Security - Harden runtime settings and key management
  9. 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.