Skip to main content

A Python library for building NANDA-compatible AI agent registries

Project description

sm-bridge

PyPI Python License

The universal on-ramp to the NANDA agent-internet.

sm-bridge lets any agent source — your own registry, an AI catalog, an ANS registry, or a single domainless agent — join the NANDA Index through one small library, and emerge carrying a normalized, cryptographically verifiable proof of trust. The Index stays a quilt of registries (one entry per registry, never one per agent); the bridge is how you get onto it.

The core is just FastAPI + Pydantic. Verification and transparency-log features live in optional extras, so you only pull cryptography when you use it.

What it does

  • Onboard any source to the quilt. A registry-scale source (like ANS, with its own resolver) joins as one entry and resolution is delegated back to it — the bridge never mirrors its agents. A source with no registry of its own (a catalog, a did:key agent) is hosted locally.
  • Verify each source with a pluggable trust profile and normalize the result to one proof block: VERIFIED / FAILED / NOT_VERIFIED. Every VERIFIED is a real signature, DNS, or Merkle check — absent live infrastructure you get an honest NOT_VERIFIED(reason), never a mocked pass.
  • Serve the NANDA discovery surfaces as drop-in FastAPI routers: /nanda/index, /nanda/resolve, /nanda/deltas, /.well-known/nanda.json, plus an AI-Catalog gateway.

Trust profiles today: ed25519-agentcard, ans-scitt (ANS SCITT receipts), ans-txt (ANS DNS discovery), dns-aid (SVCB + DNSSEC + DANE), jws-catalog (signed AI-Catalog), and nanda-delegation (did:key delegation chains). See docs/trust-profiles.md.

Install

pip install sm-bridge                 # core: FastAPI routers, models, delta sync
pip install "sm-bridge[trust]"        # + verification adapters (ed25519/SCITT/DNS-AID/JWS/delegation)
pip install "sm-bridge[trust,tlog]"   # + RFC 6962 transparency log & conformance self-test

Requires Python 3.11+.

Onboard and verify

from sm_bridge import SmBridge, SimpleAgent, SimpleAgentConverter, ANSEntryConverter, TrustRegistry
from sm_bridge.trust.ed25519_agentcard import Ed25519AgentCardProfile
from sm_bridge.trust.ans_scitt import AnsScittProfile

# A source with no registry of its own → hosted locally.
conv = SimpleAgentConverter(registry_id="quilt", provider_name="Q", provider_url="https://q.example")
conv.register(SimpleAgent(id="finance", name="Finance Agent", description="does finance"))

bridge = SmBridge(
    registry_id="quilt", provider_name="Q", provider_url="https://q.example",
    converter=conv,
    trust_registry=TrustRegistry([Ed25519AgentCardProfile(), AnsScittProfile()]),
    # A registry-scale source (ANS) → one entry, resolution delegated back to it.
    entries=[ANSEntryConverter(registry_name="acme-ans", resolver_endpoint="https://ans.acme.example")],
)

# GET /nanda/resolve?agent=finance          → agent facts + a normalized proof block
# GET /nanda/registries/acme-ans/resolve    → a delegation pointer (the quilt never mirrors ANS's agents)

Command line

The same verification is available from the terminal ([trust] extra):

sm-bridge verify ans-scitt   --receipt receipt.cbor --root-keys root-keys.txt
sm-bridge verify jws-catalog --catalog ai-catalog.json --signature sig.jws --jwks jwks.json
sm-bridge verify agent-card  --card card.json --signature-b64 <b64> --pubkey key.pem
sm-bridge verify dns-aid     --fqdn agent.example.com [--dane]
sm-bridge verify delegation  --evidence delegation-bundle.json

Exit code 0 = VERIFIED, 1 = FAILED, 2 = NOT_VERIFIED.

Runnable demos

Two offline, self-contained scenarios (see examples/):

python examples/demo1_switchboard.py            # one query → an ANS registry (delegated) + a non-ANS catalog (verified)
python examples/demo2_domainless_delegation.py  # a domainless did:key earns scoped, revocable delegation

Serve a NANDA-compatible registry

If you just want to expose your own agents on NANDA, mount the routers and register agents:

from fastapi import FastAPI
from sm_bridge import SmBridge, SimpleAgent

bridge = SmBridge(
    registry_id="my-registry",
    provider_name="My Company",
    provider_url="https://example.com",
    base_url="https://registry.example.com",
)

bridge.register_agent(SimpleAgent(
    id="my-agent",
    name="My Agent",
    description="An agent that does things",
    namespace="production",
    labels=["chat", "tool-use"],
    skills=[
        {"id": "summarize", "description": "Summarizes text"},
        {"id": "translate", "description": "Translates between languages"},
    ],
))

app = FastAPI()
app.include_router(bridge.router)            # /nanda/* endpoints
app.include_router(bridge.wellknown_router)  # /.well-known/nanda.json (RFC 8615)

You get:

  • GET /nanda/index — list public agents (with a correct total_count for pagination)
  • GET /nanda/resolve?agent=my-agent — resolve a single agent
  • GET /nanda/deltas?since=0 — change feed for synchronization
  • GET /.well-known/nanda.json — registry discovery document

Integrate an existing registry

Implement the converter protocol to expose your own data model, without copying agents into a second store:

from typing import Iterator

from sm_bridge import (
    AbstractAgentConverter, SmAgentFacts, SmEndpoints, SmCapabilities, SmSkill,
    DeltaStore, create_sm_router,
)


class MyRegistryConverter(AbstractAgentConverter):
    def __init__(self, db):
        super().__init__(registry_id="my-registry", provider_name="My Company",
                         provider_url="https://example.com")
        self.db = db

    def to_sm(self, agent) -> SmAgentFacts:
        return SmAgentFacts(
            id=f"did:web:example.com:agents:{agent.id}",
            handle=self.build_handle(agent.namespace, agent.id),
            agent_name=agent.display_name, label=agent.category,
            description=agent.description, version=agent.version,
            provider=self.build_provider(),
            endpoints=SmEndpoints(static=[agent.endpoint_url]),
            capabilities=SmCapabilities(modalities=agent.capabilities),
            skills=[SmSkill(id=s.id, description=s.desc) for s in agent.skills],
        )

    def list_agents(self, limit: int, offset: int) -> Iterator:
        return self.db.query_agents(limit=limit, offset=offset)

    def get_agent(self, agent_id: str):
        return self.db.get_agent(agent_id)

    def is_public(self, agent) -> bool:
        return agent.visibility == "public"

To attach real verification at resolve time, add a trust_evidence(agent) -> (profile_id, evidence) method to your converter and inject a TrustRegistry — the resolved facts then carry a ProofResult.

Delta sync & AI-Catalog gateway

  • Delta storeDeltaStore tracks upserts/deletes with a monotonic cursor for registry-to-registry synchronization; subclass PersistentDeltaStore to back it with a database. The default HTTP sync transport is the [federation] extra.
  • AI-Catalog gatewaycreate_gateway_router(delta_store, base_url=..., domain=...) serves /.well-known/ai-catalog.json, /agents/{slug}, and A2A /cards/{slug}.json alongside the /nanda/* router.

Transparency log & conformance

The [tlog] extra adds an RFC 6962 Merkle tree over the delta log, a signed checkpoint, and inclusion/consistency proofs, plus a conformance self-test (sm_bridge.conformance) that verifies the checkpoint signature, recomputes the root, checks append-only growth, and detects tampering.

Documentation

Related packages

Part of the sm-* trust stack:

Package Role
sm-bridge (this package) Onboard any agent source to the NANDA Index, with a normalized verifiable proof of trust
sm-arp Agency Receipt Protocol — signed receipts for what an agent did
sm-conformance Signed, offline-verifiable conformance badges

License

MIT


Aligned with Project NANDA. Built by Stellarminds.ai.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sm_bridge-0.5.0.tar.gz (59.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sm_bridge-0.5.0-py3-none-any.whl (72.6 kB view details)

Uploaded Python 3

File details

Details for the file sm_bridge-0.5.0.tar.gz.

File metadata

  • Download URL: sm_bridge-0.5.0.tar.gz
  • Upload date:
  • Size: 59.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for sm_bridge-0.5.0.tar.gz
Algorithm Hash digest
SHA256 caf309dbe48dbf275c82a6e02c29c18d0a1e913fcfa0dc95630600474adf56e8
MD5 52928547214b88813949cd5895281e1b
BLAKE2b-256 45b660cb8db24d823ebcf09229ae89c72df5d1f7ee846078538d6a8787abada1

See more details on using hashes here.

Provenance

The following attestation bundles were made for sm_bridge-0.5.0.tar.gz:

Publisher: release.yml on Sharathvc23/sm-bridge

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sm_bridge-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: sm_bridge-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 72.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for sm_bridge-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ae61c0165a422d684c608125dee0d3eb6ab1e18f7e230ea19ce6f8b6988e744a
MD5 00484688e12e524265c623a71226a907
BLAKE2b-256 f5bd90043d96f0bea0355fb5628230d712036c4bbfd564cc03dbaa9ccb30b8a9

See more details on using hashes here.

Provenance

The following attestation bundles were made for sm_bridge-0.5.0-py3-none-any.whl:

Publisher: release.yml on Sharathvc23/sm-bridge

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page