Skip to content

Trust Bundles

Trust bundles package discovery and revocation documents together for offline, air-gapped, or enterprise verification environments. Instead of fetching documents over HTTPS at verification time, the verifier uses a pre-loaded bundle.


When to Use Trust Bundles

  • Air-gapped networks — Environments without internet access
  • CI/CD pipelines — Deterministic verification without HTTP calls
  • Enterprise deployments — Centralized trust management
  • Embedded systems — Pre-provisioned trust data
  • High-throughput verification — Avoid network latency per verification

Bundle Format

A trust bundle is a JSON object containing arrays of discovery and revocation documents:

{
  "agentpin_version": "0.1",
  "bundle_id": "enterprise-bundle-2026-02",
  "created_at": "2026-02-15T00:00:00Z",
  "documents": [
    {
      "agentpin_version": "0.1",
      "entity": "example.com",
      "entity_type": "maker",
      "public_keys": [ ... ],
      "agents": [ ... ],
      "max_delegation_depth": 2,
      "updated_at": "2026-02-01T00:00:00Z"
    },
    {
      "agentpin_version": "0.1",
      "entity": "partner.com",
      "entity_type": "deployer",
      "public_keys": [ ... ],
      "agents": [ ... ],
      "max_delegation_depth": 1,
      "updated_at": "2026-02-10T00:00:00Z"
    }
  ],
  "revocations": [
    {
      "entity": "example.com",
      "revoked_credentials": [],
      "revoked_agents": [],
      "revoked_keys": []
    }
  ]
}

Creating Trust Bundles

JavaScript

import {
    createTrustBundle,
    verifyCredentialWithBundle,
    KeyPinStore,
} from 'agentpin';

// Create an empty bundle
const bundle = createTrustBundle();

// Add discovery documents
bundle.documents.push(makerDiscovery);
bundle.documents.push(deployerDiscovery);

// Add revocation documents
bundle.revocations.push(makerRevocation);
bundle.revocations.push(deployerRevocation);

// Verify a credential using the bundle (no HTTP calls)
const result = verifyCredentialWithBundle(
    credential,
    bundle,
    new KeyPinStore(),
    'verifier.com',
);

if (result.valid) {
    console.log('Verified via trust bundle:', result.agent_id);
}

Python

from agentpin import (
    create_trust_bundle,
    verify_credential_with_bundle,
    save_trust_bundle,
    load_trust_bundle,
    KeyPinStore,
)

# Create an empty bundle
bundle = create_trust_bundle()

# Add discovery and revocation documents
bundle["documents"].append(maker_discovery)
bundle["documents"].append(deployer_discovery)
bundle["revocations"].append(maker_revocation)

# Verify a credential using the bundle
result = verify_credential_with_bundle(
    credential,
    bundle,
    pin_store=KeyPinStore(),
    audience="verifier.com",
)

if result.valid:
    print(f"Verified via trust bundle: {result.agent_id}")

CLI

# Create a bundle from local documents
agentpin bundle create \
  --discovery ./maker-discovery.json \
  --discovery ./deployer-discovery.json \
  --revocation ./maker-revocations.json \
  --output ./trust-bundle.json

# Verify using a bundle
agentpin verify \
  --credential <jwt> \
  --bundle ./trust-bundle.json \
  --pin-store ./pins.json

Saving and Loading Bundles

Python

from agentpin import save_trust_bundle, load_trust_bundle

# Save bundle to disk
save_trust_bundle(bundle, "trust-bundle.json")

# Load bundle from disk
bundle = load_trust_bundle("trust-bundle.json")

JavaScript

import { saveTrustBundle, loadTrustBundle } from 'agentpin';
import fs from 'fs';

// Save to JSON file
fs.writeFileSync('trust-bundle.json', JSON.stringify(bundle, null, 2));

// Load from JSON file
const bundle = JSON.parse(fs.readFileSync('trust-bundle.json', 'utf-8'));

Looking Up Documents in a Bundle

The findBundleDiscovery function searches the bundle for a discovery document matching a given domain:

JavaScript

import { findBundleDiscovery } from 'agentpin';

const discovery = findBundleDiscovery(bundle, 'example.com');
if (discovery) {
    console.log('Found discovery for:', discovery.entity);
    console.log('Keys:', discovery.public_keys.length);
    console.log('Agents:', discovery.agents.length);
}

Python

from agentpin import find_bundle_discovery

discovery = find_bundle_discovery(bundle, "example.com")
if discovery:
    print(f"Found discovery for: {discovery['entity']}")

Enterprise Use Cases

Centralized Trust Management

In enterprise environments, a security team maintains the trust bundle and distributes it to all agent instances:

┌─────────────────────┐
│   Security Team     │
│                     │
│ 1. Collect discovery│
│    documents from   │
│    trusted domains  │
│                     │
│ 2. Build bundle     │
│                     │
│ 3. Distribute via   │
│    config management│
└────────┬────────────┘
    ┌────┴────┐
    ▼         ▼
┌────────┐ ┌────────┐
│Agent A │ │Agent B │
│        │ │        │
│ Verify │ │ Verify │
│ with   │ │ with   │
│ bundle │ │ bundle │
└────────┘ └────────┘

CI/CD Pipeline Integration

Pin the trust bundle in your repository for deterministic builds:

# .github/workflows/verify.yml
steps:
  - name: Verify agent credentials
    run: |
      agentpin verify \
        --credential "$AGENT_CREDENTIAL" \
        --bundle ./trust/bundle.json \
        --pin-store ./trust/pins.json

Bundle Rotation

Update trust bundles periodically to pick up key rotations and new agent declarations:

#!/bin/bash
# rotate-bundle.sh — Fetch fresh documents and rebuild the bundle

# Fetch latest discovery documents
curl -s https://maker.com/.well-known/agent-identity.json > /tmp/maker.json
curl -s https://deployer.com/.well-known/agent-identity.json > /tmp/deployer.json
curl -s https://maker.com/.well-known/agent-identity-revocations.json > /tmp/maker-rev.json

# Build fresh bundle
agentpin bundle create \
  --discovery /tmp/maker.json \
  --discovery /tmp/deployer.json \
  --revocation /tmp/maker-rev.json \
  --output ./trust-bundle.json

echo "Bundle updated at $(date -u +%Y-%m-%dT%H:%M:%SZ)"

Combining with TOFU Pinning

Trust bundles work seamlessly with TOFU key pinning. The pin store tracks which keys have been seen, regardless of whether they were discovered online or via a bundle:

from agentpin import KeyPinStore, verify_credential_with_bundle

# Persistent pin store
pin_store = KeyPinStore.from_json(open("pins.json").read())

result = verify_credential_with_bundle(
    credential, bundle, pin_store=pin_store, audience="verifier.com"
)

# Save updated pins
with open("pins.json", "w") as f:
    f.write(pin_store.to_json())

The first verification for a domain pins the key. Subsequent verifications (even with a different bundle version) will detect key changes.