Python SDK
The Layr8 Python SDK is an async library for building DIDComm agents. It handles WebSocket connections, Phoenix Channel protocol, DIDComm message formatting, and thread correlation. You write domain logic.
A basic agent is ~20 lines of Python. The SDK manages everything between your handler and the network.
Install
pip install layr8Requires Python >= 3.11.
Core Concepts
Config
from layr8 import Client, Config
client = Client(Config( node_url="wss://your-node.node.layr8.io/plugin_socket/websocket", api_key="your-api-key", agent_did="did:web:your-node.node.layr8.io:my-agent",))All fields fall back to environment variables if empty: LAYR8_NODE_URL, LAYR8_API_KEY, LAYR8_AGENT_DID. If agent_did is omitted, the node assigns an ephemeral DID on connect.
Handlers
Register handlers before calling connect. Use the decorator syntax — the handler’s return value determines what happens:
from layr8 import Message
@client.handle("https://layr8.io/protocols/echo/1.0/request")async def echo(msg: Message) -> Message | None: # Return Message → send response to sender # Return None → no response (fire-and-forget) # Raise → send problem report to senderThe protocol base URI is derived automatically from the message type and registered with the node on connect.
Send (Fire-and-Forget)
await client.send(Message( type="https://didcomm.org/basicmessage/2.0/message", to=["did:web:partner-node:agent"], body={"content": "Hello!"},))Request (Request/Response)
resp = await client.request( Message( type="https://layr8.io/protocols/echo/1.0/request", to=["did:web:partner-node:echo-agent"], body={"message": "ping"}, ), timeout=5.0,)# resp is the correlated response, matched by thread IDMessages
@dataclassclass Message: id: str = "" # auto-generated if empty type: str = "" # DIDComm message type URI from_: str = "" # auto-filled with agent DID (wire: "from") to: list[str] # recipient DIDs thread_id: str = "" # auto-generated for request parent_thread_id: str = "" body: Any = None # serialized to JSON context: MessageContext | None = NoneUse msg.unmarshal_body() to deserialize as a dict, or msg.unmarshal_body(MyDataclass) to construct a typed dataclass. On inbound messages, msg.context provides node metadata: authorized, recipient, and sender_credentials.
Async Context Manager
async with client: print(f"running as {client.did}") await asyncio.Event().wait() # run foreverasync with calls connect on enter and close on exit.
Durable Handlers (Persist-then-Ack)
For messages that must not be lost, use manual ack to persist before acknowledging:
@client.handle("https://layr8.io/protocols/order/1.0/created", manual_ack=True)async def handle_order(msg: Message) -> None: # Write to disk first — if this fails, the message is # NOT acked and the cloud-node will redeliver it. with open("messages.jsonl", "a") as f: f.write(json.dumps({"id": msg.id, "body": msg.body}) + "\n") f.flush()
msg.ack() # safe to ack nowSee examples/durable_handler.py for a complete working example.
Claude Code Skill
The SDK includes a Claude Code skill that teaches Claude the full API. Install it into any agent project:
mkdir -p .claude/skillscp /path/to/python-sdk/.claude/skills/build-layr8-agent-python.md .claude/skills/Once installed, Claude Code knows how to build Layr8 agents in every session. Example prompts:
- “Build me a FastAPI bridge agent that converts REST calls to DIDComm messages”
- “Add a handler for order.created messages that validates the sender’s credentials”
- “Convert this Flask endpoint into a DIDComm agent”
Links
- Python SDK on GitHub — Full README, source code, and examples
- Example Agents — Working demo agents from beginner to advanced
- DIDComm Reference — Protocol details and message patterns
- Getting Started — End-to-end setup walkthrough