โ† Back to skills
extension
Category: OtherNo API key required

Openclaw Interaction Bridge

Bridge OpenClaw agent interactions to any external program! The Snarling demo, for example, shows what the agent is doing and lets you approve or reject acti...

personAuthor: snarflakeshubclawhub

OpenClaw Interaction Bridge ๐ŸŸฅ

Agent state on a screen. Approvals on a button. Notifications that learn. No keyboard required.

A plugin that bridges OpenClaw agent activity to any external program! Snarling for example โ€” a Raspberry Pi + DisplayHAT Mini companion that shows what the agent is doing and lets you approve or reject actions with physical A/B buttons and lets agents send notifications with a feedback loop for attunement!

What It Does

State Display

The plugin hooks into OpenClaw events and POSTs state updates to Snarling's display server:

| Agent Activity | Snarling Shows | Trigger | |---|---|---| | Using tools | processing | before_tool_call | | Generating response | communicating | before_agent_reply | | 30s idle | sleeping | Auto-timeout |

Duplicates are suppressed โ€” only state changes are sent. After 30 seconds of no activity, the display automatically goes to sleep.

Physical Approvals โ€” request_user_approval

The plugin registers a request_user_approval tool that routes yes/no decisions to Snarling's physical A/B buttons. Use this tool whenever you need a human decision before proceeding with an action.

Parameters

| Parameter | Type | Required | Description | |---|---|---|---| | action | string | Yes | Short verb phrase, max 24 chars (e.g., delete_file, send_email, publish_skill). Shown on the display header line. | | message | string | Yes | Brief explanation, max 60 chars ideal, 80 chars hard limit. Shown as 2 lines of ~29 chars each on the physical display. Keep it concise โ€” long text gets truncated. (e.g., Delete /tmp/old-logs? Cannot undo.) |

When to Use

  • Before destructive actions: deleting files, dropping databases, overwriting configs
  • Before external actions: sending emails, posting to social, making API calls that change state
  • Before irreversible operations: publishing packages, deploying to production, transferring funds
  • When uncertain: if you're not sure the user would want you to proceed, ask first

When NOT to Use

  • Reading files, checking status, browsing โ€” these are safe internal actions
  • When the answer is obvious and the user explicitly asked you to do it
  • In group chats or shared channels (the approval goes to a single physical device)

How It Works

  1. You call request_user_approval({ action, message })
  2. Plugin creates a TaskFlow and sets it to waiting
  3. Snarling displays the request on screen with an A/B button prompt
  4. Human presses A (approve) or B (reject)
  5. Snarling forwards the decision to the plugin's /approval-callback route
  6. Plugin resumes the TaskFlow and returns the result

The tool blocks until a response comes back. Only one approval at a time โ€” if another is in progress, the call returns an error message instead of blocking.

Return Values

  • โœ… APPROVED โ€” proceed with the action
  • โŒ REJECTED โ€” do not proceed; respect the user's decision
  • โฐ Timed out โ€” no response within 30 minutes; treat as rejected
  • โš ๏ธ Approval request blocked โ€” another approval is already waiting; finish that one first

Example

request_user_approval({
  action: "delete_file",
  message: "Delete old-config.yaml? 90d old, cannot undo."
})

Bad example (too long, gets truncated on display):

request_user_approval({
  action: "delete_important_configuration_file",  // too long for header
  message: "Delete /home/pi/old-config.yaml? This file has not been modified in 90 days and contains important settings."  // way too long
})

Notifications โ€” send_notification

The plugin registers a send_notification tool that sends informational alerts to the Snarling display. Unlike approvals, notifications don't require a decision โ€” they're for things the agent wants you to know about.

Parameters

| Parameter | Type | Required | Description | |---|---|---|---| | message | string | Yes | The notification text, max 60 chars ideal. Shown across 2-3 rotating banners on the display. | | priority | string | No | high, normal (default), or low. Controls LED color, status boxes, and timeout behavior. | | duration | number | No | Display duration in seconds. Default 0 = use priority-based timeout (high/normal: no timeout; low: 300s auto-dismiss). |

Priority Behavior

| Priority | LED Color | Status Boxes | Timeout | Behavior | |---|---|---|---|---| | high | Warm orange | 5/5 filled | None | Stays until you interact | | normal | Yellow | 3/5 filled | None | Stays until you interact | | low | Soft yellow | 1/5 filled | 300s | Auto-dismisses, sends timed_out feedback |

How It Works

  1. Agent calls send_notification({ message, priority })
  2. Plugin POSTs to Snarling's /approval/alert endpoint with type: "notification"
  3. Snarling shows a subtle visual alert โ€” the creature's face changes, LED pulses, status boxes fill
  4. No text is shown until you press A โ€” the notification stays as a subtle presence
  5. Press A to reveal the notification text, B to dismiss without reading
  6. Snarling sends feedback back to the agent: revealed, dismissed, or timed_out with time_to_reveal_sec

Notification Feedback Loop

Every notification gets a feedback callback:

{
  "notification_id": "notify-1234567890-abc",
  "revealed": true,
  "time_to_reveal_sec": 42.5,
  "dismissed": false,
  "timed_out": false,
  "present": true
}

time_to_reveal_sec measures total time from when the notification was sent to when you interacted โ€” including any queue time behind other notifications. This enables notification attunement: the agent learns what kinds of messages you respond to and when.

Feedback is sent once per notification โ€” on reveal (A press), dismiss (B press), or timeout. Post-reveal dismiss does not send a second callback.

Setup

Prerequisites

  • Raspberry Pi with DisplayHAT Mini
  • Snarling running (display server on port 5000)
  • OpenClaw gateway >= 2026.3.24-beta.2

Install

# Clone to your OpenClaw extensions directory
git clone https://github.com/snarflakes/openclaw-interaction-bridge.git \
  ~/.openclaw/extensions/openclaw-interaction-bridge

# Install dependencies
cd ~/.openclaw/extensions/openclaw-interaction-bridge
npm install

# Restart OpenClaw
openclaw gateway restart

Custom Targets

To point at something other than the default Snarling ports (e.g., a Tauri app, mobile web view), edit the constants at the top of index.ts:

const SNARLING_URL = "http://localhost:5000/state";              // โ†’ your state endpoint
const CALLBACK_BASE_URL = "http://localhost:18789";              // โ†’ your callback base URL

For the approval secret (used to authenticate callback requests), set the OPENCLAW_APPROVAL_SECRET environment variable. If not set, a random secret is generated on each startup. When using a custom target, ensure the secret is included in the request body for callbacks.

No config file needed yet โ€” when there are multiple adapters, a config-driven system will make sense. For now, editing the source is simpler and more honest.

Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     HTTP POST      โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   button press    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  OpenClaw    โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚  Snarling     โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ โ”‚  OpenClaw    โ”‚
โ”‚  (plugin)    โ”‚   /state (5000)   โ”‚  Display      โ”‚  webhook + WS    โ”‚  Gateway     โ”‚
โ”‚              โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚  + Buttons    โ”‚  wake           โ”‚              โ”‚
โ”‚              โ”‚   /approval/alert  โ”‚               โ”‚                  โ”‚              โ”‚
โ”‚              โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚               โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ โ”‚              โ”‚
โ”‚              โ”‚   /approval/alert  โ”‚               โ”‚  /approval-cb    โ”‚              โ”‚
โ”‚              โ”‚   (type: notify)   โ”‚               โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ โ”‚              โ”‚
โ”‚              โ”‚                    โ”‚               โ”‚  /notification-cbโ”‚              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  • State updates: Plugin โ†’ Snarling /state (agent activity)
  • Approvals: Plugin โ†’ Snarling /approval/alert โ†’ Human presses A/B โ†’ Snarling โ†’ Gateway /approval-callback
  • Notifications: Plugin โ†’ Snarling /approval/alert (type: notify) โ†’ Human interacts โ†’ Snarling โ†’ Gateway /notification-callback
  • Wake: Snarling sends WebSocket RPC wake to bypass gateway requests-in-flight check

Troubleshooting

  • Display not updating: Check that Snarling's state server is running on port 5000 (curl -s http://localhost:5000/health)
  • Approvals not working: Verify Snarling is running and the callback route is accessible on port 18789
  • Notifications not showing: Check that the plugin can reach Snarling on port 5000
  • Notification feedback not received: Verify the gateway callback route on port 18789 is accessible; check gateway logs for /notification-callback hits
  • Stuck approval lock: Wait 30 minutes for the stale timeout, or restart the gateway
  • Plugin not loading: Check openclaw gateway restart logs for errors; verify npm install completed; clear jiti cache with rm -f /tmp/jiti/openclaw-interaction-bridge-*.cjs

Install from ClawHub

openclaw plugins install clawhub:@snarflakes/openclaw-interaction-bridge