Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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