Serving data

Interactive actions

Let a widget run a bounded command on the Mac when tapped — and why it's debug-only.

Most widgets are read-only. Interactive widgets (decision D12) can also fire a named, pre-registered command on the Mac when the user taps — e.g. a soundbar widget that adjusts volume, or media controls.

The two halves

1. Register the action (backend). register_action binds an actionId to a shell command scoped to one widget:

// register_action
{
  "widgetId": "wgt_abc123",
  "actionId": "volset",
  "command": "yamaha-ctl volset",
  "description": "Set soundbar volume",
  "argKeys": ["vol"]
}

2. Fire it (frontend). In the widget, call window.PERCH.trigger on tap:

button.addEventListener("click", () => window.PERCH.trigger("volset", { vol: 40 }));
window.PERCH.trigger("mutetoggle");            // no args

A widget can only fire actions registered against its own id.

How arguments are passed (safely)

The invocation args are handed to the command as a JSON string in the $PERCH_ARGS environment variable — never interpolated into the command line. So there’s no shell-injection surface: the command is fixed at registration; only the JSON payload varies.

# In your command, parse $PERCH_ARGS — e.g. with jq:
VOL=$(echo "$PERCH_ARGS" | jq -r '.vol')

argKeys documents/validates which keys the action expects (["vol"] above).

trigger vs pulse

CallUseWorks in release?
trigger(actionId, args?)Run a registered command on the MacNo — action runner is debug-only
pulse(detail?)Side-effect-free echo (bird beat + optional notification)Yes

Debug-only by design

The action runner and register_action are compiled out of release builds. Perch v1 ships read-only: a downloaded, notarized Perch app will not execute widget-triggered commands. trigger simply does nothing there. Use actions when running a debug build locally; use pulse for feedback that must work everywhere.

Neither call is a network request — both post over a native message-handler bridge, so the widget’s connect-src 'none' CSP is never relaxed.