mobridge-mcp 0.9.2 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,99 @@
1
+ ---
2
+ name: mobridge-debugging
3
+ description: Use when a MoBridge call fails, times out, is ambiguous, flaky or stuck, or returns an error.code
4
+ version: 1.0.0
5
+ ---
6
+
7
+ # MoBridge debugging
8
+
9
+ Turn an `error.code` or a strange result into the one next step. Read the error body first: it already carries
10
+ `cause`, `recoverable`, `agentAction`, `userAction` and `recovery[]` for known codes. Follow them in order.
11
+
12
+ ## When to use
13
+
14
+ - A tool or command returns `status: FAILED`, `TIMEOUT`, `RESULT_UNKNOWN`, or an `error`.
15
+ - An action reports `DISPATCHED` but the screen did not change, or the same action keeps repeating (`stuck`).
16
+ - A flow worked before and is now flaky, slow or blocked.
17
+
18
+ ## Workflow
19
+
20
+ 1. Read `error.code`, `error.message`, `error.details`, `recovery[0]`, and whether `recoverable` is true.
21
+ 2. Find the family below and open the matching reference for the full table.
22
+ 3. Apply exactly one fix, then retry once. Never retry a mutation after `RESULT_UNKNOWN` (see below).
23
+ 4. Still failing: collect evidence with `mobridge health --preflight`, `mobridge doctor` and `mobridge trace <traceId>`.
24
+ 5. Report the code, the `traceId`, `details.diagnostics` and what you already tried. Do not loop.
25
+
26
+ ```bash
27
+ mobridge health --preflight
28
+ mobridge doctor
29
+ mobridge doctor --fix
30
+ mobridge trace <traceId>
31
+ mobridge diag LOGCAT --package com.example.app
32
+ ```
33
+
34
+ `health --preflight` prints a verdict (`ready`, `degraded`, `blocked`) and ordered `nextSteps`: a `Run:` line is one
35
+ command you may run, a `Guidance:` line is something only the person can do. `doctor --fix` previews the repair and
36
+ `doctor --fix --apply` runs it (it only reconnects and re-checks).
37
+
38
+ ## Families
39
+
40
+ | Family | Typical codes | Open |
41
+ |---|---|---|
42
+ | Connect, adb, device selection | `ADB_NOT_FOUND`, `DEVICE_OFFLINE`, `DEVICE_UNAUTHORIZED`, `MULTIPLE_DEVICES`, `DEVICE_BINDING_MISMATCH` | `references/connection-errors.md` |
43
+ | Companion app and Accessibility | `COMPANION_MISSING`, `COMPANION_NOT_READY`, `ACCESSIBILITY_ENABLE_BLOCKED`, `EXTERNAL_INSTRUMENTATION_ACTIVE` | `references/connection-errors.md`, `mobridge-companion-setup` |
44
+ | Finding the target | `NODE_NOT_FOUND`, `AMBIGUOUS_MATCH`, `STALE_NODE_REF`, `VISION_REQUIRED` | `references/action-errors.md` |
45
+ | Verification and results | `DISPATCHED`, `VERIFY_TIMEOUT`, `RESULT_UNKNOWN`, `IDEMPOTENCY_MISMATCH` | `references/action-errors.md` |
46
+ | Policy and permissions | `POLICY_BLOCKED`, `ACTION_REJECTED`, `PROTECTED_CONTROL_PLANE` | `references/action-errors.md`, `mobridge-app-control` |
47
+ | Concurrency and workflows | `BUSY`, `DEVICE_BUSY`, `LOCK_TIMEOUT`, `WORKFLOW_NOT_FOUND`, `STALE_CAPTURE` | `references/action-errors.md` |
48
+
49
+ ## The five failures you will meet most
50
+
51
+ 1. `RESULT_UNKNOWN`: the action may or may not have happened (the link dropped after dispatch). Do not resend.
52
+ `mobridge operation status <operationId>`, then `mobridge screen observe`, then decide.
53
+ 2. `AMBIGUOUS_MATCH`: several nodes fit. Narrow with `--role`, `--nth`, `--within`, or `--resource-id`. Do not use the
54
+ first candidate.
55
+ 3. `NODE_NOT_FOUND`: wrong text, wrong match mode or the node is off screen. Default match is `NORMALIZED_EXACT`;
56
+ a longer on-screen string needs `CONTAINS`. Scroll with `mobridge find --text ... --scroll`. For a control with no
57
+ text try `--label`. If the screen has no accessibility tree you get `VISION_REQUIRED`, not `NODE_NOT_FOUND`.
58
+ 4. `DISPATCHED` but nothing changed: the node has no CLICK action, an overlay covers it, or the tree did not change
59
+ (WebView, canvas). Read `observation.treeEvidence` and `error.details.targetDiagnosis`. A non-clickable node
60
+ needs `--allow-gesture` with a verifying policy, or look at the pixels (`mobridge-surfaces`).
61
+ 5. `BUSY`: another state-changing call holds the device. Reads share the device; a read that arrives during a write
62
+ is refused. Wait for the write, then retry the read. Health and status calls stay available while busy.
63
+
64
+ ## Stuck and flaky
65
+
66
+ - `stuck {repeatCount, hint}` after three identical actions with an unchanged tree: stop repeating. Observe,
67
+ change the query or the surface (capture and `act at`), or ask the user.
68
+ - `targetDiagnosis.state`: `moved` and `covered` are proven; `gone` means a complete capture held no match;
69
+ `ambiguous` means several fit; `unknown` always names a reason such as `TARGET_OFFSCREEN` or `TREE_TRUNCATED`.
70
+ - Wireless adb drops kill the transport. A read retries by itself; a mutation reports `RESULT_UNKNOWN`. Prefer USB
71
+ (`mobridge-devices`).
72
+ - Another tool holding UiAutomation (Appium, uiautomator, a test runner) gives `EXTERNAL_INSTRUMENTATION_ACTIVE`.
73
+ Stop it, then `mobridge connect`.
74
+ - After upgrading the package run `mobridge daemon restart`, then `mobridge connect`.
75
+
76
+ ## Evidence ladder
77
+
78
+ | Need | Command |
79
+ |---|---|
80
+ | What did the last call do | `mobridge trace <traceId>` |
81
+ | Is the phone ready | `mobridge health --preflight` |
82
+ | Environment problems | `mobridge doctor` |
83
+ | App crash, ANR, memory | `mobridge diag CRASH --package com.example.app`, `mobridge diag PERF --package com.example.app` |
84
+ | App log | `mobridge diag LOGCAT --package com.example.app` |
85
+ | Show me the screen | `mobridge screen capture` |
86
+ | What changed between two reads | `mobridge diff --from <snapshotId> --to <snapshotId>` |
87
+
88
+ ## Do not
89
+
90
+ - Do not repeat a mutation after `RESULT_UNKNOWN` or a dropped link.
91
+ - Do not switch to raw `adb shell input` to "get around" a failure: it skips verification and the daemon will not
92
+ know what happened.
93
+ - Do not edit the plan to hide a failing step. Fix the query or the surface.
94
+ - Do not guess a package, a coordinate or a device. Ask, or read it from the tool.
95
+
96
+ ## Verification
97
+
98
+ - The fix is proven only when the same call returns `VERIFIED` (or `health --preflight` reports ready) without a retry.
99
+ - Record the `traceId` of the failing call; `mobridge trace <traceId>` is the evidence to quote.
@@ -0,0 +1,59 @@
1
+ # Action, verification, policy and workflow errors
2
+
3
+ These codes appear while acting, after the phone is connected. Connection and setup codes are in
4
+ `connection-errors.md`.
5
+
6
+ ## Targeting
7
+
8
+ | Code | Meaning | Do |
9
+ |---|---|---|
10
+ | `NODE_NOT_FOUND` | No node matched the query. | Check text and match mode, scroll (`find --scroll`), try `--label`, observe. |
11
+ | `AMBIGUOUS_MATCH` | Several nodes match, or several scroll containers of similar size. | Narrow with `--role`, `--nth`, `--within`, `--resource-id`. For scrolling pass an explicit container query. |
12
+ | `STALE_NODE_REF` | The screen changed since the NodeRef was read. | Resolve the original query again. Never revive an old ref. |
13
+ | `WEAK_REFERENCE_UNRESOLVABLE` | The ref has no usable locator any more. | Query again from scratch. |
14
+ | `VISION_REQUIRED` | The foreground has no usable accessibility tree (game, canvas, video). | `mobridge screen capture`, pick a point, `mobridge screen act at --capture <id> --x X --y Y`. |
15
+ | `NEEDS_VISION` | Semantics are not enough to decide. | Same as above. |
16
+ | `STALE_CAPTURE` | The screen no longer matches the capture you tapped on. | Capture again. For video or ads use `--stale-policy dynamic`. |
17
+ | `ACTION_UNSUPPORTED` | The node does not support that action (for example `SCROLL_FORWARD` at the end of a list, or CLICK on text). | At a list end scroll the other way or stop. For CLICK use the clickable parent, `--allow-gesture`, or `act at`. |
18
+
19
+ ## Verification and results
20
+
21
+ | Code or status | Meaning | Do |
22
+ |---|---|---|
23
+ | `DISPATCHED` | Sent, not proven. | Add `--verify`, or `wait` for the expected node. |
24
+ | `VERIFY_TIMEOUT` | The predicate was not met in time. | Observe; the action may still have worked. Use a better policy or a longer wait. |
25
+ | `NO_EFFECT` | The action ran and nothing changed. | Different target or surface. |
26
+ | `RESULT_UNKNOWN` | Dispatched, effect unknown (link dropped). | Never resend. `mobridge operation status <operationId>`, then observe. |
27
+ | `EXPIRED_UNKNOWN` | An old unknown operation timed out of the journal. | Treat as unknown. Observe. Never turn it into a new command. |
28
+ | `IDEMPOTENCY_MISMATCH` | The same `operationId` was reused with a different payload. | Use a new `operationId` for a new action. |
29
+ | `OPERATION_ID_REQUIRED` | A mutation arrived without an identity. | Pass `--operation-id` (MCP: `operationId`). |
30
+
31
+ ## Policy and safety
32
+
33
+ | Code | Meaning | Do |
34
+ |---|---|---|
35
+ | `POLICY_BLOCKED` | A policy gate refused it (install path, permission allowlist, protected package). | Read `recovery`: it names the switch to turn on in the companion app. See `mobridge-app-control`. |
36
+ | `ACTION_REJECTED` | Bad input, or input aimed at the MoBridge Runtime app itself. | Fix the field the message names. Input to the companion's own screen is refused on purpose: ask the person. |
37
+ | `PROTECTED_CONTROL_PLANE` | The target is MoBridge's own companion. | Use the companion's own UI. Not overridable. |
38
+ | `CRITICAL_SYSTEM_TARGET` | A core system package (settings, systemui, permission controller). | Only with an explicit `--allow-critical-system`, and only if you truly mean it. |
39
+ | `USER_CONFIRMATION_REQUIRED` | A person must confirm. | Ask them. |
40
+ | `AMBIGUOUS_DEVICE` | A destructive call named no device. | Pass `-d ANDROID:<serial>`. |
41
+ | `CAPTURE_BLOCKED_SECURE_WINDOW` / `SECURE_WINDOW` | The window is flagged secure. | Capture is refused; semantics may still work. |
42
+
43
+ ## Concurrency, workflows, daemon
44
+
45
+ | Code | Meaning | Do |
46
+ |---|---|---|
47
+ | `BUSY` | A state-changing call is running; this read would see mixed state. | Wait, retry the read. |
48
+ | `DEVICE_BUSY` | The bounded mutation queue is full. | Wait for the active workflow. |
49
+ | `LOCK_TIMEOUT` | The device lock was not acquired in time. Nothing was dispatched. | Retry after the active operation finishes. |
50
+ | `WORKFLOW_NOT_FOUND` | No checkpoint for that workflow id. | Check the id; it expires after 24 hours. |
51
+ | `WORKFLOW_IDENTITY_MISMATCH` / `WORKFLOW_PLAN_MISMATCH` | Resume with a different device or plan. | Resume only with the same workflow id, device, plan and token. |
52
+ | `RESUME_TOKEN_REQUIRED` | Resume needs the token from the paused result. | Pass `--resume-token`. |
53
+ | `DAEMON_BUILD_MISMATCH` | The running daemon is an older build. | `mobridge daemon restart`. |
54
+ | `INVALID_JSON` | A `--query`, plan line or condition is not valid JSON. | Quote it; wrap conditions in `nodeExists`. |
55
+ | `METHOD_NOT_FOUND` | Unknown command or action. | Read `recovery`; run `mobridge --help`. |
56
+
57
+ ## Reading a refused input
58
+
59
+ Many `ACTION_REJECTED` bodies list the allowed values and a valid example. Fix that one field and retry once.
@@ -0,0 +1,31 @@
1
+ # Connection and setup errors
2
+
3
+ Every code below comes with `cause`, `recoverable`, `agentAction` and, when a person must act, `userAction` in the error body. Do exactly the matching step; do not try things at random.
4
+
5
+ | `error.code` | Cause | Self-heals or plain retry | What to do |
6
+ |---|---|---|---|
7
+ | `ADB_NOT_FOUND` | `adb` is not installed or not on PATH. | no | Tell the user to install Android Platform Tools, then run `mobridge connect`. **User:** Install Android Platform Tools (https://developer.android.com/tools/releases/platform-tools) and add its folder to PATH. |
8
+ | `ADB_SERVER_UNRESPONSIVE` | The adb server does not answer. | yes | Retry `mobridge connect`; if it repeats ask the user to approve `mobridge doctor --restart-adb`. |
9
+ | `DEVICE_NOT_FOUND` | The device that was named is not attached. | no | Run `mobridge devices`, pick an attached serial, never substitute another phone. **User:** Connect the phone by USB (or `adb connect`) and unlock it. |
10
+ | `DEVICE_OFFLINE` | adb sees the device but it is offline or just reconnecting. | yes | Wait a few seconds and retry `mobridge connect`. **User:** If it persists: replug the cable, unlock the phone, toggle USB debugging. |
11
+ | `DEVICE_UNAUTHORIZED` | The phone has not accepted this computer's USB debugging key. | no | Ask the user to unlock the phone and accept the dialog, then retry `mobridge connect`. **User:** Unlock the phone and tap Allow on the "Allow USB debugging?" dialog (tick Always allow). |
12
+ | `MULTIPLE_DEVICES` | More than one usable device is attached and none was chosen. | no | Pick one from `details.candidates` and pass it as deviceId (`-d ANDROID:<serial>`), or save it once with `mobridge device use <serial>`. |
13
+ | `AMBIGUOUS_DEVICE` | Several devices are connected in this daemon and the call named none. | no | Pass `deviceId` (from `mobridge devices`) on every call; never guess one. |
14
+ | `DEVICE_BINDING_MISMATCH` | The runtime socket answered for a different phone than the one named. | yes | Run `mobridge connect -d ANDROID:<serial>` again; if it repeats run `mobridge doctor`. Nothing was driven. |
15
+ | `COMPANION_MISSING` | The companion app is not installed and no APK was available. | no | Run `npx -y mobridge-mcp@latest install`, or set MSM_COMPANION_APK to the APK of this package. |
16
+ | `COMPANION_VERSION_MISMATCH` | The installed companion is not the build this host expects. | yes | Run `mobridge connect`; it updates the companion once. |
17
+ | `COMPANION_INSTALL_BLOCKED` | The phone refused the USB install (OEM setting or confirmation prompt). | no | Show the user `recovery`, then retry `mobridge connect`. **User:** Unlock the phone and tap Install/Allow; Xiaomi/Redmi/POCO: Developer options > Install via USB and USB debugging (Security settings); Play Protect: Install anyway. |
18
+ | `COMPANION_INSTALL_FAILED` | The install failed for a device reason (storage, Android version). | no | Show the user the message, then retry `mobridge connect`. **User:** Free storage, or use a device on Android 10+. |
19
+ | `COMPANION_NOT_READY` | The companion did not answer the handshake ("socket hang up"). | yes | Read `diagnostics` and `recovery[0]`, apply it, then run `mobridge connect` again. **User:** Only if `recovery[0]` asks: open the MoBridge Runtime app once / exclude it from battery optimisation. |
20
+ | `COMPANION_UNAVAILABLE` | The companion process is not running. | yes | Run `mobridge connect`; it restarts the companion. |
21
+ | `ACCESSIBILITY_DISABLED` | The Accessibility service is off. | yes | Run `mobridge connect`; it enables the service over adb and reads it back. |
22
+ | `ACCESSIBILITY_ENABLE_BLOCKED` | The phone does not let adb enable the Accessibility service. | no | Show the user `userAction`, then run `mobridge connect --wait-user 120` to resume the moment it is on. **User:** Settings > Accessibility > MoBridge Runtime > On. Android 13+: first Settings > Apps > MoBridge Runtime > ⋮ > Allow restricted settings. Xiaomi: Developer options > USB debugging (Security settings). |
23
+ | `WAITING_FOR_USER_ACCESSIBILITY` | Waiting for the person to turn Accessibility on; the wait window ended. | no | Ask the user to finish the step, then run `mobridge connect` again (it resumes; nothing is reinstalled). **User:** Settings > Accessibility > MoBridge Runtime > On. |
24
+ | `ACCESSIBILITY_PREEMPTED` | The service is enabled but not bound; another owner took the session. | yes | Wait a few seconds and run `mobridge connect`. |
25
+ | `EXTERNAL_INSTRUMENTATION_ACTIVE` | Another tool holds UiAutomation (uiautomator, a test runner, another agent). | no | Fail fast: ask the user to stop the other tool, then `mobridge connect`. **User:** Stop the other automation tool on this phone. |
26
+ | `TRANSPORT_DEGRADED` | The link to the phone dropped. | yes | Retry the read; for a mutation check `mobridge operation status <operationId>` first. Prefer USB over wireless adb. |
27
+ | `WS_CONNECTION_LOST` | The WebSocket to the companion closed. | yes | Reads retry by themselves; a mutation reports RESULT_UNKNOWN, so look its operation up, never resend it. |
28
+ | `RESULT_UNKNOWN` | A mutation was dispatched but its effect could not be confirmed. | no | Never repeat it. Run `mobridge operation status <operationId>` and observe the screen. |
29
+ | `AMBIGUOUS_MATCH` | More than one node matches the query. | no | Narrow the query using `candidates`; never click the first. |
30
+ | `NEEDS_VISION` | Semantics are not enough to decide. | no | Take `mobile.screen.capture`, look at the image and act with `at`. |
31
+ | `UNSUPPORTED_PLATFORM` | iOS was requested. | no | Use an Android device. |
@@ -0,0 +1,94 @@
1
+ ---
2
+ name: mobridge-devices
3
+ description: Use when choosing a phone, working with several devices, USB versus wireless adb, or a lost connection
4
+ version: 1.0.0
5
+ ---
6
+
7
+ # MoBridge devices and transport
8
+
9
+ Rule: the answer comes from the phone you named, or the call fails. No call ever falls back to another phone.
10
+
11
+ ## When to use
12
+
13
+ - More than one phone is attached, or you are unsure which one a command will hit.
14
+ - You want to move from USB to wireless adb, or the link dropped.
15
+ - `MULTIPLE_DEVICES`, `AMBIGUOUS_DEVICE`, `DEVICE_NOT_FOUND`, `DEVICE_OFFLINE`, `DEVICE_UNAUTHORIZED`,
16
+ `DEVICE_BINDING_MISMATCH`, `TRANSPORT_DEGRADED` or `WS_CONNECTION_LOST`.
17
+
18
+ ## Workflow
19
+
20
+ 1. `mobridge devices` to list what is attached and usable.
21
+ 2. Name the phone on every call, or save it once with `mobridge device use <serial>`.
22
+ 3. Prefer USB for long plans and mutations; use wireless only for short reads.
23
+ 4. On a dropped link follow "Recover a lost connection" below, then apply `mobridge-companion-setup` if the companion is the problem.
24
+
25
+ ## Choose a phone
26
+
27
+ ```bash
28
+ mobridge devices
29
+ mobridge connect -d ANDROID:<serial>
30
+ mobridge device use <serial>
31
+ mobridge device current
32
+ mobridge device clear
33
+ ```
34
+
35
+ | Attached | You pass | Result |
36
+ |---|---|---|
37
+ | one usable | nothing | that phone |
38
+ | two or more usable | nothing | `MULTIPLE_DEVICES` with `details.candidates` |
39
+ | any | a named, usable phone | that phone |
40
+ | any | a named, absent phone | `DEVICE_NOT_FOUND` |
41
+ | any | a named, offline or unauthorized phone | `DEVICE_OFFLINE` / `DEVICE_UNAUTHORIZED` |
42
+
43
+ - With several phones pass `-d ANDROID:<serial>` on every call (MCP: `deviceId`), or save one with
44
+ `mobridge device use <serial>` once. Never pick one yourself from the candidates without asking when it matters.
45
+ - Destructive calls (app control, `app ...`) always need an explicit device.
46
+ - Each phone has its own binding proof: a nonce is written to that serial and must come back from the companion
47
+ socket. A stale forward to another phone fails as `DEVICE_BINDING_MISMATCH`; run `mobridge connect -d ANDROID:<serial>` again.
48
+ - The registry serialises state-changing calls per device and runs in practice as one session. Do not assume two
49
+ phones can be driven in parallel from one daemon without naming each.
50
+
51
+ ## USB or wireless
52
+
53
+ | | USB | Wireless adb (same Wi-Fi) |
54
+ |---|---|---|
55
+ | Setup | cable, USB debugging on, accept the key | `adb pair` / `adb connect` on the computer first |
56
+ | Stability | best | a link drop kills the transport and the companion's session |
57
+ | Use for | long plans, mutations, anything you must trust | quick reads, demos |
58
+
59
+ Prefer USB for long flows and mutations. On wireless, check `mobridge health --preflight` before a plan and expect
60
+ `TRANSPORT_DEGRADED` or `WS_CONNECTION_LOST` if the Wi-Fi blips: a read retries by itself; a mutation reports
61
+ `RESULT_UNKNOWN`, so look up its `operationId` instead of resending.
62
+
63
+ Different network and no cable: only an overlay VPN (WireGuard or Tailscale) with `MSM_ADB_REMOTE=host:5555`, or a
64
+ relay, gives a route. Without one there is no route; ask the person to connect a cable.
65
+
66
+ ## Recover a lost connection
67
+
68
+ 1. `mobridge health --preflight` for the verdict and ordered `nextSteps`.
69
+ 2. `mobridge connect -d ANDROID:<serial>` once. It reinstalls nothing that is already right.
70
+ 3. Still down: `mobridge doctor`, then `mobridge doctor --fix`, and with the person's yes `mobridge doctor --fix --apply`.
71
+ 4. After upgrading the package or when a stale daemon answers: `mobridge daemon restart`, then connect.
72
+ 5. Check the daemon itself with `mobridge daemon status`.
73
+
74
+ ```bash
75
+ mobridge health --preflight
76
+ mobridge connect -d ANDROID:<serial>
77
+ mobridge doctor
78
+ mobridge daemon status
79
+ mobridge daemon restart
80
+ ```
81
+
82
+ ## Rules for several phones
83
+
84
+ - Name the phone on every call. If you lose track, run `mobridge devices` and `mobridge device current`.
85
+ - Do not carry a NodeRef, a capture id or a workflow id from one phone to another.
86
+ - When two phones share an operation id, reuse is refused; give each action its own `operationId`.
87
+ - A foreground-only fact (screen contents) is per phone. Observe again after switching.
88
+
89
+ References: `references/wireless-adb.md`.
90
+
91
+ ## Verification
92
+
93
+ - `mobridge device current` shows the saved default; `mobridge health --preflight` shows the phone you will hit is ready.
94
+ - The `device` field of every response must match the phone you meant.
@@ -0,0 +1,35 @@
1
+ # Wireless adb
2
+
3
+ MoBridge uses adb only to provision (install the companion, enable Accessibility, forward a port). Once connected,
4
+ the runtime talks to the companion over a WebSocket on the forwarded port. Wireless adb therefore only has to
5
+ survive provisioning; the session then depends on that forward staying alive.
6
+
7
+ ## Android 11 and newer (pairing code)
8
+
9
+ On the phone: Developer options, Wireless debugging on, Pair device with pairing code. On the computer:
10
+
11
+ ```bash
12
+ adb pair <ip>:<pairing-port>
13
+ adb connect <ip>:<connect-port>
14
+ adb devices
15
+ ```
16
+
17
+ Then run `mobridge devices` and `mobridge connect -d ANDROID:<serial>` where the serial is what `adb devices` shows
18
+ (usually `<ip>:<port>`).
19
+
20
+ ## Older phones
21
+
22
+ Connect once by USB, run `adb tcpip 5555`, unplug, `adb connect <ip>:5555`.
23
+
24
+ ## Staying connected
25
+
26
+ - Keep the screen on and the phone on the same network. Sleep and Wi-Fi roaming drop the link.
27
+ - A drop appears as `TRANSPORT_DEGRADED` or `WS_CONNECTION_LOST`. Reads recover; for a mutation use
28
+ `mobridge operation status <operationId>`.
29
+ - If the address changes, adb needs a new `adb connect`, and MoBridge needs a new `mobridge connect`.
30
+ - A phone that is connected both by USB and wireless shows up twice: name the serial you want.
31
+
32
+ ## Not on the same network
33
+
34
+ There is no route without a cable. Overlay networks (WireGuard, Tailscale) work with `MSM_ADB_REMOTE=host:5555`
35
+ set in the environment of the daemon. Ask the person before setting it.
@@ -0,0 +1,98 @@
1
+ ---
2
+ name: mobridge-efficiency
3
+ description: Use when optimizing MoBridge for fewer tokens, faster runs, parallel reads, burst capture or long plans
4
+ version: 1.0.0
5
+ ---
6
+
7
+ # MoBridge efficiency
8
+
9
+ How to get the most out of each call: fewer tokens, fewer round trips, no wasted waits.
10
+
11
+ ## When to use
12
+
13
+ - A flow is slow, verbose or burns context on screenshots.
14
+ - You are about to run dozens of single commands, poll in a loop, or read the whole tree after every tap.
15
+ - You need a short video-like view of a transition.
16
+
17
+ ## Workflow
18
+
19
+ 1. Start from `mobridge-core` and act by query without a preliminary observe.
20
+ 2. Pick the cheapest sensor from the ladder; capture only when meaning is missing (then apply `mobridge-surfaces`).
21
+ 3. Batch two or more steps into one plan (apply `mobridge-recipes`).
22
+ 4. Measure with the `timing` spans before changing anything else.
23
+
24
+ ## The token ladder (cheapest first)
25
+
26
+ | Need | Use | Cost |
27
+ |---|---|---|
28
+ | Act on something you can name | `mobridge screen act click --text "X" --verify auto` (no observe) | the verdict only |
29
+ | Know what is tappable | `mobridge screen observe --actionable` | small JSON |
30
+ | Read the screen | `mobridge screen observe` | semantic JSON, no image |
31
+ | See pixels | `mobridge screen capture` | small image (scale 0.5) |
32
+ | Read small text | `mobridge screen capture --mode detail` or `--roi x,y,w,h` | native resolution of a region |
33
+ | Watch a transition | `mobridge screen burst --duration 2 --interval 400` | frames in daemon memory, fetched one by one |
34
+
35
+ Rules of thumb:
36
+
37
+ - Observe only when the screen is unknown, after navigation, when a match is ambiguous, or when an action failed.
38
+ - Never observe at the end of a plan unless you need the state: use `--return-state` on `run` when you do.
39
+ - Prefer `observe --actionable` to a full read. In MCP `app-only` is on by default and drops status-bar noise.
40
+ - A capture is the last resort for understanding; try the semantic path first. Games, canvas and ads need pixels.
41
+ - Use `--format webp` for smaller files; the `-o` extension also sets the format.
42
+
43
+ ```bash
44
+ mobridge screen observe --actionable
45
+ mobridge screen capture --mode detail
46
+ mobridge screen capture --roi 0,0,1080,400 -o top.png
47
+ mobridge screen burst --duration 2 --interval 400
48
+ mobridge screen burst --frame <burstId>.3 -o frame3.webp
49
+ ```
50
+
51
+ ## Fewer round trips
52
+
53
+ - Two or more steps: one `mobridge run plan.jsonl` or `mobile.run`. The daemon keeps a hot session and passes data
54
+ between steps without sending it through the model.
55
+ - Many commands from a script: `mobridge session --jsonl`. Input lines `{"id":"1","argv":["screen","observe"]}`, output
56
+ lines `{"id":"1","exit":0,"output":{...}}`. One process, no spawn per command.
57
+ - Every CLI call still pays process start-up. Do not issue a hundred single commands when one plan does the job.
58
+ - A click by query already waits up to 1500 ms (4000 ms on system UI). Add `--wait-ms <0-10000>` instead of a manual
59
+ sleep. `--wait-ms 0` turns it off.
60
+ - Wait on a condition, never on a timer: `mobridge wait '<condition>'` or `mobridge watch --timeout-ms 3000`.
61
+
62
+ ## Parallel work
63
+
64
+ - Reads share the device: observe, capture, inspect and state may run at the same time.
65
+ - State-changing calls run one after another per device. A read that arrives during a write is refused with `BUSY`;
66
+ retry it after the write. Do not parallelise mutations.
67
+ - Several phones: each call names its phone, and the calls for different phones are independent.
68
+
69
+ ## Burst instead of video
70
+
71
+ `screen burst --duration S --interval MS` takes ordered screenshots on a wall-clock schedule and keeps them in
72
+ daemon RAM, never on disk.
73
+
74
+ | Limit | Value |
75
+ |---|---|
76
+ | Duration | up to 60 s |
77
+ | Frames | up to 120 |
78
+ | Memory | 48 MiB, oldest frames evicted first |
79
+ | Held for | 120 s, then dropped |
80
+ | Minimum interval | 350 ms (Android throttles screenshots near 333 ms) |
81
+
82
+ The result lists frames with `seq`, `tMs`, `frameId` and `changedFromPrev`, without images. Fetch one with
83
+ `--frame <burstId>.<n>`, or a range `<burstId>.<a>-<b>`. Frames cannot be used with `act at`; capture again to tap.
84
+
85
+ ## Habits that save the most
86
+
87
+ 1. Act with a query directly; skip the preliminary observe.
88
+ 2. Verify with the right policy so you do not need a second read.
89
+ 3. Use `app` in the act result instead of observing to see where a tap landed.
90
+ 4. Cache nothing across navigation; a NodeRef from before a screen change is stale.
91
+ 5. Stop a failing loop at `stuck` instead of retrying.
92
+
93
+ References: `references/measuring.md`.
94
+
95
+ ## Verification
96
+
97
+ - Compare `timing` and output size before and after a change; keep it only if one of them drops and the verdict stays `VERIFIED`.
98
+ - Do not claim a speed-up without a measured run on the target app.
@@ -0,0 +1,29 @@
1
+ # Measuring cost
2
+
3
+ Every response carries `timing`: CLI start-up, IPC, daemon queue, device RPC, resolve, verification and
4
+ serialization spans. Read them before guessing what is slow.
5
+
6
+ | Span | What a high value means |
7
+ |---|---|
8
+ | CLI `moduleReadyMs` / `ensureDaemonMs` | Process start-up. Batch commands (`run`, `session --jsonl`). |
9
+ | `daemonQueueMs` | Another mutation was running. Serialise less, or wait for it. |
10
+ | `deviceRpcMs` | The phone is slow: heavy screen, wireless link, battery saver. |
11
+ | `resolveNodeMs` | The tree is large. Narrow with `--within` or `--resource-id`. |
12
+ | `verificationMs` / `uiStabilityMs` | The screen keeps animating. Use `watch`, or verify on a stable node. |
13
+
14
+ ## Quick experiments
15
+
16
+ ```bash
17
+ mobridge screen observe --actionable --json
18
+ mobridge screen observe --json
19
+ mobridge screen capture --json
20
+ ```
21
+
22
+ Compare the sizes of the three outputs for your screen. The semantic read is much smaller than a full tree dump and
23
+ carries no image; a capture costs image tokens, so use it when pixels are the question.
24
+
25
+ ## Rules
26
+
27
+ - Measure with real calls on the target app. Do not quote benchmark numbers from another phone or app.
28
+ - Change one thing at a time, then compare `timing` and output size.
29
+ - If a flow needs more than about ten commands, turn it into a plan before tuning anything else.
@@ -0,0 +1,139 @@
1
+ ---
2
+ name: mobridge-recipes
3
+ description: Use when chaining MoBridge steps, writing a JSONL plan, mixing CLI with MCP or saving and replaying a flow
4
+ version: 1.0.0
5
+ ---
6
+
7
+ # MoBridge recipes
8
+
9
+ How to combine the CLI and MCP surfaces, and how to turn a manual flow into a plan that can be resumed,
10
+ replayed and handed from one interface to the other.
11
+
12
+ ## When to use
13
+
14
+ - A task needs two or more steps, a login, a form, a settings change or any repeatable flow.
15
+ - You started in MCP and want a file, a batch or diagnostics from the CLI (or the reverse).
16
+ - You want to save a verified flow so it can run again.
17
+
18
+ ## Workflow
19
+
20
+ 1. Apply `mobridge-core` for the single-step loop and `mobridge-devices` to name the phone.
21
+ 2. One step: act directly. Two or more steps: write a JSONL plan and run it once.
22
+ 3. Give the run a stable `workflowId` and step ids so it can be resumed or looked up from CLI or MCP.
23
+ 4. Read `mobridge run --status` on failure; resume only from the reported step, never replay a mutation.
24
+ 5. Save a flow that worked as a scenario; apply `mobridge-debugging` when it fails.
25
+
26
+ ## Choose the surface
27
+
28
+ | Goal | Use |
29
+ |---|---|
30
+ | One known action with visible text | `mobridge screen act click --text "Login" --verify auto` or `mobile.screen.act` |
31
+ | Two or more steps | `mobridge run plan.jsonl` or `mobile.run` |
32
+ | Many CLI commands in a row | `mobridge session --jsonl` (one process, no spawn per command) |
33
+ | Inline image for the model | MCP `mobile.screen.capture` |
34
+ | Files, streams, diagnostics, recordings | CLI |
35
+ | Unknown screen | `mobridge screen observe`, then decide |
36
+
37
+ Chaining shell commands with `&&` is fine, but each call pays process start-up. In `a && b || c` the `||` branch
38
+ runs when a OR b fails: use `if` to branch.
39
+
40
+ ## Plans (JSONL)
41
+
42
+ One step per line, unique `id`, stable across retries. A `wait` condition is always wrapped.
43
+
44
+ ```json
45
+ {"id":"s1","open":"com.example.app"}
46
+ {"id":"s2","tap":{"text":"Skip"}}
47
+ {"id":"s3","wait":{"condition":{"nodeExists":{"text":{"value":"Home","match":"CONTAINS"}}},"timeoutMs":3000}}
48
+ {"id":"s4","type":{"field":"com.example.app:id/email","text":"a@b.c"}}
49
+ {"id":"s5","scroll":{"query":{"text":{"value":"Settings","match":"CONTAINS"}},"direction":"FORWARD"}}
50
+ {"id":"s6","key":"BACK"}
51
+ ```
52
+
53
+ Run it with a workflow id, check it, resume it:
54
+
55
+ ```bash
56
+ mobridge run plan.jsonl --workflow-id wf_login_0001
57
+ mobridge run --status --workflow-id wf_login_0001
58
+ mobridge run plan.jsonl --workflow-id wf_login_0001 --resume-token <token>
59
+ mobridge run plan.jsonl --workflow-id wf_login_0002 --return-state
60
+ ```
61
+
62
+ - The run stops at the first step that is not verified and reports `PAUSED` with a `resumeToken` and `notRun`.
63
+ - A `scroll` step scrolls until the query is found; it is not a single swipe.
64
+ - By default a run does not observe at the end. Add `--return-state` (MCP `returnState: true`) when you need it.
65
+ - A checkpoint lives at most 24 hours and stores only a plan hash and step ids, never the plan or secrets.
66
+ Resume only with the same workflow id, device, plan and token.
67
+
68
+ More step shapes and dataflow: `references/jsonl-steps.md`.
69
+
70
+ ## CLI and MCP on the same task
71
+
72
+ Both go through one daemon, so a flow can start in one and finish in the other.
73
+
74
+ 1. Give every single mutation an `operationId` and every plan a `workflowId`.
75
+ 2. When you switch interface, look the work up instead of repeating it:
76
+ - mutation: `mobridge operation status <operationId>`;
77
+ - plan: `mobridge run --status --workflow-id <id>`, or MCP `mobile.run` with `plan: {"control":"status"}`.
78
+ 3. Reuse of an `operationId` with the same payload returns the receipt with `idempotentReplay: true`.
79
+
80
+ ## Save a flow as a scenario
81
+
82
+ ```bash
83
+ mobridge scenario list
84
+ mobridge scenario save login-flow --intent "log in with the test account" --steps '[{"id":"s1","action":"CLICK","find":{"query":{"text":{"value":"Login","match":"EXACT"}}},"verify":{"policy":"WINDOW_CHANGED"}}]'
85
+ mobridge scenario get login-flow
86
+ mobridge scenario run login-flow
87
+ mobridge scenario delete login-flow
88
+ ```
89
+
90
+ Scenario ids are lowercase letters, digits and hyphens. A saved scenario is a recording, not a guarantee: run it
91
+ and read the verdicts. A scenario fails closed when a target is missing.
92
+
93
+ ## Recipes
94
+
95
+ Login without leaking the password:
96
+
97
+ ```bash
98
+ mobridge open com.example.app
99
+ mobridge type --field com.example.app:id/email "user@example.com" --verify auto
100
+ mobridge type --field com.example.app:id/password --secret --verify auto
101
+ mobridge screen act click --text "Sign in" --verify auto
102
+ ```
103
+
104
+ (`--secret` reads the value from stdin; `--secret-env VAR` reads an environment variable.)
105
+
106
+ Read a list that scrolls:
107
+
108
+ ```bash
109
+ mobridge screen observe --actionable
110
+ mobridge scroll down
111
+ mobridge screen observe --actionable
112
+ mobridge diff --from <beforeSnapshot> --to <afterSnapshot>
113
+ ```
114
+
115
+ Wait for a screen to settle after a tap:
116
+
117
+ ```bash
118
+ mobridge screen act click --text "Continue" --verify WINDOW_CHANGED
119
+ mobridge watch --timeout-ms 3000
120
+ ```
121
+
122
+ Answer a system permission dialog that is on screen:
123
+
124
+ ```bash
125
+ mobridge permission respond --decision ALLOW_WHILE_USING
126
+ ```
127
+
128
+ ## Pitfalls
129
+
130
+ - Do not send a long run as dozens of CLI processes. One plan or one `session --jsonl` does it.
131
+ - Do not reuse a step id inside a plan; the run reports a structured result but the status is ambiguous.
132
+ - Do not branch on a `DISPATCHED` step as if it succeeded. Add a verify or a `wait` step.
133
+ - A plan that mixes an `open` of an app with a different foreground app after launch can stay `DISPATCHED`: the
134
+ app opened another activity or package. Observe and wait on the expected node instead of assuming.
135
+
136
+ ## Verification
137
+
138
+ - A plan is done when `run` reports every step `VERIFIED` (or the `--return-state` read shows the target screen).
139
+ - After a failure, `mobridge run --status --workflow-id <id>` shows the last good step and the resume token.
@@ -0,0 +1,28 @@
1
+ # JSONL step reference
2
+
3
+ Every line is one JSON object with a unique `id` and exactly one verb key.
4
+
5
+ | Verb | Shape | Notes |
6
+ |---|---|---|
7
+ | `open` | `{"id":"s1","open":"com.example.app"}` | Launch or bring to front. Verified by the foreground package. |
8
+ | `tap` | `{"id":"s2","tap":{"text":"Skip"}}` | Same query fields as `find`. Add `"verify":{"policy":"WINDOW_CHANGED"}` when you know it. |
9
+ | `type` | `{"id":"s3","type":{"field":"com.example.app:id/email","text":"a@b.c"}}` | `field` is the resource id of the input, `text` is the value to type. |
10
+ | `wait` | `{"id":"s4","wait":{"condition":{"nodeExists":{...}},"timeoutMs":3000}}` | Wrapped condition only. |
11
+ | `scroll` | `{"id":"s5","scroll":{"query":{...},"direction":"FORWARD"}}` | Scrolls until the query is found. |
12
+ | `key` | `{"id":"s6","key":"BACK"}` | `BACK`, `HOME`, `RECENTS`, `NOTIFICATION_SHADE`. |
13
+ | `find` | `{"id":"s7","find":{"query":{...}}}` | Resolves a node for later steps. |
14
+ | `gesture` | `{"id":"s8","gesture":{"kind":"SWIPE","x":540,"y":1600,"x2":540,"y2":800,"durationMs":300}}` | Coordinates are unverified by nature. |
15
+ | `capture` | `{"id":"s9","capture":{}}` | Takes a screenshot into daemon memory and returns a `captureId`. |
16
+ | `diag` | `{"id":"s10","diag":{"kind":"LOGCAT","packageName":"com.example.app"}}` | Host-side diagnostics. |
17
+
18
+ ## Dataflow
19
+
20
+ A step result can feed a later step. `$name` references are resolved on the host only, never sent to the model.
21
+ Use them for ids and values that appear mid-flow; keep secrets out of plans.
22
+
23
+ ## Rules
24
+
25
+ - Ids are unique and stable. Retrying a plan with the same workflow id reuses them.
26
+ - A step that is only `DISPATCHED` stops the run unless it carries its own verify.
27
+ - Unknown verbs are rejected with `ACTION_REJECTED` and the allowed shapes; fix the line and run again.
28
+ - Keep plans short. Split a long flow at a natural checkpoint (a screen that is easy to wait on).