Federated agent identity in a single function call — Python SDK for the Carapace Protocol
Project description
carapace — Python SDK
Federated agent identity in a single function call.
pip install carapace-sdk
Status: Alpha — API is stable, ARIA registry live at
https://api.relayforge.tools/aria/v1.
Quick start
import os
from carapace import Carapace
# One-time setup — auto-generates a keypair when owner_key is omitted
carapace = Carapace.create(
registry_url="https://api.relayforge.tools/aria/v1",
owner_key=os.environ.get("CARAPACE_OWNER_KEY") # optional — auto-generates if absent
)
# Register an agent — one function call
card = carapace.register(
name="MyAgent",
description="A helpful research agent",
framework="langchain",
capabilities=[
{"id": "research", "name": "Research", "description": "Searches and summarizes topics"}
],
endpoints=[
{"protocol": "a2a", "url": "https://my-server.example.com/agent"}
]
)
# Verify another agent — one function call
result = carapace.verify(card.id)
print(result.verified) # True
# Discover agents by capability — one function call
peers = carapace.discover(capability="research")
# Verify offline — no network needed
ok = carapace.verify_local(card, card.signature, card.owner.public_key)
What the SDK handles silently:
- Ed25519 key generation and derivation (private key never leaves your process)
- JCS canonicalization (RFC 8785) before signing
- Identity card construction from minimal input
- Signature verification
API reference
Carapace.create(registry_url, owner_key=None) → Carapace
Factory constructor. Auto-generates an Ed25519 keypair when owner_key is omitted.
# With an existing key (production):
c = Carapace.create(registry_url=url, owner_key=os.environ["CARAPACE_OWNER_KEY"])
# Auto-generate key (quick test / one-off):
c = Carapace.create(registry_url=url)
print(c.public_key()) # store or share the public key
Carapace(registry_url, owner_key=None)
Direct constructor. Offline operations (verify_local) work even without owner_key;
signing and registering raise a ValueError with a clear message if owner_key is absent.
carapace.register(...) → AgentCard
Build, sign, and register a new agent in one call.
| Param | Type | Required |
|---|---|---|
name |
str |
Yes |
description |
str |
Yes |
framework |
str |
Yes |
capabilities |
list[dict] |
Yes |
endpoints |
list[dict] |
Yes |
version |
str |
No |
tags |
list[str] |
No |
metadata |
dict |
No |
carapace.verify(agent_id) → VerifyResult
Registry round-trip: fetch card, re-verify signature.
result = carapace.verify("agent-uuid")
print(result.verified) # bool
print(result.agent) # AgentCard | None
carapace.discover(...) → list[AgentCard]
Search the registry. All params optional.
peers = carapace.discover(capability="research", framework="langchain", limit=10)
carapace.verify_local(card, signature, public_key) → bool
Ed25519 verification — fully offline, no network call.
ok = carapace.verify_local(card, card.signature, card.owner.public_key)
carapace.get(agent_id) → AgentCard
Fetch a card directly from the registry by UUID.
carapace.public_key() → str
Return the hex-encoded public key derived from owner_key.
Key management
Generate a keypair once; store the private key in a secrets manager or environment variable.
from carapace.keys import generate_key_pair
kp = generate_key_pair()
print(kp.private_key) # 64-char hex — keep secret, store in env/vault
print(kp.public_key) # 64-char hex — safe to share
A2A compatibility
Generate a valid A2A Agent Card for /.well-known/agent.json discovery:
from carapace.a2a import generate_well_known_card
import json
a2a = generate_well_known_card(card)
# Serve as JSON at /.well-known/agent.json
print(json.dumps(a2a.to_dict(), indent=2))
MCP compatibility
Export capabilities as an MCP tools/list response:
from carapace.mcp import generate_tools_list, generate_mcp_server_config
import json
tools = generate_tools_list(card) # {"tools": [...]}
config = generate_mcp_server_config(card) # claude_desktop_config.json entry
print(json.dumps(tools.to_dict(), indent=2))
Async support (AsyncCarapaceClient)
Use AsyncCarapaceClient for FastAPI, LangChain async chains, CrewAI async tasks,
or any other async-first Python framework. It has an identical API to CarapaceClient
but all network calls are async def.
import asyncio
import os
from carapace import AsyncCarapaceClient
async def main():
async with AsyncCarapaceClient(
registry_url="https://api.relayforge.tools/aria/v1",
owner_private_key=os.environ["CARAPACE_OWNER_KEY"],
) as client:
card = await client.register(
name="MyAsyncAgent",
description="Runs in an async event loop",
framework="fastapi",
capabilities=[{"id": "query", "name": "Query", "description": "Handles queries"}],
endpoints=[{"protocol": "https", "url": "https://my-api.example.com"}],
)
result = await client.verify(card.id)
agents = await client.discover(capability="query")
asyncio.run(main())
FastAPI tip: inject
AsyncCarapaceClientas a dependency and reuse a singlehttpx.AsyncClientacross requests for connection pooling.
Low-level API (CarapaceClient)
For advanced use or custom signing flows, the lower-level sync client is available:
from carapace import CarapaceClient
from carapace.keys import generate_key_pair
kp = generate_key_pair()
client = CarapaceClient(
registry_url="https://api.relayforge.tools/aria/v1",
owner_private_key=kp.private_key
)
card = client.register(name="MyAgent", ...)
result = client.verify("agent-uuid")
agents = client.discover(capability="research")
Security model
- Private key never leaves your process. Only the derived public key is sent to the registry.
- Signatures use Ed25519 (RFC 8032) over JCS-canonical (RFC 8785) JSON.
- No registry dependency for verification. Use
verify_localorcarapace.crypto.verify_payloadoffline. - Revocation is soft-delete — card stays in registry with
status: "revoked".
Development
git clone https://github.com/ryan10sa-star/relayforge
cd relayforge/carapace-protocol/sdk/python
pip install -e ".[dev]"
pytest
Roadmap
- ✅ Ed25519 + JCS signing (PyNaCl)
- ✅ Key generation helper (
generate_key_pair) - ✅
Carapaceconvenience class — directive-spec API - ✅
register()/verify()/discover()/verify_local() - ✅
generate_well_known_card()— A2A/.well-known/agent.json - ✅
generate_tools_list()— MCPtools/list - ✅ Cross-language interop verified (Python ↔ JS byte-identical signatures)
- ✅ GitHub Actions CI (Python 3.10, 3.11, 3.12)
- ✅ PEP 561 typed package (
py.typedmarker) - ✅ Async client (
AsyncCarapaceClient) for FastAPI, LangChain, CrewAI - ✅ ARIA registry live at
https://api.relayforge.tools/aria/v1(2026-03-18) - ⏩ Publish alpha to PyPI (awaiting PyPI token)
MIT License — RelayForge
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 carapace_sdk-0.2.0.tar.gz.
File metadata
- Download URL: carapace_sdk-0.2.0.tar.gz
- Upload date:
- Size: 25.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
12124326523b548439404059e0ddf5e3f58b1c9512781d6b47576976796c2b59
|
|
| MD5 |
1d10374bab6db90cb78b1a1091a262ed
|
|
| BLAKE2b-256 |
fb20f160633aafb6ac6ea0baa71eed7dfa6c6ca5f4cceef08881c60715b62214
|
File details
Details for the file carapace_sdk-0.2.0-py3-none-any.whl.
File metadata
- Download URL: carapace_sdk-0.2.0-py3-none-any.whl
- Upload date:
- Size: 24.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
51e9a77358523839ab05d493e72a62e1555c4cfc2094f00a6fdad2e66ea12783
|
|
| MD5 |
f64d279ef0fae212388c7fdabcf9aa40
|
|
| BLAKE2b-256 |
5ae8a8f38bdee148f618e839558e2ddfb3e9952bc5ea413f50d3fc324a9ce779
|