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.

Verifiable Agent Feed ([feed])

The [feed] extra projects the delta log as a signed, hash-chained Verifiable Agent Feedalongside /nanda/deltas, not replacing it. sm_bridge.feed.build_delta_feed(deltas, identity, ...) returns a signed feed-page a peer subscribes to with ?since=<cursor>; read_delta_feed(page) verifies it for authenticity and completeness (no dropped or reordered delta) and returns the verified records. Where /nanda/deltas asks a puller to trust the server for completeness, the feed lets a subscriber prove it. The extra is opt-in; the core never imports sm-feed.

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.6.0.tar.gz (61.2 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.6.0-py3-none-any.whl (74.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: sm_bridge-0.6.0.tar.gz
  • Upload date:
  • Size: 61.2 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.6.0.tar.gz
Algorithm Hash digest
SHA256 3c4fc4dec5bc263a40957de2ec71f302996d2caa3f7cd253db7aacccb1da7822
MD5 a8b484caec6b5a5aa93f4347ae7da379
BLAKE2b-256 2444230b6e624e29dd52fc11e68fe26f2d15b97e84853ef137c8cb853215686c

See more details on using hashes here.

Provenance

The following attestation bundles were made for sm_bridge-0.6.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.6.0-py3-none-any.whl.

File metadata

  • Download URL: sm_bridge-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 74.7 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.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a9d2c05e69d6d491ab098db5353e350f5474f327101207be792be70ef8e40d46
MD5 8ded9cd9e785aaa02b1e17cc085e8ec4
BLAKE2b-256 8a83bb615edbbfde6e9a57d9712aec5b756db10f81b08b56ef1d4cfc96ff2347

See more details on using hashes here.

Provenance

The following attestation bundles were made for sm_bridge-0.6.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