Python SDK for the Shadownet protocol.
Project description
shadownet-py
Python SDK for the Shadownet protocol. Implements the v0.1 RFCs in idiomatic, async, fully-typed Python.
What this is
A reusable library — not a server, not a canonical core. It exposes the protocol primitives needed to build a Shadow:
- DID resolution —
did:key(local) anddid: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
SidecarProtocol + a one-call helper that wires every RFC-0007 tool onto aFastMCPserver.
It is consumed by:
hermes-social— the Sidecar reference implementation.shadownet-cloud— the multi-tenant Sidecar host (forthcoming).
Interop with shadownet-go and shadownet-ts is verified at the wire level by shadownet-conformance.
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
Engineering conventions and contribution rules live in CLAUDE.md.
Specifications
- Protocol RFCs:
shadownet-specs/rfcs - Wire-level walkthrough:
shadownet-specs/examples/birthday-flow.md - Development plan:
shadownet-specs/DEVELOPMENT.md
Versioning
Releases track the protocol version they implement (0.1.x while the spec is at v0.1). Pre-releases use the PEP 440 form (0.1.0rc1) and the matching git tag (v0.1.0-rc.1). Per-release changes are recorded in CHANGELOG.md.
License
MIT.
Project details
Release history Release notifications | RSS feed
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 shadownet-0.1.3.tar.gz.
File metadata
- Download URL: shadownet-0.1.3.tar.gz
- Upload date:
- Size: 40.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3d39149162a419e53054e2040d685e54cbdc23a39c297f6032637a152926ef81
|
|
| MD5 |
fa453aebd54df9139e3e04d3d0dc2592
|
|
| BLAKE2b-256 |
7dcebef3a6af675c8685326101566acfadc363a63b2c609cdd96c25d7d10f1b4
|
Provenance
The following attestation bundles were made for shadownet-0.1.3.tar.gz:
Publisher:
release.yml on shadownet-protocol/shadownet-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shadownet-0.1.3.tar.gz -
Subject digest:
3d39149162a419e53054e2040d685e54cbdc23a39c297f6032637a152926ef81 - Sigstore transparency entry: 1436403286
- Sigstore integration time:
-
Permalink:
shadownet-protocol/shadownet-py@4963f21386fcc0e7aa2d3682d066c05e0c7db368 -
Branch / Tag:
refs/tags/v0.1.3 - Owner: https://github.com/shadownet-protocol
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4963f21386fcc0e7aa2d3682d066c05e0c7db368 -
Trigger Event:
push
-
Statement type:
File details
Details for the file shadownet-0.1.3-py3-none-any.whl.
File metadata
- Download URL: shadownet-0.1.3-py3-none-any.whl
- Upload date:
- Size: 59.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8a83777555edcaebd86196fd4064f970fcf38ab355dab66a044a5127ae1b06d6
|
|
| MD5 |
90fbbaa5601cf77f43097983c18b3da8
|
|
| BLAKE2b-256 |
50c1b6b7cc82669cb9f9215fbf5120c533e5e41cf331503a942e4527c6c44c71
|
Provenance
The following attestation bundles were made for shadownet-0.1.3-py3-none-any.whl:
Publisher:
release.yml on shadownet-protocol/shadownet-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
shadownet-0.1.3-py3-none-any.whl -
Subject digest:
8a83777555edcaebd86196fd4064f970fcf38ab355dab66a044a5127ae1b06d6 - Sigstore transparency entry: 1436403300
- Sigstore integration time:
-
Permalink:
shadownet-protocol/shadownet-py@4963f21386fcc0e7aa2d3682d066c05e0c7db368 -
Branch / Tag:
refs/tags/v0.1.3 - Owner: https://github.com/shadownet-protocol
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@4963f21386fcc0e7aa2d3682d066c05e0c7db368 -
Trigger Event:
push
-
Statement type: