A Python library for building NANDA-compatible AI agent registries
Project description
sm-bridge
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:keyagent) is hosted locally. - Verify each source with a pluggable trust profile and normalize the result to one
proof block:
VERIFIED/FAILED/NOT_VERIFIED. EveryVERIFIEDis a real signature, DNS, or Merkle check — absent live infrastructure you get an honestNOT_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 correcttotal_countfor pagination)GET /nanda/resolve?agent=my-agent— resolve a single agentGET /nanda/deltas?since=0— change feed for synchronizationGET /.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 store —
DeltaStoretracks upserts/deletes with a monotonic cursor for registry-to-registry synchronization; subclassPersistentDeltaStoreto back it with a database. The default HTTP sync transport is the[federation]extra. - AI-Catalog gateway —
create_gateway_router(delta_store, base_url=..., domain=...)serves/.well-known/ai-catalog.json,/agents/{slug}, and A2A/cards/{slug}.jsonalongside 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 Feed — alongside /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
docs/trust-profiles.md— the trust profiles and the proof block.docs/quilt-onboarding.md— entry mode vs hosting mode, and verify-at-admission.CHANGELOG.md— release notes.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3c4fc4dec5bc263a40957de2ec71f302996d2caa3f7cd253db7aacccb1da7822
|
|
| MD5 |
a8b484caec6b5a5aa93f4347ae7da379
|
|
| BLAKE2b-256 |
2444230b6e624e29dd52fc11e68fe26f2d15b97e84853ef137c8cb853215686c
|
Provenance
The following attestation bundles were made for sm_bridge-0.6.0.tar.gz:
Publisher:
release.yml on Sharathvc23/sm-bridge
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sm_bridge-0.6.0.tar.gz -
Subject digest:
3c4fc4dec5bc263a40957de2ec71f302996d2caa3f7cd253db7aacccb1da7822 - Sigstore transparency entry: 2299626397
- Sigstore integration time:
-
Permalink:
Sharathvc23/sm-bridge@bf18b72901303395826011864e5e4918ceb9352a -
Branch / Tag:
refs/tags/v0.6.0 - Owner: https://github.com/Sharathvc23
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@bf18b72901303395826011864e5e4918ceb9352a -
Trigger Event:
release
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a9d2c05e69d6d491ab098db5353e350f5474f327101207be792be70ef8e40d46
|
|
| MD5 |
8ded9cd9e785aaa02b1e17cc085e8ec4
|
|
| BLAKE2b-256 |
8a83bb615edbbfde6e9a57d9712aec5b756db10f81b08b56ef1d4cfc96ff2347
|
Provenance
The following attestation bundles were made for sm_bridge-0.6.0-py3-none-any.whl:
Publisher:
release.yml on Sharathvc23/sm-bridge
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
sm_bridge-0.6.0-py3-none-any.whl -
Subject digest:
a9d2c05e69d6d491ab098db5353e350f5474f327101207be792be70ef8e40d46 - Sigstore transparency entry: 2299626402
- Sigstore integration time:
-
Permalink:
Sharathvc23/sm-bridge@bf18b72901303395826011864e5e4918ceb9352a -
Branch / Tag:
refs/tags/v0.6.0 - Owner: https://github.com/Sharathvc23
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@bf18b72901303395826011864e5e4918ceb9352a -
Trigger Event:
release
-
Statement type: