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.

Discover & Trust Remote Agents

Find other A2A agents and apply an explicit admission policy. Node.js snippets below run inside an async function. Remote evidence variables denote values obtained through an independently authenticated channel.

from jacs.a2a_discovery import discover_and_assess_sync
from jacs.client import JacsClient

client = JacsClient.quickstart(name="my-agent", domain="my-agent.example.com")
result = discover_and_assess_sync("https://agent.example.com", client=client)
if result["allowed"]:
    print(f"Trusted: {result['card']['name']} ({result['trust_level']})")

Add to Your Trust Store

For strict policy, establish native JACS trust from an authenticated agent document and explicit native public key. An Agent Card is self-advertised and cannot create strict identity trust by itself:

from jacs.client import JacsClient
from jacs.a2a import JACSA2AIntegration

client = JacsClient.quickstart(name="my-agent", domain="my-agent.example.com")
a2a = JACSA2AIntegration(client, trust_policy="strict")

# Enroll independently authenticated evidence before assessment
a2a.trust_a2a_agent(remote_native_agent_json, remote_native_public_key_pem)

# Assess a remote agent's trustworthiness
assessment = a2a.assess_remote_agent(remote_card_json)
print(f"JACS registered: {assessment['jacs_registered']}")
print(f"Allowed: {assessment['allowed']}")


Async API

from jacs.a2a_discovery import discover_agent, discover_and_assess

card = await discover_agent("https://agent.example.com")
result = await discover_and_assess("https://agent.example.com", policy="verified", client=client)
const { discoverAndAssess } = require('@hai.ai/jacs/a2a-discovery');

const { JacsClient } = require('@hai.ai/jacs/client');
const client = await JacsClient.quickstart({ name: 'my-agent', domain: 'my-agent.example.com' });
const result = await discoverAndAssess('https://agent.example.com', { client });
if (result.allowed) {
  console.log(`Trusted: ${result.card.name} (${result.trustLevel})`);
}

Add to Your Trust Store

const { JacsClient } = require('@hai.ai/jacs/client');
const { JACSA2AIntegration } = require('@hai.ai/jacs/a2a');

const client = await JacsClient.quickstart({
  name: 'my-agent',
  domain: 'my-agent.example.com',
});
const a2a = new JACSA2AIntegration(client, 'strict');

// Enroll independently authenticated evidence before assessment.
a2a.trustA2AAgent(remoteNativeAgentDocument, remoteNativePublicKeyPem);

// Assess a remote agent
const assessment = a2a.assessRemoteAgent(remoteCardJson);
console.log(`JACS registered: ${assessment.jacsRegistered}`);
console.log(`Allowed: ${assessment.allowed}`);


Trust Policies

PolicyBehavior
openAccept all agents without verification
verifiedRequire a valid Agent Card JWS against the same-origin JWKS and a durable jacsId:jacsVersion key pin (default). This is origin/key continuity, not proof of the claimed native JACS identity.
strictRequire an explicitly trusted native JACS root. Direct ML-DSA-87 cards must use that exact key. ES256 cards must also carry the fixed-path compatibility binding, whose native signature, identity/version, binding hash, compatibility JWK/kid, scope, expiry, and signed issuance time all verify. Bindings are accepted for at most seven days after issuedAt (with five minutes of future clock skew), and the verifier durably pins the latest observed hash, kid, and issuedAt; a newer root-signed binding advances the pin and older replays fail closed.

Lifecycle boundary: The absolute seven-day freshness check also applies on first contact, independently of expiresAt. Local discovery generation refreshes an authentic binding after six days under the shared issuance lock, preserving its scopes and explicit expiry. Once a newer native-root-signed binding is observed, JACS also rejects rollback to the old hash/kid. Use an earlier expiresAt when old compatibility keys must stop working sooner, and distribute the refreshed binding promptly after rotation or compromise.

How Trust Flows

1. Discover  -- Fetch /.well-known/agent-card.json from a remote URL
2. Assess    -- Check for JACS extension, verify signatures
3. Decide    -- Trust policy determines if the agent is allowed
4. Authorize -- Apply application policy; strict enrollment precedes assessment

With open, all agents pass step 3 without identity assurance. With verified, the Agent Card JWS must verify against the same-origin JWKS and the signing key must match its durable TOFU pin; this proves origin/key continuity, not native identity. With strict, the native root must be explicitly trusted and a directly signed card must use that exact root key. ES256 compatibility additionally requires a signed binding authorizing the exact card key, identity, version, scope, and current binding hash. These policies parse the legacy card format; they are not an A2A 1.0 verifier.

Next Steps

CLI a2a discover is an inspection command: --json skips trust assessment, and a disallowed assessment can still exit successfully. Use the assessor's explicit allowed result for admission; an exit code or fetched card is not authentication.