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.
Upgrade from 0.6.0 or earlier.
0.7.0fixes a flaw in/nanda/resolve: an identifier scoped to a different registry (@other-registry:ns/foo, or adid:webunder another host) was reduced to a bare id and answered locally, carrying this registry's proof block, with nothing to tell the caller the scope had been ignored. Such an identifier is now rejected with400.
0.7.0and0.8.0also change behaviour deliberately: no certification block is emitted unless the source declared one,conformance_levelis computed rather than asserted,ns:agentis no longer split toagent, and the delta log is append-only. See CHANGELOG.md before upgrading.
Requires Python 3.11 or later. MIT licensed.
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/nanda-index-onboarding.md— getting an org listed on the NANDA Index: what you register, and the two paths the Index then fetches from you.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 |
Auditing this registry
This package serves records, which makes it a thing the corroboration stack
audits rather than a consumer of it. Two instances serving the same agents are
swept by sm-divergence in CI and
must corroborate to AGREE; a divergence means this registry is misrepresenting
its own data.
That check has a limit, and it is pinned as a test rather than left implied: two
instances of the same code misbehaving identically agree with each other. So the
converter also records what it supplied that the source did not — provenance,
carrying invented, defaulted and dropped — because nothing downstream can
infer it. See ARCHITECTURE.md.
License
MIT
Aligned with Project NANDA. Built by Stellarminds.ai.
Metadata
Release files for sm-bridge 0.10.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| sm_bridge-0.10.0.tar.gz | 68.6 kB | With provenance | Details for sm_bridge-0.10.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| sm_bridge-0.10.0-py3-none-any.whl | Python 3 | none | any | Details for sm_bridge-0.10.0-py3-none-any.whl |
Total release size: 151.2 kB
Release files / sm_bridge-0.10.0.tar.gz
| Download URL | sm_bridge-0.10.0.tar.gz |
|---|---|
| Size | 68.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8983436a4c86f06ceb57ee0c3a9d16321a3e42951de4a3210f233ff681abe634
|
|
BLAKE2b-256 checksum How to use checksums |
244d08a2f6c46c8b9a9b092a35d9315178e425456d813bc7951f69f73a9ae011
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.
Transparency logRelease files / sm_bridge-0.10.0-py3-none-any.whl
| Download URL | sm_bridge-0.10.0-py3-none-any.whl |
|---|---|
| Size | 82.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c39f96f1f41239bbf51a5a7c4dbb7975f626ecfbbed4a5fee79eec78ae3b721a
|
|
BLAKE2b-256 checksum How to use checksums |
74afca632632271faa2497deffafb3ea5ca31cb5c4de4b7f745aa089a17bec85
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.
Transparency logSecurity for sm-bridge 0.10.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for sm_bridge-0.10.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 29, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.