|
| 1 | +{ |
| 2 | + "schema_version": 1, |
| 3 | + "id": "io.pilot.otto", |
| 4 | + "display_name": "Otto", |
| 5 | + "tagline": "Drive real Chrome tabs from an agent — extract, automate, screenshot, no headless farm", |
| 6 | + "description_md": "Otto is secure remote browser automation. A controller CLI sends commands over an authenticated WebSocket to a relay daemon, which routes them to a Chrome extension running on live tabs. Code drives the browser deterministically; the agent decides what to do, not how to click.\n\nWhat an agent gets:\n- **Content extraction** — `otto.extract` / `otto.extract.format` turn a URL into clean markdown, distilled/clean/raw HTML, or text through a real tab.\n- **Site commands** — `otto.test` runs registered actions on real sessions (Reddit/LinkedIn `getPosts`, Hacker News `getFrontPage`, Google `getSearchResults`, …); `otto.commands` lists what a node exposes.\n- **Page \u0026 tab control** — `otto.screenshot` (viewport or full page) and `otto.cmd` for low-level primitives (tab open/navigate/query, DOM extract).\n- **Status \u0026 diagnostics** — `otto.status` (relay + connected nodes), `otto.client.status`, `otto.authcode`, `otto.extension.info`, `otto.logs`/`otto.logs.status`, `otto.agent.status` — all JSON.\n- **Full CLI surface** — `otto.exec` runs any verbatim otto argv.\n\nGood to know:\n- Returns JSON wherever the CLI offers it; discover the live surface at runtime with `otto.help` — every method, its parameters, and its latency class (fast / med / slow).\n- Real browser tabs, not a headless farm — no Docker, Puppeteer farm, or cloud-browser rental.\n- Prerequisite stack on the host: a running relay (`otto start`), Chrome with the Otto extension loaded and paired as a node, and a logged-in controller. Until that is up, page commands return a structured error (`{stdout,stderr,exit}`); `otto.status` is the right preflight.\n- Runs on macOS and Linux (arm64 + amd64); the otto CLI is staged as a self-contained binary and sha-pinned on install. Free and open source (MIT) — no payment, no per-call limit.", |
| 7 | + "vendor": { |
| 8 | + "name": "Telepat", |
| 9 | + "url": "https://telepat.io", |
| 10 | + "publisher_pubkey": "ed25519:mTyrd5ZG/tl76CLpdUEaaGvCjrnE6QLHPVm7XrduH/w=" |
| 11 | + }, |
| 12 | + "homepage": "https://docs.telepat.io/otto", |
| 13 | + "source_url": "https://github.com/telepat-io/otto", |
| 14 | + "license": "MIT", |
| 15 | + "categories": [ |
| 16 | + "automation", |
| 17 | + "browser", |
| 18 | + "web" |
| 19 | + ], |
| 20 | + "keywords": [ |
| 21 | + "otto", |
| 22 | + "browser", |
| 23 | + "automation", |
| 24 | + "chrome", |
| 25 | + "scraping", |
| 26 | + "extract", |
| 27 | + "markdown", |
| 28 | + "screenshot", |
| 29 | + "agent", |
| 30 | + "web", |
| 31 | + "relay", |
| 32 | + "extension" |
| 33 | + ], |
| 34 | + "size": { |
| 35 | + "bundle_bytes": 5355850, |
| 36 | + "installed_bytes": 9633952 |
| 37 | + }, |
| 38 | + "compat": { |
| 39 | + "min_pilot_version": "1.0.0", |
| 40 | + "runtimes": [ |
| 41 | + "go" |
| 42 | + ] |
| 43 | + }, |
| 44 | + "methods": [ |
| 45 | + { |
| 46 | + "name": "otto.exec", |
| 47 | + "summary": "Run any otto subcommand. Payload is {\"args\":[...]} — the verbatim otto argv. Use this for the full CLI surface beyond the curated methods (config, client register/login/remove, pair, listener unsubscribe, extension update, agent install, site-filtered `commands list --site`, filtered `logs list`, etc.). Add \"--json\" where the command supports it. Example args: [\"commands\",\"list\",\"--site\",\"reddit.com\",\"--json\"]. Note: interactive/streaming subcommands (setup, settings, logs follow, listener subscribe-network, test with stream/wait flags, mcp serve, start --attached) are not suitable over one-shot IPC." |
| 48 | + }, |
| 49 | + { |
| 50 | + "name": "otto.status", |
| 51 | + "summary": "Relay daemon status as JSON: running pid, port, uptime, log path, and the list of currently connected browser node IDs. The right preflight before any page command — an empty node list means no Chrome extension node is paired/online." |
| 52 | + }, |
| 53 | + { |
| 54 | + "name": "otto.commands", |
| 55 | + "summary": "List the automation commands the connected node(s) expose, as JSON. Use to learn which site commands are available before calling otto.test. For a single site, use otto.exec with [\"commands\",\"list\",\"--site\",\"\u003cdomain\u003e\",\"--json\"]." |
| 56 | + }, |
| 57 | + { |
| 58 | + "name": "otto.extract", |
| 59 | + "summary": "Extract the readable content of a web page through a live paired browser tab, as JSON markdown. Opens a temporary tab on the node, extracts, and closes it. Requires a running relay and a paired Chrome node." |
| 60 | + }, |
| 61 | + { |
| 62 | + "name": "otto.extract.format", |
| 63 | + "summary": "Extract page content in a chosen format: markdown, distilled_html, clean_html, raw_html, or text. Returns JSON. Like otto.extract but lets you pick the output representation." |
| 64 | + }, |
| 65 | + { |
| 66 | + "name": "otto.screenshot", |
| 67 | + "summary": "Capture a screenshot of a page through a live browser tab; returns JSON (base64 PNG in the envelope, no local Preview window). Requires a running relay and a paired Chrome node." |
| 68 | + }, |
| 69 | + { |
| 70 | + "name": "otto.test", |
| 71 | + "summary": "Run a registered site command on a browser node (opens a tab, runs the command, returns JSON). Provide site (e.g. reddit.com), command id (e.g. getPosts), and a JSON payload string (use {} for none, e.g. {\"limit\":10}). One-shot; requires relay + paired node." |
| 72 | + }, |
| 73 | + { |
| 74 | + "name": "otto.cmd", |
| 75 | + "summary": "Send a single raw action to the target browser node and return the full JSON envelope. Provide the action name and a JSON payload string (use {} for none). Use for low-level primitives (e.g. primitive.tab.open) not covered by a curated method." |
| 76 | + }, |
| 77 | + { |
| 78 | + "name": "otto.logs", |
| 79 | + "summary": "Read recent relay logs as JSON. For filtered queries (level/source/since/request-id) use otto.exec with [\"logs\",\"list\",...,\"--json\"]." |
| 80 | + }, |
| 81 | + { |
| 82 | + "name": "otto.logs.status", |
| 83 | + "summary": "Relay log storage status as JSON (retention, counts, sizes). Check whether logging is healthy and how much history is available." |
| 84 | + }, |
| 85 | + { |
| 86 | + "name": "otto.client.status", |
| 87 | + "summary": "Local controller client identity state and where its secret resolves from (env vs keychain), as JSON. Verify the controller is registered and logged in before running page commands." |
| 88 | + }, |
| 89 | + { |
| 90 | + "name": "otto.authcode", |
| 91 | + "summary": "List pending pairing codes from the relay as JSON. See codes awaiting approval when bringing a new Chrome extension node online (approve with `otto pair \u003ccode\u003e` via otto.exec)." |
| 92 | + }, |
| 93 | + { |
| 94 | + "name": "otto.extension.info", |
| 95 | + "summary": "Installed Chrome extension artifact metadata (version, unpacked path, checksum) and configured relay URLs, as JSON. Confirm which extension build the host has staged for the Load-unpacked handoff." |
| 96 | + }, |
| 97 | + { |
| 98 | + "name": "otto.agent.status", |
| 99 | + "summary": "Which agent frameworks (claude, codex, cursor, vscode, …) currently have the Otto MCP server registered, as JSON." |
| 100 | + }, |
| 101 | + { |
| 102 | + "name": "otto.help", |
| 103 | + "summary": "Discovery: every method with params, kind, and latency class." |
| 104 | + } |
| 105 | + ], |
| 106 | + "changelog": [ |
| 107 | + { |
| 108 | + "version": "0.20.0", |
| 109 | + "notes": [ |
| 110 | + "Released v0.20.0" |
| 111 | + ] |
| 112 | + } |
| 113 | + ], |
| 114 | + "links": [ |
| 115 | + { |
| 116 | + "label": "Source", |
| 117 | + "url": "https://github.com/telepat-io/otto" |
| 118 | + }, |
| 119 | + { |
| 120 | + "label": "Website", |
| 121 | + "url": "https://docs.telepat.io/otto" |
| 122 | + } |
| 123 | + ] |
| 124 | +} |
0 commit comments