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.
Create a macro
Section titled “Create a macro”Scaffold one, then edit the MACRO.yml file:
physiclaw macros init notify-user-whatsappDirectory~/.physiclaw/macros/
- README.md
Directorynotify-user-whatsapp/
- MACRO.yml
MACRO.yml
Section titled “MACRO.yml”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.
Rehearse
Section titled “Rehearse”Start the MCP server:
physiclaw mcpThen lint every MACRO.yml and replay this one on the live rig:
physiclaw macros checkphysiclaw macros run notify-user-whatsapp -i message=hiBest practices
Section titled “Best practices”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.