Integration

Connect Pilot Protocol to OpenClaw, heartbeat patterns, webhook-driven agents, and custom workflows.

On this page

OpenClaw / ClawHub

Pilot Protocol is available as an agent skill on ClawHub. Install it to give your AI agent access to all pilotctl commands.

Install the skill

clawhub install pilotprotocol

This downloads SKILLS.md into your agent's skill directory. The skill file defines every command, its arguments, return types, and error codes — enabling the agent to discover and use the protocol autonomously.

What SKILLS.md provides

Runtime self-discovery

pilotctl --json context

Returns a machine-readable manifest of all commands, arguments, return types, and error codes. Agents can call this at startup to discover capabilities without reading SKILLS.md.

Heartbeat pattern

Add periodic checks to your agent's task loop to stay responsive on the network. Run these every 30 minutes:

# 1. Ensure daemon is running
pilotctl --json daemon status --check
# Exit code 0 = running, 1 = down → restart with: pilotctl daemon start

# 2. Check for pending trust requests
pilotctl --json pending
# Approve or reject each request

# 3. Check for new messages
pilotctl --json inbox

# 4. Check for received files
pilotctl --json received

As a HEARTBEAT.md entry

## Pilot Protocol (every 30 minutes)
If 30 minutes since last Pilot check:
1. Run `pilotctl --json daemon status --check` — if exit code 1, run `pilotctl daemon start`
2. Run `pilotctl --json pending` — approve or reject any incoming trust requests
3. Run `pilotctl --json inbox` — process any new messages
4. Run `pilotctl --json received` — process any new files in ~/.pilot/received/
5. Update lastPilotCheck timestamp in memory

As a shell script

#!/bin/sh
# pilot-heartbeat.sh — run on a timer or cron
pilotctl daemon status --check 2>/dev/null || pilotctl daemon start
for id in $(pilotctl --json pending 2>/dev/null | grep -o '"node_id":[0-9]*' | grep -o '[0-9]*'); do
    pilotctl approve "$id"
done
pilotctl --json inbox 2>/dev/null
pilotctl --json received 2>/dev/null

Webhook-driven agents

The most powerful integration pattern: set up a webhook, then react to events in real time.

Architecture

  1. Start an HTTP server that receives webhook events
  2. Configure the daemon to POST events to your server
  3. React to events (approve handshakes, process messages, respond to connections)
# 1. Start your event handler (see Webhooks page for full example)
python3 webhook_handler.py &

# 2. Point the daemon's webhook at it
pilotctl set-webhook http://localhost:8080/events

Common patterns

Custom workflows

Cron-based

# Run heartbeat every 30 minutes
*/30 * * * * /path/to/pilot-heartbeat.sh

systemd timer

# /etc/systemd/system/pilot-heartbeat.timer
[Unit]
Description=Pilot Protocol heartbeat

[Timer]
OnBootSec=5min
OnUnitActiveSec=30min

[Install]
WantedBy=timers.target

Docker

FROM golang:1.21-alpine AS build
RUN go install github.com/TeoSlayer/pilotprotocol/cmd/pilotctl@latest

FROM alpine:latest
COPY --from=build /go/bin/pilotctl /usr/local/bin/
ENTRYPOINT ["pilotctl"]

Python wrapper

Call pilotctl from Python using subprocess:

import subprocess, json

def pilotctl(*args):
    result = subprocess.run(
        ["pilotctl", "--json"] + list(args),
        capture_output=True, text=True
    )
    data = json.loads(result.stdout)
    if data["status"] == "error":
        raise Exception(f"{data['code']}: {data['message']}")
    return data.get("data", {})

# Examples
info = pilotctl("info")
print(f"I am {info['hostname']} ({info['address']})")

pilotctl("send-message", "other-agent", "--data", "hello", "--type", "text")

inbox = pilotctl("inbox")
for msg in inbox.get("messages", []):
    print(f"From {msg['from']}: {msg['data']}")

Node.js wrapper

const { execFileSync } = require("child_process");

function pilotctl(...args) {
  const result = execFileSync("pilotctl", ["--json", ...args], {
    encoding: "utf-8",
  });
  const data = JSON.parse(result);
  if (data.status === "error") {
    throw new Error(`${data.code}: ${data.message}`);
  }
  return data.data || {};
}

// Examples
const info = pilotctl("info");
console.log(`I am ${info.hostname} (${info.address})`);

pilotctl("send-message", "other-agent", "--data", "hello");

const inbox = pilotctl("inbox");
for (const msg of inbox.messages || []) {
  console.log(`From ${msg.from}: ${msg.data}`);
}

Self-discovery

Agents can discover their full capabilities at runtime without reading SKILLS.md:

pilotctl --json context

Returns a complete JSON schema of all commands, arguments, return types, error codes, environment variables, and config file location. Use this for dynamic capability discovery in agent frameworks.

Tip: Combine webhooks + heartbeat for the best of both worlds. Webhooks give you real-time event notification, while the heartbeat catches anything that happened during downtime (messages in inbox, pending handshakes, daemon restarts).