Mains (Hands): acting on the screen
Mains produces synthetic input: pointer, keyboard, scrolling, windows. Every action goes through the same chain: point resolution, target probe, guard, ceiling gate, audit log, then execution. An action above the ceiling is refused.
Levels
| Tool | Level | Internal name | Observed target required |
|---|---|---|---|
main_navigate | L1 | NONDESTRUCTIVE | no |
main_hover | L1 | NONDESTRUCTIVE | no |
main_activate | L1 | NONDESTRUCTIVE | no |
main_window_minimize | L1 | NONDESTRUCTIVE | no |
main_window_hide | L1 | NONDESTRUCTIVE | no |
main_window_show | L1 | NONDESTRUCTIVE | no |
main_click | L2 | INPUT | yes |
main_type | L2 | INPUT | no |
main_drag | L2 | INPUT | yes |
main_key | L2 | INPUT | no |
main_press | L3 | VALIDATION | yes |
main_mouse_down | L4 | AUTONOMOUS | yes |
main_mouse_up | L4 | AUTONOMOUS | yes |
main_key_down | L4 | AUTONOMOUS | no |
main_key_up | L4 | AUTONOMOUS | no |
The level is nominal: the target can raise it depending on the reversibility of the action, but never lower it. "Observed target required" means that the action commits on a screen element that must be checked before acting.
Response shape
All action tools return a JSON object of one of these three shapes.
| Shape | Meaning |
|---|---|
{"status": "refused", "reason": "..."} | The action is refused (ceiling, guard, human confirmation not obtained) |
{"status": "done", "result": ..., "focus": ...} | The action was executed; focus is present only if a bring-to-front took place |
{"status": "error", "reason": "..."} | The organ failed to execute the action |
Preparation errors become a structured MCP error {"error": "<code>", "message": "..."} and never crash the server:
| Code | Meaning |
|---|---|
invalid_arguments | Invalid argument, for example space="image" without display |
index_out_of_range | The display index does not exist |
capture_failed | Enumerating the displays failed |
motor_unavailable | Mains is not available on this host |
Without Accessibility, silent failures
Without the Accessibility permission, main_type, main_key, main_hover and main_navigate return status: "done" with no effect at all, and main_click, main_press and main_drag wait 30 seconds for a confirmation dialog. Call daimon_doctor before concluding that a tool is broken.
Common parameters
Intent and reversibility
Every action tool requires intent: a sentence declaring what you want to do, recorded in the audit log. The tools that commit also carry reversible: declare honestly whether the action can be undone.
Positioning
The positional tools (main_click, main_press, main_hover, main_navigate, main_drag, main_mouse_down, main_mouse_up) share this block:
| Parameter | Type | Default | Role |
|---|---|---|---|
space | string | "global" | "global": points of the global desktop, the unit returned by vue_find. "image": pixels of a vue_snapshot, resolved by Daimon |
display | integer | none | Display index; required when space="image" |
max_width | integer | 720 | With space="image": the same cap as the snapshot. Ignored in global |
region | object {x, y, width, height} | none | With space="image": the same region as the snapshot, in points local to the display. Ignored in global |
Target window
main_click, main_press and main_drag also carry this block. Empty strings and 0 mean "not specified".
| Parameter | Type | Default | Role |
|---|---|---|---|
window_bundle | string | "" | Bundle identifier of the target application |
window_title | string | "" | Title of the target window |
window_pid | integer | 0 | Target process identifier |
ensure_focus | boolean | true | First activates a target window that is not in front |
What the tool description says
The MCP description of main_click reads "window={bundle|title|pid}"; the actual parameters are the three flat fields window_bundle, window_title and window_pid above.
Modifiers
On macOS: cmd, shift, opt, ctrl. On Windows: ctrl, shift, alt, win; cmd and fn are refused there.
main_click
Clicks on an element or a coordinate. Level L2. Refused above the ceiling.
| Parameter | Type | Default | Required | Role |
|---|---|---|---|---|
x, y | integer | none | yes | Point to click |
intent | string | none | yes | Declared intent |
reversible | boolean | true | no | Whether the action can be undone |
button | string | "left" | no | left, right or middle |
count | integer | 1 | no | 1 or 2 (double-click) |
modifiers | list of strings | [] | no | Modifiers held during the click |
role | string | "" | no | Role of the element (from Touché (Touch)) |
label | string | "" | no | Label of the element (from Touché) |
Plus the Positioning and Target window blocks.
Example call
{
"x": 1210, "y": 84, "intent": "Ouvrir le menu Fichier",
"role": "AXMenuBarItem", "label": "Fichier", "reversible": true
}Pitfalls: provide role and label (read with touche_probe) so that Daimon can check the reversibility of the target.
main_type
Types text into the field that has focus. Level L2.
| Parameter | Type | Default | Required | Role |
|---|---|---|---|---|
text | string | none | yes | Text to type |
intent | string | none | yes | Declared intent |
reversible | boolean | true | no | Whether the action can be undone |
role | string | "" | no | Role of the targeted field |
label | string | "" | no | Label of the targeted field |
Example call: { "text": "bonjour", "intent": "Remplir le champ nom" }
Pitfalls
- The typed text is never written to the audit log.
main_typedoes not choose the field: click on it first.- For a key or a shortcut, use
main_key, notmain_type.
main_key
Sends a discrete key or a shortcut (Return, Tab, Escape, arrows, function keys, or for example cmd+shift+r). Level L2.
| Parameter | Type | Default | Required | Role |
|---|---|---|---|---|
key | string | none | yes | Key or combination |
intent | string | none | yes | Declared intent |
modifiers | list of strings | [] | no | Modifiers |
count | integer | 1 | no | Number of repetitions |
reversible | boolean | true | no | Whether the action can be undone |
Example call
{ "key": "r", "modifiers": ["cmd", "shift"], "intent": "Recharger la page sans cache" }Pitfalls: a single character is typed with the key that the active keyboard layout uses for it. Dangerous combinations require confirmation.
main_press
Activates a committing button at (x, y) through the accessibility API (AXPress). Level L3. Targets that are not back-navigation require human confirmation.
| Parameter | Type | Default | Required | Role |
|---|---|---|---|---|
x, y | integer | none | yes | Point of the button |
intent | string | none | yes | Declared intent |
reversible | boolean | false | no | Whether the action can be undone |
role | string | "" | no | Role of the element |
label | string | "" | no | Label of the element |
Plus the Positioning and Target window blocks.
Example call
{ "x": 900, "y": 640, "intent": "Valider l'envoi du formulaire", "role": "AXButton", "label": "Envoyer" }Pitfalls: unlike the other tools, reversible defaults to false.
main_drag
Drags from (from_x, from_y) to (to_x, to_y). Level L2. The drop destination is classified for its reversibility: dropping onto the Trash, for example, triggers the gate.
| Parameter | Type | Default | Required | Role |
|---|---|---|---|---|
from_x, from_y | integer | none | yes | Start point |
to_x, to_y | integer | none | yes | End point |
intent | string | none | yes | Declared intent |
button | string | "left" | no | Mouse button |
reversible | boolean | true | no | Whether the action can be undone |
Plus the Positioning and Target window blocks; both points go through resolution.
Example call
{ "from_x": 300, "from_y": 400, "to_x": 700, "to_y": 400, "intent": "Déplacer la vignette" }main_navigate
Scrolls by a scroll_y value. Level L1. Reversibility is forced to true.
| Parameter | Type | Default | Required | Role |
|---|---|---|---|---|
intent | string | none | yes | Declared intent |
scroll_y | integer | 0 | no | Amount; positive = upward |
x, y | integer | none | no | Point where the scroll lands |
Plus the Positioning block (accepted for x/y).
Example call: { "intent": "Descendre dans la liste", "scroll_y": -300, "x": 700, "y": 500 }
Pitfalls
- The amount depends on the platform: pixels on macOS; on Windows, 120 corresponds to one wheel notch.
- Give a point
(x, y)so that the scroll lands on the intended view; without a point, it applies wherever the pointer is.
main_hover
Moves the pointer to (x, y) without clicking (to reveal a tooltip or a menu). Level L1. Reversibility is forced to true.
| Parameter | Type | Default | Required | Role |
|---|---|---|---|---|
x, y | integer | none | yes | Targeted point |
intent | string | none | yes | Declared intent |
Plus the Positioning block.
main_activate
Brings an application or a window to the foreground. Level L1.
| Parameter | Type | Default | Required | Role |
|---|---|---|---|---|
intent | string | none | yes | Declared intent |
bundle | string | "" | no | Bundle identifier |
title | string | "" | no | Window title |
pid | integer | 0 | no | Process identifier |
Example call: { "intent": "Passer sur le Finder", "bundle": "com.apple.finder" }
main_window_minimize
Minimizes the foreground window of the target application, through accessibility (unaffected by a remapped shortcut, unlike Cmd+M). Level L1. Reversible: main_window_show restores it. Same parameters as main_activate.
main_window_hide
Hides the target application (unaffected by a remapped shortcut, unlike Cmd+H). Level L1. Reversible: main_window_show restores it. Same parameters as main_activate.
main_window_show
Unhides, unminimizes and raises the target application: the undo of main_window_minimize and main_window_hide. Level L1. Same parameters as main_activate.
main_mouse_down
Low-level primitive: presses and holds the left mouse button at (x, y). Level L4 only.
| Parameter | Type | Default | Required | Role |
|---|---|---|---|---|
x, y | integer | none | yes | Point |
intent | string | none | yes | Declared intent |
Plus the Positioning block.
Pitfalls: the button is released automatically after 10 seconds if main_mouse_up does not follow, even with no other call.
main_mouse_up
Releases the held left button, at (x, y). Level L4. Same parameters as main_mouse_down.
main_key_down
Low-level primitive: presses and holds a key. Level L4 only.
| Parameter | Type | Default | Required | Role |
|---|---|---|---|---|
key | string | none | yes | Key |
intent | string | none | yes | Declared intent |
modifiers | list of strings | [] | no | Modifiers |
Pitfalls: the key is released automatically after 10 seconds if main_key_up does not follow, even with no other call.
main_key_up
Releases a held key. Level L4.
| Parameter | Type | Default | Required | Role |
|---|---|---|---|---|
key | string | none | yes | Key |
intent | string | none | yes | Declared intent |