Skip to content

Macros

Tokens are expensive. A macro batches many gestures into a single model call, so the agent invokes a sequence you authored and rehearsed instead of driving the phone step by step. Macros save tokens and time.

Scaffold one, then edit the MACRO.yml file:

bash
physiclaw macros init notify-user-whatsapp
  • Directory~/.physiclaw/macros/
    • README.md
    • Directorynotify-user-whatsapp/
      • MACRO.yml
yaml
name: notify-user-whatsapp
# The agent picks a macro by this line alone, so make clear when to use it and what it does.
description: Use when messaging your user on WhatsApp. Opens the chat and stages the text, stopping before Send
# false means the agent can't see or call it.
enabled: true
# The args needed for this macro.
inputs:
message:
description: The message text to send
example: "Order placed, $4.77"
# Run top to bottom, one action per step.
steps:
- name: start-home
tool: home_screen
- name: open-whatsapp
tool: tap
with:
# [left, top, right, bottom] as 0–1 screen fractions.
bbox: [0.31, 0.893, 0.491, 0.974]
- name: await-whatsapp
tool: wait
with:
seconds: 2
# WhatsApp reopens where it was left, so accept either title.
expect:
{or: ["Chats", "your-user-name"], within: [0.02, 0.05, 0.95, 0.18]}
hint: "WhatsApp did not open — log in, then send manually"
- name: open-chat
tool: tap
with:
bbox: [0.03, 0.32, 0.60, 0.42]
# Skip if we are already in the chat.
skip_when:
{text: "your-user-name", within: [0.20, 0.05, 0.60, 0.11]}
# Make sure we tap the right list item.
guard:
require: {text: "your-user-name", within: [0.03, 0.30, 0.95, 0.44]}
- name: stage-text
tool: send_to_clipboard
with:
text: "{message}"
- name: focus-input
tool: tap
with:
bbox: [0.2, 0.928, 0.6, 0.962]
# Skip if the keyboard is up. Its space bar has no label, so use "123".
skip_when:
{text: "123", within: [0.05, 0.86, 0.30, 0.93]}
- name: paste-menu
tool: long_press
with:
# The input box sits higher once the keyboard is up.
bbox: [0.2, 0.59, 0.6, 0.62]
- name: paste
tool: tap
with:
bbox: [0.10, 0.545, 0.21, 0.566]
guard:
require: {text: "Paste", within: [0.03, 0.52, 0.40, 0.59]}
# No send step: the agent checks the text and decides whether to send.

Available tools: tap, double_tap, long_press, swipe, home_screen, go_back, force_quit, send_to_clipboard, peek, and wait.

The full reference lives at ~/.physiclaw/macros/README.md.

Start the MCP server:

bash
physiclaw mcp

Then lint every MACRO.yml and replay this one on the live rig:

bash
physiclaw macros check
physiclaw macros run notify-user-whatsapp -i message=hi

Keep macros short and single-purpose. Anything that needs a decision mid-way, like confirmations, payments, or choosing among results, belongs to the agent, not a macro.

Let an agent draft it. Connect claude or codex to your MCP server, then ask it to write the macro.

Rehearse before enabling. Hard-coded bboxes are trustworthy only because you tested them on this rig, this phone, this layout.

Watch the stats. physiclaw macros stats shows per-macro counters. A rising consecutive_aborts streak means the app layout changed under the macro; re-rehearse and update the bboxes.