harness/phone.md, tools/phone_action.json, loop.json phone, conformance/phone.json. The LLeMbas server's tool alone (scope llembas, sessions chat), offered once a message came from the LLeMbas app with the capability phone_actions (new requirement phone). Actions: alarm, timer, calendar_event, sms_draft, email_draft, dial, navigate, add_stop, search_nearby, stop_navigation, open_app, open_url, media, torch, settings_panel, automation_intent. Each reads its own fields; required fields and value checks give the call's refusal in the spec's words. The person confirms on the phone every time; the result is done, declined or failed with what the phone said, or no answer in time. add_stop carries the route's destination: no map app adds to a running route, so the phone plans again via the stop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
6.1 KiB
Phone actions
Spec 3.6.0. phone_action (tools/phone_action.json) lets a chat's model do something on the
person's phone — set an alarm, start a route, draft a message — when the person is writing from the
LLeMbas app on that phone. The model proposes; the app shows the person a card and does nothing
until they confirm it there; the app carries it out with the phone's own apps and answers what
happened, which is the call's result. The texts and numbers are loop.json phone.
It is the server's tool alone (scope: llembas, sessions: chat). The CLI never offers it: a
terminal has no phone behind it.
1. Who offers it
- The capability. The app declares
phone_actions(loop.jsonphone.capability) with each message it sends. A message sent from anywhere else — the web, Desktop, another app — declares nothing. requires: phone. The tool is offered in a chat once a message has been sent to it with the capability, and stays offered for the rest of the chat (the tool list is the session's,context.md§10): a chat started on the phone and continued on the web keeps the tool, and a web chat continued on the phone gains it from that message on (the list changes once, so the prompt is made again once).- Unavailable. A call answers the tool's
unavailabletext, word for word, when the message being answered was not sent with the capability (there is no phone to confirm on), and in a chat nobody attends (a schedule's, a subagent's). Nothing reaches any phone then. - Confirm: always. Every call is put to the person, in every mode; nothing remembers an answer.
The card is the phone's own: the server never asks a second time on another screen. Its risk is
interact: no mode refuses it, Plan mode included, because nothing on disk changes and the person decides on the phone.
2. A call
action is one of phone.actions; summary is the line the phone shows. Each action reads only
its phone.fields; anything else in the call is dropped before the phone sees it. The call is
checked before anything is sent, in this order, and the first problem is the call's result:
actionnot one of the actions:texts.unknown_action({{actions}}the list, joined with,).- The action's
phone.required, each entry in turn: a field is present when it is not null, not an empty string (after trimming) and not an empty list or object; a list inside the list is present when any one of its fields is. Every entry that is missing, in order, goes in onetexts.missing: a field by its name, a group as its names joined withor, the entries joined withand(add_stop needs stop and destination.). - The fields present, in
phone.checkorder (only those the action reads): one that is not what it should be istexts.badwith{{field}}its name and{{what}}fromphone.what:time:HH:MM, hours 00–23, minutes 00–59.days: a list, each one ofmon…sun.seconds: an integer (never a boolean) from 1 to 86400.start,end:YYYY-MM-DDorYYYY-MM-DDTHH:MM(not checked as a calendar date).to,cc: a list of strings, each non-empty after trimming.number: at least three digits, and nothing but digits, spaces and+ ( ) - . / # *.destination,stop: an object with numericlatandlontogether (each in its range), or a non-emptyquery, or a non-emptyname.stops: a list of such places.mode,near,command,panel: one of the schema's values.url: beginshttp://orhttps://(any case) and has something after it.on: a boolean.values: an object of strings.
A call that passes is the action the phone receives: action, summary (trimmed; the action's
name when empty) and the action's fields that are present, as the model gave them, strings trimmed.
3. The answer
The server waits up to phone.wait_seconds for the phone's answer: status (done, declined
or failed) and an optional message, at most phone.message_max_chars characters (cut there).
The call's result is the status's text — texts.done, texts.declined, texts.failed — and,
when there is a message, a blank line and texts.says with it. A status the phone does not know is
failed. No answer in time is texts.no_answer, with no message; the card goes away.
What the person pressed is theirs: declined means they said no, and the model is told not to try again unless asked. Failed is the phone's: an app missing, a permission refused, a map app that cannot do what was asked.
4. Navigation
Map apps differ, and the phone says when one cannot: the model is not told which app the person uses.
navigatestarts a route todestinationthroughstops, in order;modeis how the person travels (drivewhen not said).replace_routereplaces a route already running without the phone asking first.add_stop: no map app adds a stop to a running route, so the phone plans again — from where the person is, tostop, then todestination. The model givesdestinationas the person told it when the route began: the tool's description tells it to keep it.search_nearbylooks forqueryaround the person (near: me) or along the running route (near: route).stop_navigationends the route where the map app allows it; one that does not answersfailedwith why.
5. The other actions
alarmandtimerare the phone's clock app;daysrepeats an alarm.calendar_eventopens the calendar's new-event screen filled in; the person saves it.sms_draftandemail_draftare drafts: the messaging or mail app opens with them, and the person sends.dialopens the dialer with the number; the person places the call.open_appnames an app as the person does;open_urlopens an address in the browser.mediacontrols what is playing;torchswitches the torch.settings_panelopens the phone's quick panel or page for a setting; the person changes it.automation_intentruns an automation the person made in an automation app (Tasker whenappis not said), by its name, withvaluesas its inputs.