Skip to main content

Python SDK for the Shadownet protocol.

Project description

Shadownet — Python SDK

PyPI Python CI License: MIT Typed

Python SDK for the Shadownet protocol. Implements the v0.1 RFCs in idiomatic, async, fully-typed Python.

Note (0.2.0 — repository move). This SDK previously lived at shadownet-protocol/shadownet-py. Starting with 0.2.0 it ships from the shadownet-protocol/shadownet monorepo at python-sdk/. The PyPI package name (shadownet) is unchanged — pip install shadownet and existing imports continue to work. See MIGRATION.md for details.

What this is

A reusable library — not a server, not a canonical core. It exposes the protocol primitives needed to build a Shadow:

  • DID resolutiondid:key (local) and did:web (async, cached, 16 KiB cap per RFC-0002).
  • Verifiable Credentials — VC-JWT issuance + verification, freshness proofs, BitstringStatusList revocation (fail-closed >L1 per RFC-0003).
  • SCA client — proof-session, issuance, freshness, callback-HMAC verification (RFC-0004).
  • SNS client — async resolver with TTL + negative cache, signed-record verification (RFC-0005).
  • A2A profile — session-token + Verifiable Presentation handshake; framework-agnostic verifier; optional FastAPI dependency (RFC-0006).
  • Webhooks — outbound dispatcher with the spec retry schedule + degraded-state tracking; receiver-side verifier (RFC-0007).
  • MCP — Pydantic models + a Sidecar Protocol + a one-call helper that wires every RFC-0007 tool onto a FastMCP server.

It is consumed by hermes-social — the Sidecar reference implementation — and by downstream Sidecar deployments that compose the SDK with their own infrastructure.

Interop with the Go SDK (in this same repo) and a planned TypeScript SDK is verified at the wire level by the conformance/ suite.

Install

pip install shadownet
# or
uv add shadownet

Python 3.12+ required. For the optional FastAPI helpers:

pip install 'shadownet[fastapi]'

Quick examples

Issue and verify a credential

from shadownet.crypto.ed25519 import Ed25519KeyPair
from shadownet.did.key import derive_did_key
from shadownet.did.resolver import Resolver
from shadownet.vc.credential import issue_credential, new_credential, verify_credential

issuer_kp = Ed25519KeyPair.generate()
issuer_did = derive_did_key(issuer_kp.public_bytes)

subject_kp = Ed25519KeyPair.generate()
subject_did = derive_did_key(subject_kp.public_bytes)

cred = new_credential(
    issuer=issuer_did,
    subject=subject_did,
    level="urn:shadownet:level:L2",
    subject_type="person",
)
token = issue_credential(issuer_key=issuer_kp, issuer_kid=issuer_did, credential=cred)

verified = await verify_credential(token, resolver=Resolver())
assert verified.level == "urn:shadownet:level:L2"

Mint and verify a presentation

from shadownet.vc.presentation import mint_presentation, verify_presentation
from shadownet.trust import TrustStore

verifier_did = "did:key:z6MkVerifier..."
vp_jwt = mint_presentation(
    holder_key=subject_kp,
    holder_did=subject_did,
    audience_did=verifier_did,
    credentials=[token],
)

trust = TrustStore.from_pairs([(issuer_did, ["urn:shadownet:level:L2"])])
result = await verify_presentation(
    vp_jwt,
    resolver=Resolver(),
    expected_audience=verifier_did,
    trust_store=trust,
)
assert len(result.credentials) == 1

Run the inbound A2A handshake

from shadownet.a2a.server import verify_handshake
from shadownet.sca.predicate import LevelLeaf

ctx = await verify_handshake(
    request_headers,                 # any Mapping[str, str]
    expected_audience=my_did,
    resolver=Resolver(),
    trust_store=trust,
    required_predicate=LevelLeaf(level="urn:shadownet:level:L2"),
)
# ctx.caller_did is the verified peer DID
# ctx.presentation.credentials are the credentials that survived every check

Register the RFC-0007 MCP tools

from mcp.server.fastmcp import FastMCP
from shadownet.mcp.register import register_shadownet_tools

server = FastMCP(name="my-sidecar")
register_shadownet_tools(server, my_sidecar_implementation)
# all required RFC-0007 tools are now exposed; opt into the optional ones with
# include_optional={"present", "audit"}

The full set of public APIs is curated under shadownet.{crypto, did, vc, sca, sns, trust, a2a, webhook, mcp}. See the tests/integration/test_birthday_flow.py for an end-to-end Sarah → Lukas walkthrough.

Conformance

tests/conformance/ validates every Pydantic wire model against the JSON Schemas in shadownet-specs/schemas/. CI fails on any drift.

Develop

uv sync --all-extras           # runtime + dev + extras
uv run pytest                  # full suite (incl. conformance), with coverage
uv run pytest -m network       # opt-in network tests
uv run ruff check .            # lint
uv run ruff format .           # format
uv run mypy src/shadownet      # strict typing

See CONTRIBUTING.md at the repo root for the full contributor guide.

Specifications

Versioning

Releases track the protocol version they implement (0.x.y while the spec is at v0.1). Pre-releases use the PEP 440 form (0.2.0rc1) and the matching git tag (python-sdk/v0.2.0-rc.1). The monorepo tag scheme prefixes each subtree's tags with its directory: python-sdk/vX.Y.Z for the Python SDK, core/vX.Y.Z for the Go SDK, core/pgstore/vX.Y.Z for the Postgres backend. Per-release changes are recorded in CHANGELOG.md.

License

MIT.

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

shadownet-0.3.0.tar.gz (53.6 kB view details)

Uploaded Source

Built Distribution

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

shadownet-0.3.0-py3-none-any.whl (76.7 kB view details)

Uploaded Python 3

File details

Details for the file shadownet-0.3.0.tar.gz.

File metadata

  • Download URL: shadownet-0.3.0.tar.gz
  • Upload date:
  • Size: 53.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for shadownet-0.3.0.tar.gz
Algorithm Hash digest
SHA256 152fe0d8defde0b12be5f8ff269e99701ebc6d97efa4fb3db30db01a112bcae3
MD5 573807c874a9fb91ac0f7c73e72281a7
BLAKE2b-256 b2c41c77808628aa84b619d0a4e08d707937c0a6cc1bad1783fb75f0008c928b

See more details on using hashes here.

Provenance

The following attestation bundles were made for shadownet-0.3.0.tar.gz:

Publisher: release-python-sdk.yml on shadownet-protocol/shadownet

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

File details

Details for the file shadownet-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: shadownet-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 76.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for shadownet-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fa0d5d12bda6dc83b9c59eef6e2af54e5f48f6f2ba5cc8661dc5192ddc03a8e1
MD5 dba5842bbbf1825225db4c1018d6d72c
BLAKE2b-256 f430b546558d36f80ab1703555d2eccdb0e062b46cb1d2ffc359f0f8e703ea8a

See more details on using hashes here.

Provenance

The following attestation bundles were made for shadownet-0.3.0-py3-none-any.whl:

Publisher: release-python-sdk.yml on shadownet-protocol/shadownet

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