Native library reference. Extended CLI examples use
jacs-compat. This source reference can include unreleased changes; see the package guide for installation and MCP profiles for available tools.
Basic Usage
Source and published packages: Version 0.16.1 has a recorded release inventory. Version 0.16.0 is the first release whose source includes the native PQ DID/JWK and Agent Card behavior. See the identity integration guide.
This chapter covers fundamental JACS operations in Node.js, including agent initialization, document creation, signing, and verification.
Async and synchronous methods
The standard JacsAgent I/O methods and simple signing helpers are async.
Selected operations also provide Sync variants. Standalone verification,
trust helpers and several low-level JacsSimpleAgent methods are synchronous;
check the API signature for the method you call.
// Async (default, recommended)
await agent.load('./jacs.config.json');
const doc = await agent.createDocument(JSON.stringify(content));
// Sync (blocks event loop)
agent.loadSync('./jacs.config.json');
const syncDoc = agent.createDocumentSync(JSON.stringify(content));
Initializing an Agent
Create and Load Agent
import { JacsAgent } from '@hai.ai/jacs';
// Create a new agent instance
const agent = new JacsAgent();
// Load configuration from file (async)
await agent.load('./jacs.config.json');
// Or use sync variant
agent.loadSync('./jacs.config.json');
Configuration File
Create an identity with quickstart first. A configuration only points to existing keys and an agent document; writing placeholder IDs does not initialize an agent. A generated config contains fields like:
{
"$schema": "https://hai.ai/schemas/jacs.config.schema.json",
"jacs_data_directory": "./jacs_data",
"jacs_key_directory": "./jacs_keys",
"jacs_default_storage": "fs",
"jacs_agent_key_algorithm": "pq2025",
"jacs_agent_id_and_version": "agent-uuid:version-uuid"
}
Creating Documents
Basic Document Creation
import { JacsAgent } from '@hai.ai/jacs';
const agent = new JacsAgent();
await agent.load('./jacs.config.json');
// Create a document from JSON
const documentData = {
title: "Project Proposal",
content: "Quarterly development plan",
budget: 50000
};
const signedDocument = await agent.createDocument(JSON.stringify(documentData));
console.log('Signed document:', signedDocument);
With Custom Schema
Validate against a custom JSON Schema:
const signedDocument = await agent.createDocument(
JSON.stringify(documentData),
'./schemas/proposal.schema.json' // custom schema path
);
With Output File
const signedDocument = await agent.createDocument(
JSON.stringify(documentData),
null, // no custom schema
'./output/proposal.json' // output filename
);
Without Saving
const signedDocument = await agent.createDocument(
JSON.stringify(documentData),
null, // no custom schema
null, // no output filename
true // noSave = true
);
With Attachments
const signedDocument = await agent.createDocument(
JSON.stringify(documentData),
null, // no custom schema
null, // no output filename
false, // save the document
'./attachments/report.pdf', // attachment path
true // embed files
);
Verifying Documents
Verify Document Signature
// Verify a document's signature and hash
const isValid = await agent.verifyDocument(signedDocumentJson);
console.log('Document valid:', isValid);
Verify Specific Signature Field
// Verify with a custom signature field
const isValid = await agent.verifySignature(
signedDocumentJson,
'jacsSignature' // signature field name
);
Updating Documents
Update Existing Document
// Use a complete document previously created and stored by this agent.
const updatedData = JSON.parse(signedDocument);
const documentKey = `${updatedData.jacsId}:${updatedData.jacsVersion}`;
updatedData.title = 'Updated Proposal';
updatedData.budget = 75000;
const updatedDocument = await agent.updateDocument(
documentKey,
JSON.stringify(updatedData)
);
console.log('Updated document:', updatedDocument);
Update with New Attachments
const updatedDocument = await agent.updateDocument(
documentKey,
JSON.stringify(updatedData),
['./new-report.pdf'], // new attachments
true // embed files
);
Signing and Verification
Sign Arbitrary Data
// Sign any string data
const signature = await agent.signString('Important message to sign');
console.log('Signature:', signature);
Verify Arbitrary Data
// Verify a signature on string data
const isValid = await agent.verifyString(
'Important message to sign', // original data
signatureBase64, // base64 signature
publicKeyBuffer, // public key as Buffer
'ring-Ed25519' // algorithm
);
Working with Agreements
The methods below inspect the legacy jacsAgreement sidecar. Its participant,
role and quorum policy is not authenticated; complete, policy_authenticated
and policy_accepted remain false. Agreement v2 also provides inspection, not
application consent or execution permission. See Agreement v2.
Create an Agreement
// Add agreement requiring multiple agent signatures
const documentWithAgreement = await agent.createAgreement(
signedDocumentJson,
[JSON.parse(agent.exportAgent()).jacsId], // local signer for this example
'Do you agree to these terms?', // question
'Q1 2024 service contract', // context
'jacsAgreement' // field name
);
Sign an Agreement
// Sign the agreement as the current agent
const signedAgreement = await agent.signAgreement(
documentWithAgreementJson,
'jacsAgreement' // agreement field name
);
Check Agreement Status
// Check which agents have signed
const status = await agent.checkAgreement(
documentWithAgreementJson,
'jacsAgreement'
);
console.log('Agreement status:', JSON.parse(status));
Agent Operations
Verify Agent
// Verify the loaded agent's signature
const isValid = await agent.verifyAgent();
console.log('Agent valid:', isValid);
Update Agent
// Update agent document
const agentDocument = JSON.parse(agent.exportAgent());
agentDocument.jacsAgentType = 'hybrid';
const updatedAgentJson = await agent.updateAgent(JSON.stringify(agentDocument));
Sign External Agent
// Sign another agent's document with registration signature
const signedAgentJson = await agent.signAgent(
externalAgentJson,
publicKeyBuffer,
'ring-Ed25519'
);
Request/Response Signing
These legacy instance methods sign generic documents. They do not bind HTTP
request context or authorize a route. Use request-bound HTTP credentials
for that purpose. These methods remain synchronous (V8-thread-only, no Sync suffix):
Sign a Request
// Sign request parameters as a JACS document
const signedRequest = agent.signRequest({
method: 'GET',
path: '/api/resource',
timestamp: new Date().toISOString(),
body: { query: 'data' }
});
Verify a Response
// Verify a signed response
const result = agent.verifyResponse(signedResponseJson);
console.log('Response valid:', result);
// Verify and get signer's agent ID
const resultWithId = agent.verifyResponseWithAgentId(signedResponseJson);
console.log('Signer ID:', resultWithId);
Utility Functions
Hash String
import { hashString } from '@hai.ai/jacs';
// SHA-256 hash of a string
const hash = hashString('data to hash');
console.log('Hash:', hash);
Create Configuration
import { createConfig } from '@hai.ai/jacs';
// Programmatically create a config JSON string
const configJson = createConfig(
undefined, // jacs_use_security
'./jacs_data', // jacs_data_directory
'./jacs_keys', // jacs_key_directory
undefined, // private key filename
undefined, // public key filename
'pq2025', // key algorithm
undefined, // private key password
undefined, // agent id and version
'fs' // default storage
);
console.log('Config:', configJson);
Error Handling
import { JacsAgent } from '@hai.ai/jacs';
const agent = new JacsAgent();
try {
await agent.load('./jacs.config.json');
} catch (error) {
console.error('Failed to load agent:', error.message);
}
try {
const doc = await agent.createDocument(JSON.stringify({ data: 'test' }));
console.log('Document created');
} catch (error) {
console.error('Failed to create document:', error.message);
}
try {
const isValid = await agent.verifyDocument(invalidJson);
} catch (error) {
console.error('Verification failed:', error.message);
}
Complete Example
import { JacsAgent, hashString } from '@hai.ai/jacs';
async function main() {
// Initialize agent
const agent = new JacsAgent();
await agent.load('./jacs.config.json');
// Create a generic proposal document
const proposal = {
title: 'Project Proposal',
description: 'Q1 development plan',
budget: 50000
};
const signedProposal = await agent.createDocument(JSON.stringify(proposal));
console.log('Document created');
// Verify the document
if (await agent.verifyDocument(signedProposal)) {
console.log('Document signature valid');
}
// Create a sidecar for signature inspection
const proposalWithAgreement = await agent.createAgreement(
signedProposal,
[JSON.parse(agent.exportAgent()).jacsId],
'Do you approve this proposal?'
);
// Sign the agreement
const signedAgreement = await agent.signAgreement(proposalWithAgreement);
console.log('Agreement signed');
// Check agreement status
const status = await agent.checkAgreement(signedAgreement);
console.log('Status:', status);
// Hash some data for reference
const proposalHash = hashString(signedProposal);
console.log('Document hash:', proposalHash);
}
main().catch(console.error);
Next Steps
- MCP Integration - Model Context Protocol support
- HTTP Server - Create HTTP APIs
- Express Middleware - Express.js integration
- API Reference - Complete API documentation