Files
LLeMbas-CLI/harness/phone.md
T
HomerandClaude Opus 5.5 6da9c7fcd0
ci / check (push) Waiting to run
Harness spec 3.6.0: phone_action, done on the person's phone and confirmed there
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>
2026-11-10 16:32:15 +00:00

6.1 KiB
Raw Blame History

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.json phone.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 unavailable text, 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:

  1. action not one of the actions: texts.unknown_action ({{actions}} the list, joined with , ).
  2. 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 one texts.missing: a field by its name, a group as its names joined with or, the entries joined with and (add_stop needs stop and destination.).
  3. The fields present, in phone.check order (only those the action reads): one that is not what it should be is texts.bad with {{field}} its name and {{what}} from phone.what:
    • time: HH:MM, hours 00–23, minutes 00–59.
    • days: a list, each one of mon … sun.
    • seconds: an integer (never a boolean) from 1 to 86400.
    • start, end: YYYY-MM-DD or YYYY-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 numeric lat and lon together (each in its range), or a non-empty query, or a non-empty name. stops: a list of such places.
    • mode, near, command, panel: one of the schema's values.
    • url: begins http:// or https:// (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.

  • navigate starts a route to destination through stops, in order; mode is how the person travels (drive when not said). replace_route replaces 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, to stop, then to destination. The model gives destination as the person told it when the route began: the tool's description tells it to keep it.
  • search_nearby looks for query around the person (near: me) or along the running route (near: route).
  • stop_navigation ends the route where the map app allows it; one that does not answers failed with why.

5. The other actions

  • alarm and timer are the phone's clock app; days repeats an alarm.
  • calendar_event opens the calendar's new-event screen filled in; the person saves it.
  • sms_draft and email_draft are drafts: the messaging or mail app opens with them, and the person sends. dial opens the dialer with the number; the person places the call.
  • open_app names an app as the person does; open_url opens an address in the browser.
  • media controls what is playing; torch switches the torch.
  • settings_panel opens the phone's quick panel or page for a setting; the person changes it.
  • automation_intent runs an automation the person made in an automation app (Tasker when app is not said), by its name, with values as its inputs.