API Reference

Complete API documentation for the jacs Python package.

For most use cases, the Simplified API (jacs.simple) and JacsClient (instance-based, multiple agents) are recommended. This page documents the lower-level JacsAgent class and module-level functions.

Installation

pip install jacs

Core Module

import jacs
from jacs import JacsAgent

JacsAgent Class

The JacsAgent class is the primary interface for JACS operations. Each instance maintains its own state and can be used independently, allowing multiple agents in the same process.

Constructor

JacsAgent()

Creates a new empty JacsAgent instance. Call load() to initialize with a configuration.

Example:

agent = jacs.JacsAgent()
agent.load('./jacs.config.json')

agent.load(config_path)

Load and initialize the agent from a configuration file.

Parameters:

  • config_path (str): Path to the JACS configuration file

Returns: str - The loaded agent's JSON

Example:

agent = jacs.JacsAgent()
agent_json = agent.load('./jacs.config.json')
print('Agent loaded:', json.loads(agent_json)['jacsId'])

agent.create_document(document_string, custom_schema=None, output_filename=None, no_save=False, attachments=None, embed=False)

Create and sign a new JACS document.

Parameters:

  • document_string (str): JSON string of the document content
  • custom_schema (str, optional): Path to a custom JSON Schema for validation
  • output_filename (str, optional): Filename to save the document
  • no_save (bool, optional): If True, don't save to storage (default: False)
  • attachments (str, optional): Path to file attachments
  • embed (bool, optional): If True, embed attachments in the document

Returns: str - The signed document as a JSON string

Example:

# Basic document creation
doc = agent.create_document(json.dumps({
    'title': 'My Document',
    'content': 'Hello, World!'
}))

# With custom schema
validated_doc = agent.create_document(
    json.dumps({'title': 'Validated', 'amount': 100}),
    custom_schema='./schemas/invoice.schema.json'
)

# Without saving
temp_doc = agent.create_document(
    json.dumps({'data': 'temporary'}),
    no_save=True
)

# With attachments
doc_with_file = agent.create_document(
    json.dumps({'report': 'Monthly Report'}),
    attachments='./report.pdf',
    embed=True
)

agent.verify_document(document_string)

Verify a document's signature and hash integrity.

Parameters:

  • document_string (str): The signed document JSON string

Returns: bool - True if the document is valid

Example:

is_valid = agent.verify_document(signed_document_json)
if is_valid:
    print('Document signature verified')
else:
    print('Document verification failed')

agent.verify_signature(document_string, signature_field=None)

Verify a document's signature with an optional custom signature field.

Parameters:

  • document_string (str): The signed document JSON string
  • signature_field (str, optional): Name of the signature field (default: 'jacsSignature')

Returns: bool - True if the signature is valid

Example:

# Verify default signature field
is_valid = agent.verify_signature(doc_json)

# Verify custom signature field
is_valid_custom = agent.verify_signature(doc_json, 'customSignature')

agent.update_document(document_key, new_document_string, attachments=None, embed=False)

Update an existing document, creating a new version.

Parameters:

  • document_key (str): The document key in format "id:version"
  • new_document_string (str): The modified document as JSON string
  • attachments (list, optional): List of attachment file paths
  • embed (bool, optional): If True, embed attachments

Returns: str - The updated document as a JSON string

Example:

# Parse existing document to get key
doc = json.loads(signed_doc)
document_key = f"{doc['jacsId']}:{doc['jacsVersion']}"

# Update the document
updated_doc = agent.update_document(
    document_key,
    json.dumps({
        **doc,
        'title': 'Updated Title',
        'content': 'Modified content'
    })
)

agent.create_agreement(document_string, agent_ids, question=None, context=None, agreement_field_name=None)

Add an agreement requiring multiple agent signatures to a document.

Parameters:

  • document_string (str): The document JSON string
  • agent_ids (list): List of agent IDs required to sign
  • question (str, optional): The agreement question
  • context (str, optional): Additional context for the agreement
  • agreement_field_name (str, optional): Field name for the agreement (default: 'jacsAgreement')

Returns: str - The document with agreement as a JSON string

Example:

doc_with_agreement = agent.create_agreement(
    signed_document_json,
    ['agent-1-uuid', 'agent-2-uuid', 'agent-3-uuid'],
    question='Do you agree to these terms?',
    context='Q1 2024 Service Agreement',
    agreement_field_name='jacsAgreement'
)

agent.sign_agreement(document_string, agreement_field_name=None)

Sign an agreement as the current agent.

Parameters:

  • document_string (str): The document with agreement JSON string
  • agreement_field_name (str, optional): Field name of the agreement (default: 'jacsAgreement')

Returns: str - The document with this agent's signature added

Example:

signed_agreement = agent.sign_agreement(
    doc_with_agreement_json,
    'jacsAgreement'
)

agent.check_agreement(document_string, agreement_field_name=None)

Check the status of an agreement (which agents have signed).

Parameters:

  • document_string (str): The document with agreement JSON string
  • agreement_field_name (str, optional): Field name of the agreement (default: 'jacsAgreement')

Returns: str - JSON string with agreement status

Example:

status_json = agent.check_agreement(signed_agreement_json)
status = json.loads(status_json)

print('Required signers:', status['required'])
print('Signatures received:', status['signed'])
print('Complete:', status['complete'])

agent.sign_artifact(artifact_json, artifact_type, parent_signatures_json=None)

Sign an A2A artifact with JACS provenance. This is the canonical method name.

Parameters:

  • artifact_json (str): JSON string of the artifact to sign
  • artifact_type (str): Type of artifact (e.g., "task", "message")
  • parent_signatures_json (str, optional): JSON string of parent signatures for chain of custody

Returns: str - The signed, wrapped artifact as a JSON string

Example:

signed = agent.sign_artifact(
    json.dumps({"action": "classify", "input": "hello"}),
    "task"
)

agent.wrap_a2a_artifact(artifact_json, artifact_type, parent_signatures_json=None)

Deprecated since 0.9.0. Use sign_artifact() instead. This method will be removed in 1.0.0.

Set JACS_SHOW_DEPRECATIONS=1 to see runtime warnings when deprecated methods are called.

Wraps an A2A artifact with JACS provenance signature. Identical behavior to sign_artifact().

Parameters: Same as sign_artifact().


agent.sign_string(data)

Sign arbitrary string data with the agent's private key.

Parameters:

  • data (str): The data to sign

Returns: str - Base64-encoded signature

Example:

signature = agent.sign_string('Important message')
print('Signature:', signature)

agent.verify_string(data, signature_base64, public_key, public_key_enc_type)

Verify a signature on arbitrary string data.

Parameters:

  • data (str): The original data
  • signature_base64 (str): The base64-encoded signature
  • public_key (bytes): The public key as bytes
  • public_key_enc_type (str): The key algorithm (e.g., 'ring-Ed25519')

Returns: bool - True if the signature is valid

Example:

is_valid = agent.verify_string(
    'Important message',
    signature_base64,
    public_key_bytes,
    'ring-Ed25519'
)

agent.sign_request(params)

Sign a request payload, wrapping it in a JACS document.

Parameters:

  • params (any): The request payload (will be JSON serialized)

Returns: str - JACS-signed request as a JSON string

Example:

signed_request = agent.sign_request({
    'method': 'GET',
    'path': '/api/data',
    'timestamp': datetime.now().isoformat(),
    'body': {'query': 'value'}
})

agent.verify_response(document_string)

Verify a JACS-signed response and extract the payload.

Parameters:

  • document_string (str): The JACS-signed response

Returns: dict - Dictionary containing the verified payload

Example:

result = agent.verify_response(jacs_response_string)
payload = result.get('payload')
print('Verified payload:', payload)

agent.verify_response_with_agent_id(document_string)

Verify a response and return both the payload and signer's agent ID.

Parameters:

  • document_string (str): The JACS-signed response

Returns: dict - Dictionary with payload and agent ID

Example:

result = agent.verify_response_with_agent_id(jacs_response_string)
print('Payload:', result['payload'])
print('Signed by agent:', result['agentId'])

agent.verify_agent(agent_file=None)

Verify the agent's own signature and hash, or verify another agent file.

Parameters:

  • agent_file (str, optional): Path to an agent file to verify

Returns: bool - True if the agent is valid

Example:

# Verify the loaded agent
is_valid = agent.verify_agent()

# Verify another agent file
is_other_valid = agent.verify_agent('./other-agent.json')

agent.update_agent(new_agent_string)

Update the agent document with new data.

Parameters:

  • new_agent_string (str): The modified agent document as JSON string

Returns: str - The updated agent document

Example:

current_agent = json.loads(agent.load('./jacs.config.json'))
updated_agent = agent.update_agent(json.dumps({
    **current_agent,
    'description': 'Updated description'
}))

agent.sign_agent(agent_string, public_key, public_key_enc_type)

Sign another agent's document with a registration signature.

Parameters:

  • agent_string (str): The agent document to sign
  • public_key (bytes): The public key as bytes
  • public_key_enc_type (str): The key algorithm

Returns: str - The signed agent document

Example:

signed_agent = agent.sign_agent(
    external_agent_json,
    public_key_bytes,
    'ring-Ed25519'
)

Module-Level Functions

These functions operate on a global agent singleton and are maintained for backwards compatibility. New code should use the JacsAgent class instead.

jacs.load(config_path)

Load the global agent from a configuration file.

import jacs
jacs.load('./jacs.config.json')

jacs.sign_request(data)

Sign a request using the global agent.

signed = jacs.sign_request({'method': 'tools/call', 'params': {...}})

jacs.verify_request(data)

Verify an incoming request using the global agent.

payload = jacs.verify_request(incoming_request_string)

jacs.sign_response(data)

Sign a response using the global agent.

signed = jacs.sign_response({'result': 'success'})

jacs.verify_response(data)

Verify an incoming response using the global agent.

result = jacs.verify_response(response_string)
payload = result.get('payload')

MCP Module

from jacs.mcp import JACSMCPServer, JACSMCPClient, create_jacs_mcp_server, jacs_call

Canonical MCP documentation lives at Python MCP Integration. This API section lists the MCP entry points only:

  • JACSMCPServer(mcp_server, config_path="./jacs.config.json", strict=False) - Wrap a FastMCP server with JACS request verification and response signing.
  • JACSMCPClient(url, config_path="./jacs.config.json", strict=False, **kwargs) - Create a FastMCP client with JACS signing/verification interceptors.
  • create_jacs_mcp_server(name, config_path=None) - One-line server factory.
  • jacs_call(server_url, method, **params) - One-shot authenticated MCP call.

For examples, strict-mode behavior, and security guidance, see Python MCP Integration.


Configuration

Configuration File Format

Create a jacs.config.json file:

{
  "$schema": "https://hai.ai/schemas/jacs.config.schema.json",
  "jacs_agent_id_and_version": "your-agent-id:version",
  "jacs_agent_key_algorithm": "ring-Ed25519",
  "jacs_agent_private_key_filename": "private.pem",
  "jacs_agent_public_key_filename": "public.pem",
  "jacs_data_directory": "./jacs_data",
  "jacs_default_storage": "fs",
  "jacs_key_directory": "./jacs_keys"
}

Configuration Options

FieldTypeDescription
jacs_agent_id_and_versionstringAgent ID and version in format "id:version"
jacs_agent_key_algorithmstringSigning algorithm: "ring-Ed25519", "RSA-PSS", "pq-dilithium", "pq2025"
jacs_agent_private_key_filenamestringPrivate key filename
jacs_agent_public_key_filenamestringPublic key filename
jacs_data_directorystringDirectory for data storage
jacs_key_directorystringDirectory for key storage
jacs_default_storagestringStorage backend: "fs", "s3", "memory"

Error Handling

All methods may raise exceptions. Use try/except for error handling:

try:
    agent = jacs.JacsAgent()
    agent.load('./jacs.config.json')
    doc = agent.create_document(json.dumps({'data': 'test'}))
except FileNotFoundError as e:
    print(f'Configuration file not found: {e}')
except ValueError as e:
    print(f'Invalid configuration: {e}')
except Exception as e:
    print(f'JACS error: {e}')

Common Exceptions

ExceptionDescription
FileNotFoundErrorConfiguration file or key file not found
ValueErrorInvalid configuration or document format
RuntimeErrorAgent not loaded or cryptographic operation failed

Type Hints

The package supports type hints for better IDE integration:

from jacs import JacsAgent
import json

def process_document(agent: JacsAgent, data: dict) -> str:
    """Create and return a signed document."""
    doc_string = json.dumps(data)
    return agent.create_document(doc_string)

def verify_and_extract(agent: JacsAgent, doc: str) -> dict:
    """Verify document and extract content."""
    if agent.verify_document(doc):
        return json.loads(doc)
    raise ValueError("Document verification failed")

Thread Safety

JacsAgent instances use internal locking and are thread-safe. You can safely use the same agent instance across multiple threads:

import threading
from jacs import JacsAgent

agent = JacsAgent()
agent.load('./jacs.config.json')

def worker(data):
    # Safe to call from multiple threads
    doc = agent.create_document(json.dumps(data))
    return doc

threads = [
    threading.Thread(target=worker, args=({'id': i},))
    for i in range(10)
]
for t in threads:
    t.start()
for t in threads:
    t.join()

See Also