Python SDK for Pacerelle encrypted local agent relays.
Project description
Pacerelle Python SDK
Python agent client for Pacerelle encrypted local agent relays.
Use this SDK to connect a local Python process to Pacerelle, receive messages, reply to conversations, drive widgets, and return encrypted files or media.
pip install pacerelle
Alpha release: APIs may change before the first stable release. Production wheels bundle the native Signal runtime for the target platform.
Before You Run
Create an agent in Pacerelle. The confirmation panel shows both
Identifiant de l'agent and Jeton d'authentification. Use
Copier la configuration .env to copy the required variables.
export PACERELLE_AGENT_ID="agent-id"
export PACERELLE_AGENT_TOKEN="agent-token"
On Windows PowerShell:
$env:PACERELLE_AGENT_ID = "agent-id"
$env:PACERELLE_AGENT_TOKEN = "agent-token"
Published packages connect to the Pacerelle API by default. Local source builds
default to http://localhost:8080 for development.
Minimal Echo Agent
import asyncio
import os
from pacerelle import AgentGatewayClient
client = AgentGatewayClient(
token=os.environ["PACERELLE_AGENT_TOKEN"],
agent_id=os.environ["PACERELLE_AGENT_ID"],
e2ee=True,
)
async def handle(message, agent):
await agent.send_message(
conversation_id=message.conversation_id,
to=message.from_id,
reply_to_message_id=message.id,
text=f"Received: {message.text}",
)
client.on_message(handle)
asyncio.run(client.connect())
Incoming Messages
The handler receives an AgentMessage:
async def handle(message, agent):
print(message.id)
print(message.conversation_id)
print(message.from_id)
print(message.text)
print(message.attachments)
print(message.widget_response)
Use message.from_id as the to value when replying to the user.
Sending Messages And Replies
Send a normal message:
await agent.send_message(
conversation_id=message.conversation_id,
to=message.from_id,
text="I can help with that.",
)
Reply to a specific user message:
await agent.send_message(
conversation_id=message.conversation_id,
to=message.from_id,
reply_to_message_id=message.id,
text="Replying to your last message.",
)
Running Your Own Agent Logic
async def handle(message, agent):
result = await run_my_agent(message.text)
await agent.send_message(
conversation_id=message.conversation_id,
to=message.from_id,
reply_to_message_id=message.id,
text=result,
)
Widgets
Widgets are sent as encrypted conversation messages. Each method returns the
widget id. User answers arrive later as message.widget_response.
Confirm
await agent.send_confirm_widget(
conversation_id=message.conversation_id,
to=message.from_id,
widget_id="confirm-delete",
title="Delete file?",
body="This cannot be undone.",
danger=True,
labels={"yes": "Delete", "no": "Cancel"},
)
Handle the answer:
if message.widget_response and message.widget_response.ref == "confirm-delete":
if message.widget_response.cancelled:
return
if message.widget_response.value is True:
await agent.send_message(
conversation_id=message.conversation_id,
to=message.from_id,
text="Confirmed.",
)
Choice
await agent.send_choice_widget(
conversation_id=message.conversation_id,
to=message.from_id,
widget_id="choose-format",
title="Choose a format",
options=[
{"id": "pdf", "label": "PDF"},
{"id": "csv", "label": "CSV"},
],
multi=False,
)
Permission
await agent.send_permission_widget(
conversation_id=message.conversation_id,
to=message.from_id,
widget_id="permission-files",
title="Allow file access?",
body="The agent needs access to selected files.",
scopes=["once", "session"],
)
Form
await agent.send_form_widget(
conversation_id=message.conversation_id,
to=message.from_id,
widget_id="profile-form",
title="Complete profile",
submitLabel="Save",
fields=[
{"name": "email", "label": "Email", "type": "email", "required": True},
{"name": "notes", "label": "Notes", "type": "textarea"},
],
)
Progress
progress_id = await agent.send_progress_widget(
conversation_id=message.conversation_id,
to=message.from_id,
widget_id="import-progress",
title="Importing files",
value=10,
max=100,
cancellable=True,
)
Update it:
await agent.send_widget_update(
conversation_id=message.conversation_id,
to=message.from_id,
ref=progress_id,
spec={"value": 65, "body": "Almost done"},
)
File Picker
await agent.send_file_picker_widget(
conversation_id=message.conversation_id,
to=message.from_id,
widget_id="pick-files",
title="Choose files",
multiple=True,
accept=[".pdf", "image/*"],
max_files=5,
)
Date And Time
await agent.send_datetime_widget(
conversation_id=message.conversation_id,
to=message.from_id,
widget_id="schedule",
title="Pick a meeting time",
mode="datetime",
min="2026-05-21T09:00:00",
)
Files And Media
send_file and send_media encrypt bytes locally with AES-GCM, upload only
ciphertext to /agent/blobs, then send the attachment key and IV inside the
E2EE message payload.
await agent.send_file(
conversation_id=message.conversation_id,
to=message.from_id,
reply_to_message_id=message.id,
text="Here is the report.",
name="report.txt",
mime="text/plain",
data=b"private report",
)
Media adds optional dimensions or duration:
await agent.send_media(
conversation_id=message.conversation_id,
to=message.from_id,
text="Preview attached.",
name="chart.png",
mime="image/png",
data=png_bytes,
width=1200,
height=800,
)
Encryption
When e2ee=True, the SDK encrypts and decrypts messages locally before they
leave your machine. On connect, the client publishes the agent pre-key bundle,
establishes encrypted sessions for conversations, and keeps message contents
opaque to the relay.
Use e2ee=False only for local debugging or non-encrypted transports.
MCP
This package is the Python SDK for building agents. The MCP server is distributed separately:
npx -y @pacerelle/mcp-server
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 Distributions
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 pacerelle-0.1.0a1.tar.gz.
File metadata
- Download URL: pacerelle-0.1.0a1.tar.gz
- Upload date:
- Size: 52.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d83c15c91624fbd3133ed57250463785177a3ccf0654ab1a6cb23de61e08b661
|
|
| MD5 |
f982338ba82d6c805b595c77dcfb1364
|
|
| BLAKE2b-256 |
e8c705459b135f1ea85de7626a005bad0e47dc87012a523eefc5e325611fed8c
|
File details
Details for the file pacerelle-0.1.0a1-cp312-cp312-win_amd64.whl.
File metadata
- Download URL: pacerelle-0.1.0a1-cp312-cp312-win_amd64.whl
- Upload date:
- Size: 781.1 kB
- Tags: CPython 3.12, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
06bba4a2ced65d31f547b8b3efd05b97631c66ce653e1aa3a851d6d8497b3ceb
|
|
| MD5 |
367237dee0077a68cf03a3a2ec5b17eb
|
|
| BLAKE2b-256 |
11ea1a725e847f48f6a56cc2334fc0fcd69f430f844ff606300e3d2358a6ee5a
|
File details
Details for the file pacerelle-0.1.0a1-cp312-cp312-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: pacerelle-0.1.0a1-cp312-cp312-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 928.5 kB
- Tags: CPython 3.12, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4bbe1ea2a0709c3c9fde25142f4e365940d1cb314e64f974b4d80e50fed28367
|
|
| MD5 |
a5e99f02358603366d763433c3dd0b5a
|
|
| BLAKE2b-256 |
22ceca5b26a5277ea88aa93ba651ef39e9a804fd197fd899a238057af50dbac6
|
File details
Details for the file pacerelle-0.1.0a1-cp312-cp312-manylinux_2_34_aarch64.whl.
File metadata
- Download URL: pacerelle-0.1.0a1-cp312-cp312-manylinux_2_34_aarch64.whl
- Upload date:
- Size: 738.7 kB
- Tags: CPython 3.12, manylinux: glibc 2.34+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cfa93bcd31ef9574b98a92219a142a9a762c2df8d2c639e09e2f89c3e33e80b1
|
|
| MD5 |
a5d6efb7094f43abfd4209a442e52d78
|
|
| BLAKE2b-256 |
b976f12ebf23073301e39c9256fca303ef5111f16e077f497399aa4ee9e83031
|
File details
Details for the file pacerelle-0.1.0a1-cp312-cp312-macosx_14_0_arm64.whl.
File metadata
- Download URL: pacerelle-0.1.0a1-cp312-cp312-macosx_14_0_arm64.whl
- Upload date:
- Size: 625.3 kB
- Tags: CPython 3.12, macOS 14.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b1d5ceb04933362ea1257b6b08f29e39d1c3ac7fc9057080767ed29bd2d59c06
|
|
| MD5 |
7b733cce9a1a04434e3ff2f9bede354e
|
|
| BLAKE2b-256 |
cb9c1909b0aa3dd0d142fec132fe92b03ae1ea506a86a5850ea6c5d4c4ddfa59
|