[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-96437":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":8,"htmlUrl":8,"language":9,"languages":8,"totalLinesOfCode":8,"stars":10,"forks":11,"watchers":12,"openIssues":13,"contributorsCount":14,"subscribersCount":14,"size":14,"stars1d":15,"stars7d":15,"stars30d":15,"stars90d":14,"forks30d":14,"starsTrendScore":16,"compositeScore":17,"rankGlobal":8,"rankLanguage":8,"license":18,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":21,"hasPages":19,"topics":22,"createdAt":8,"pushedAt":8,"updatedAt":23,"readmeContent":24,"aiSummary":8,"trendingCount":14,"starSnapshotCount":14,"syncStatus":13,"lastSyncTime":25,"discoverSource":26},96437,"mobile-jev","droidrun\u002Fmobile-jev","droidrun",null,"JavaScript",264,35,126,2,0,65,195,4.67,"MIT License",false,"main",true,[],"2026-09-21 02:04:32","# Mobile Jev\n\n[![Watch Jev navigate Uber on a live Mobilerun phone](docs\u002Fmedia\u002Fuber-demo.gif)](https:\u002F\u002Fgithub.com\u002Fdroidrun\u002Fmobile-jev\u002Fblob\u002Fmain\u002Fdocs\u002Fmedia\u002Fuber-demo.mp4)\n\n**[▶ Watch the demo](https:\u002F\u002Fgithub.com\u002Fdroidrun\u002Fmobile-jev\u002Fblob\u002Fmain\u002Fdocs\u002Fmedia\u002Fuber-demo.mp4)** — Jev opens Uber, enters a route from San Francisco Airport to the Golden Gate Bridge, and reaches payment selection. The recorded task timer shows about **21 seconds for 9 actions**. A completed booking is not demonstrated.\n\n**One goal. A real Android phone. Jev makes the decisions.**\n\nA standalone mobile agent for [Mobilerun](https:\u002F\u002Fmobilerun.ai), powered by [TypeSafe's Jev](https:\u002F\u002Fdocs.typesafe.ai\u002F) and the [Mobilerun API](https:\u002F\u002Fdocs.mobilerun.ai\u002F). Includes a live React studio, a CLI, execution traces, and request-level latency measurements. No ADB connection is required.\n\n[Mobilerun](https:\u002F\u002Fmobilerun.ai) · [Mobilerun docs](https:\u002F\u002Fdocs.mobilerun.ai) · [TypeSafe](https:\u002F\u002Ftypesafe.ai) · [Jev docs](https:\u002F\u002Fdocs.typesafe.ai) · [Demo guide](docs\u002FDEMO.md)\n\n## Run it\n\nRequirements: **Node.js 24 recommended** (22.16+ supported), **pnpm 10.30.1**, **curl 7.70+**, a ready Mobilerun Android device, and API keys for Mobilerun and TypeSafe. Tested locally on macOS; CI runs offline tests and the build on Linux.\n\n```sh\ngit clone https:\u002F\u002Fgithub.com\u002Fdroidrun\u002Fmobile-jev.git\ncd mobile-jev\ncorepack enable\npnpm install --frozen-lockfile\ncp .env.example .env.local\n```\n\nAdd `MOBILERUN_API_KEY` and `TYPESAFE_API_KEY` to `.env.local`. List your devices, then set `MOBILERUN_DEVICE_ID` to the one you want to control:\n\n```sh\npnpm devices\npnpm doctor\npnpm dev\n```\n\nOpen **http:\u002F\u002F127.0.0.1:3040**. Enter a goal and press **Run task**.\n\n- Get a Mobilerun key from [API keys](https:\u002F\u002Fcloud.mobilerun.ai\u002Fapi-keys).\n- Get a TypeSafe key from the [TypeSafe console](https:\u002F\u002Fconsole.typesafe.ai\u002F).\n- Connect or provision your own Android device through Mobilerun. Device\u002Fservice charges are separate from this project.\n- The default API endpoint is production. Set `MOBILERUN_BASE_URL` to your own environment if needed; the code contains no fixed account or device ID.\n\nAlready export your variables? That works too. Exported variables take precedence over `.env.local`, which takes precedence over `.env`.\n\n## Included demo: enable dark theme\n\nAsk **“Turn on dark theme in Android Settings.”** Jev discovers Settings from the device's installed apps, opens it through the Mobilerun API, selects the relevant controls, and changes the setting. The demo runner reads the screen again and verifies the actual Dark theme switch is on; it does not accept a model DONE response as proof.\n\n```sh\npnpm demo dark-theme --reset\n```\n\n`--reset` first asks Jev to establish and verify an off baseline. Setup, task execution, and verification have separate timings. Every attempt is retained locally, including failures. This is a small reproducible utility demo without accounts, purchases, or travel-app loading. See [what the demo does and its limits](docs\u002FDEMO.md).\n\n## The studio\n\n- A live device stream using the official [`@mobilerun\u002Freact`](https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@mobilerun\u002Freact) component.\n- Goal input, executed-action timeline, model latency, and a task clock that stops on completion, failure, or cancellation.\n- Stop control, reconnect, fullscreen, and recent runs. Clear removes finished runs and resets the timer. One task owns the configured device at a time.\n- The desktop workspace fits in one viewport; activity scrolls inside its panel.\n\nThe account API keys stay on the server. The browser receives device-scoped streaming credentials only. The app binds to localhost, validates request origins, and is intended for a single local operator. Public\u002Fmulti-user hosting requires your own authentication and device authorization. Recent runs are held in memory and cleared on server restart.\n\n## Use the CLI\n\n```sh\n# Preview the next decision, without executing it:\npnpm agent run \"Turn on dark theme in Android Settings.\"\n\n# Execute a goal and retain the real model decisions:\npnpm agent run \"Turn on dark theme in Android Settings.\" \\\n  --execute --steps 20 --trace artifacts\u002Fdark-theme.jsonl\n\n# Inspect a phone or measure the API:\npnpm agent observe\npnpm agent screenshot\npnpm agent profile --out artifacts\u002Fapi-profile.json\n\n# Direct controls for debugging:\npnpm agent tap 300 500\npnpm agent type \"San Francisco\" --clear\npnpm agent back\n```\n\nUse `--device ID` to override the configured device. `pnpm agent --help` lists all options. Traces and screenshots are ignored by git and never overwrite an existing file.\n\n## How Jev drives it\n\n```mermaid\nflowchart LR\n  A[Observe device] --> B[Indexed controls and installed apps]\n  B --> C[One Jev request: operation + speculative targets]\n  C --> D[Validate selected branch and fresh target]\n  D --> E[Execute through Mobilerun]\n  E --> A\n```\n\nJev chooses `OPEN_APP`, `TAP`, `TYPE_TEXT`, scrolling, navigation, `WAIT`, `DONE`, or `BLOCKED`. Operation and compatible-target questions share one request; unused target answers cannot execute. App launch targets come from the installed-app API. When a goal names installed apps explicitly, exact name matching narrows that inventory; otherwise up to 200 apps are offered and the launcher remains available.\n\nThe executor resolves coordinates from observed bounds. It validates probability distributions, rejects stale targets, and never retries a device mutation after an uncertain transport failure. It records actions before the next observation, so a failed read cannot erase an executed action.\n\nText comes from exact spans in the goal. Jev selects a span; code copies it into the field. Supply `--text \"exact field value\"` to override those candidates. This implementation does not generate arbitrary prose or invent missing personal details. A separate text-generation model is not needed.\n\nText replacement uses the API's faster `accepted` completion mode when the focused field can be read back. The agent verifies the complete field value in its next observation before asking Jev to continue; an unverified value stops the run without retyping. Appends, password fields, and fields without a readable target retain server-side `committed` completion. Set `MOBILERUN_TEXT_COMPLETION_MODE=committed` (or CLI `--text-completion committed`) to use that mode for every input.\n\nConfidence is visible and an optional `--confidence` cutoff is available. **Jev's DONE response is not independent proof of success.** Check the resulting device state, especially for numeric values, dates, and multi-part goals. The demo runner provides task-specific verification; see [the demo guide](docs\u002FDEMO.md).\n\n## Speed and reproducibility\n\nThe model transport reuses its HTTPS connection. Device readiness is cached briefly. The loop observes immediately after actions, with bounded polling for transitions, rather than sleeping after every interaction. Jev still chooses every operation; there are no prepared tap sequences in the policy.\n\nRequest timings split DNS, TCP\u002FTLS, response wait, and download from total wall time. Response wait includes network, server, and device work—not just server processing. A 300 ms swipe also includes its requested gesture duration. See [the demo guide](docs\u002FDEMO.md) for measurement boundaries, successes, and failures.\n\nAn identical prompt is not guaranteed to produce an identical trace. App version, locale, current screen, account state, network, and model version affect results. `jev-latest` is convenient; set `TYPESAFE_MODEL` to a supported fixed version when comparing runs, and retain the returned model name in the trace.\n\n## Development\n\n```sh\npnpm check       # tests, lint, typecheck, formatting, production build\npnpm build\npnpm start      # production studio on localhost:3040\n```\n\nCI requires no API keys and does not control a phone. Live `run --execute` and demo commands make real model\u002Fdevice requests.\n\n| Directory               | Purpose                                                          |\n| ----------------------- | ---------------------------------------------------------------- |\n| `scripts\u002Fmobile-agent\u002F` | Device adapter, Jev policy, executor, transports, CLI and tests  |\n| `apps\u002Fjev-studio\u002F`      | Next.js studio, device credentials route, SSE and task lifecycle |\n| `scripts\u002Fdoctor.mjs`    | Configuration and device connectivity checks                     |\n| `scripts\u002Fdemo.mjs`      | Repeatable demo and outcome verification                         |\n| `artifacts\u002F`            | Local-only traces, screenshots and measurements                  |\n\nMIT licensed; dependencies retain their respective licenses.\n","2026-09-20 02:30:03","CREATED_QUERY"]