Pacerelle Docs

SDK integration

Build complete JavaScript and Python agent runtimes with real credentials.

The SDK is the recommended way to build a custom local agent. It handles the repetitive runtime work:

  • connecting your process to Pacerelle
  • using the agent id and token from the app
  • incoming message parsing
  • replies
  • widgets
  • file and media uploads

Start with the integration path if you want the shortest tested path, then come back here for SDK details.

Required environment

PACERELLE_AGENT_ID="agent id copied from the New agent dialog"
PACERELLE_AGENT_TOKEN="token copied from the New agent dialog"

Hosted Pacerelle users only need these two values.

JavaScript SDK

Install

npm i @pacerelle/sdk

Create the agent file

import {
  createNodeAgentGatewayClient,
  createNodeSignalSnapshotStore,
} from "@pacerelle/sdk/node";

const agentId = process.env.PACERELLE_AGENT_ID!;
const signalStore = createNodeSignalSnapshotStore(agentId);

const client = createNodeAgentGatewayClient({
  agentId,
  token: process.env.PACERELLE_AGENT_TOKEN!,
  baseUrl: process.env.PACERELLE_BASE_URL,
  wsUrl: process.env.PACERELLE_WS_URL,
  e2ee: true,
  signalSnapshot: signalStore.signalSnapshot,
  onSignalSnapshot: signalStore.onSignalSnapshot,
  onOpen: () => console.log("connected"),
  onClose: () => console.log("closed"),
  onError: console.error,
});

client.onMessage(async (message, agent) => {
  await agent.sendMessage({
    conversationId: message.conversationId,
    to: message.from,
    replyToMessageId: message.id,
    text: `Received: ${message.text}`,
  });
});

await client.connect();

Run the agent

node --env-file=.env agent.mjs

JavaScript handler contract

The handler receives message and agent.

client.onMessage(async (message, agent) => {
  console.log(message.id);
  console.log(message.conversationId);
  console.log(message.from);
  console.log(message.text);
  console.log(message.attachments);
  console.log(message.widgetResponse);
});

When replying, always use the inbound conversationId and from:

await agent.sendMessage({
  conversationId: message.conversationId,
  to: message.from,
  replyToMessageId: message.id,
  text: "Done.",
});

Connect your own logic

Replace the echo with your model, script, or workflow:

client.onMessage(async (message, agent) => {
  const answer = await runLocalWorkflow(message.text);

  await agent.sendMessage({
    conversationId: message.conversationId,
    to: message.from,
    replyToMessageId: message.id,
    text: answer,
  });
});

Python SDK

Install

pip install --pre pacerelle

Create the agent file

import asyncio
import os

from pacerelle import AgentGatewayClient

client = AgentGatewayClient(
    agent_id=os.environ["PACERELLE_AGENT_ID"],
    token=os.environ["PACERELLE_AGENT_TOKEN"],
    base_url=os.environ.get("PACERELLE_BASE_URL"),
    ws_url=os.environ.get("PACERELLE_WS_URL"),
    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())

Python requirements

  • Python 3.12 for the current alpha wheels.
  • Windows x64, Linux x64, Linux ARM64, or macOS ARM64.

Long-running agents

For long-running encrypted agents, persist Signal state between restarts:

  • JavaScript: use createNodeAgentGatewayClient(...) and createNodeSignalSnapshotStore(agentId) from @pacerelle/sdk/node.
  • Python: the SDK uses a local store by default under the user's home directory unless a different store root is configured.

This makes reconnects smoother and avoids making the user repeat setup work.

An encrypted agent has two identities: PACERELLE_AGENT_ID and the local Signal snapshot. Reusing the same agent id with a new snapshot can break older encrypted conversations. The Node helper stores state at:

~/.pacerelle/agents/<agent-id>.signal.b64

Override the location with PACERELLE_AGENT_SIGNAL_STATE_FILE or PACERELLE_AGENT_SIGNAL_STATE_DIR when you need a managed path.

Error handling checklist

  • Store agent tokens in environment variables or a secret manager.
  • Add onOpen, onClose, and onError callbacks in JavaScript.
  • Keep the process alive; the SDK listens continuously over WebSocket.
  • Do not log decrypted user messages in production.
  • Reconnect after network drops.
  • Rotate the token if authentication fails because the token was replaced.

When to use MCP instead

Use the SDK when you are building your own runtime. Use MCP server when you want an MCP-compatible desktop client to host the local bridge for you.