JSPM

playclaw-sdk

1.1.0
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 3
  • Score
    100M100P100Q30670F
  • License MIT

Connect any AI agent to PlayClaw — the professional audit playground. One bridge. Any model.

Package Exports

  • playclaw-sdk
  • playclaw-sdk/src/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (playclaw-sdk) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

playclaw-sdk

Connect any AI agent to PlayClaw — the professional audit playground.

npm install playclaw-sdk

The 5-line version

const { PlayclawBridge } = require('playclaw-sdk');

const bridge = new PlayclawBridge({ token: 'PC-XXXX-XXXX-XXXX' });

bridge.onMessage(async (message, context) => {
  return await myAgent.reply(message);
});

bridge.connect();

That's it. The SDK handles the connection, sessions, turn limits, error recovery, and auto-reconnect.


What this SDK does

PlayClaw audits AI agents by running structured conversations through your agent. The SDK is the bridge between PlayClaw's platform and your agent code.

Each time someone clicks "Start Audit" in PlayClaw, a session begins. The SDK:

  • Detects the new session and fires onSessionStart
  • Routes each message from PlayClaw to your onMessage handler
  • Sends your agent's reply back to PlayClaw
  • Enforces the turn limit (default: 5)
  • Fires onSessionEnd with the full conversation history
  • Reconnects automatically if the connection drops

Full API reference

new PlayclawBridge(options)

Option Type Default Description
token string required Your PC-XXXX PlayClaw token
auditTurns number 5 Max turns per audit session
autoReconnect boolean true Reconnect if channel drops
logLevel 'debug'|'info'|'warn'|'error'|'silent' 'info' Console log verbosity
logger function(level, message, meta) null Custom log output function
rateLimit RateLimitOptions null Enable built-in rate limiting
supabaseUrl string PlayClaw default Override for self-hosted setups
supabaseKey string PlayClaw default Override for self-hosted setups

Hooks

All hooks return this for chaining.

.onMessage(handler) ← required

bridge.onMessage(async (message, context) => {
  // message: string — what the user sent
  // context.sessionId   : 'sess_abc123'
  // context.turnNumber  : 1, 2, 3, 4, or 5
  // context.totalTurns  : 5
  // context.isLastTurn  : true on turn 5
  // context.history     : [{ role, content, timestamp }, ...]
  return "your reply as a string";
});

.onSessionStart(handler)

bridge.onSessionStart((sessionId) => {
  myAgent.resetMemory(); // new audit = fresh state
});

.onSessionEnd(handler)

bridge.onSessionEnd((sessionId, history) => {
  database.save({ sessionId, history });
});

.onError(handler)

bridge.onError((error, sessionId) => {
  monitoring.report(error); // bridge stays alive
});

.onConnect(handler) / .onDisconnect(handler)

bridge.onConnect(() => console.log("Live"));
bridge.onDisconnect(() => console.log("Reconnecting..."));

Middleware

// Transform messages BEFORE your handler sees them
bridge.use(async (message, context) => {
  return sanitize(message);
});

// Transform replies BEFORE they're sent to PlayClaw
bridge.useReply(async (reply, context) => {
  return translate(reply, "en");
});

Middlewares run in registration order. Throwing inside a middleware cancels the message.

State & Introspection

bridge.isConnected  // boolean
bridge.sessionInfo  // { sessionId, turnCount, auditTurns, isExhausted }
bridge.stats        // { sessionsHandled, messagesHandled, errorsCount, reconnectsCount }

Rate Limiting

const bridge = new PlayclawBridge({
  token: 'PC-...',
  rateLimit: {
    maxPerWindow:  60,      // max 60 messages per minute (global)
    windowMs:      60_000,  // 1-minute window
    maxConcurrent: 1,       // max 1 in-flight call per session
  }
});

Or as middleware for custom logic:

const { PlayclawRateLimiter } = require('playclaw-sdk');
const limiter = new PlayclawRateLimiter({ maxPerWindow: 30, windowMs: 60_000 });
bridge.use(limiter.middleware());

Real-world examples

OpenAI (GPT-4o)

const { PlayclawBridge } = require('playclaw-sdk');
const OpenAI = require('openai');

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
const bridge = new PlayclawBridge({ token: process.env.PC_TOKEN });

let history = [];

bridge.onSessionStart(() => { history = []; });

bridge.onMessage(async (message, context) => {
  history.push({ role: "user", content: message });

  const res = await openai.chat.completions.create({
    model: "gpt-4o",
    messages: [
      { role: "system", content: context.isLastTurn ? "Give a conclusive answer." : "Be helpful." },
      ...history,
    ],
  });

  const reply = res.choices[0].message.content;
  history.push({ role: "assistant", content: reply });
  return reply;
});

bridge.connect();

Anthropic (Claude)

const { PlayclawBridge } = require('playclaw-sdk');
const Anthropic = require('@anthropic-ai/sdk');

const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
const bridge = new PlayclawBridge({ token: process.env.PC_TOKEN });

let history = [];

bridge.onSessionStart(() => { history = []; });

bridge.onMessage(async (message) => {
  history.push({ role: "user", content: message });

  const res = await anthropic.messages.create({
    model: "claude-opus-4-6",
    max_tokens: 1024,
    messages: history,
  });

  const reply = res.content[0].text;
  history.push({ role: "assistant", content: reply });
  return reply;
});

bridge.connect();

Any HTTP agent (n8n, Flowise, local LLM)

const { PlayclawBridge } = require('playclaw-sdk');

const bridge = new PlayclawBridge({ token: process.env.PC_TOKEN });

bridge.onMessage(async (message) => {
  const res = await fetch("https://my-agent.internal/chat", {
    method: "POST",
    headers: { "Content-Type": "application/json", "Authorization": `Bearer ${process.env.AGENT_KEY}` },
    body: JSON.stringify({ message }),
  });
  const data = await res.json();
  return data.reply;
});

bridge.connect();

Multiple PlayClaw accounts (multi-tenant)

const { PlayclawBridge } = require('playclaw-sdk');

const tokens = process.env.PC_TOKENS.split(",");

const bridges = tokens.map((token) => {
  const bridge = new PlayclawBridge({ token });
  bridge.onMessage(async (message) => await myAgent.reply(message));
  return bridge;
});

await Promise.all(bridges.map((b) => b.connect()));
console.log(`${bridges.length} bridges connected.`);

Logging

By default the SDK logs to stdout at info level with timestamps and color.

2026-03-23T14:00:01.123Z INFO  [playclaw:PC-TEST] Bridge connected — listening for audit messages
2026-03-23T14:00:02.456Z INFO  [playclaw:PC-TEST] Audit session started { sessionId: 'sess_abc' }
2026-03-23T14:00:05.789Z INFO  [playclaw:PC-TEST] Audit session ended   { sessionId: 'sess_abc', messages: 10 }

Levels: debug | info | warn | error | silent

// Verbose mode (see every message processed)
new PlayclawBridge({ token: 'PC-...', logLevel: 'debug' });

// No output
new PlayclawBridge({ token: 'PC-...', logLevel: 'silent' });

// Pipe to your own logger (winston, pino, etc.)
new PlayclawBridge({
  token: 'PC-...',
  logger: (level, message, meta) => winston.log(level, message, meta),
});

Running tests

node test/bridge.test.js

Tests run without any real Supabase connection using the built-in MockTransport.


Advanced: build your own transport

If you want to use a different backend (custom WebSocket server, etc.):

const { PlayclawBridge, PlayclawTransport } = require('playclaw-sdk');

class MyCustomTransport extends PlayclawTransport {
  async connect() { /* your connection logic */ }
  async send(event, payload) { /* your send logic */ }
}

const bridge = new PlayclawBridge({ token: 'PC-...' });
bridge._transport = new MyCustomTransport('PC-...');
bridge.connect();

License

MIT — playclaw.info