From 810a0e8eaba1ad21045fd6c973927efe2086da72 Mon Sep 17 00:00:00 2001 From: Alex Godoroja <50743382+Alexgodoroja@users.noreply.github.com> Date: Wed, 24 Jun 2026 15:08:05 -0700 Subject: [PATCH] =?UTF-8?q?submit=20io.pilot.otto=20v0.20.0=20(Otto=20?= =?UTF-8?q?=E2=80=94=20remote=20browser=20automation)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/samples/ab-report-otto.html | 278 ++++++++++++++++++ docs/samples/otto-ab-cases.json | 4 + submissions/io.pilot.otto/submission.json | 331 ++++++++++++++++++++++ 3 files changed, 613 insertions(+) create mode 100644 docs/samples/ab-report-otto.html create mode 100644 docs/samples/otto-ab-cases.json create mode 100644 submissions/io.pilot.otto/submission.json diff --git a/docs/samples/ab-report-otto.html b/docs/samples/ab-report-otto.html new file mode 100644 index 0000000..cad4228 --- /dev/null +++ b/docs/samples/ab-report-otto.html @@ -0,0 +1,278 @@ + +A/B report — io.pilot.otto + +

Vanilla vs Pilot — A/B report

+

App io.pilot.otto · delivered from the Pilot R2 artifact registry · generated by scripts/ab_report.py

+ +

Summary

+
CommandVanilla (ms)Pilot (ms)Δ overheadMatch
Version240695+455
Relay status124379+255
Controller client status125481+356
Discover node commands1341098+964
+ +

Adapter-generated help — otto.help (local, no backend), 353 ms

+
+
Pilot · otto.help (generated by the adapter)
{
+  "app": "io.pilot.otto",
+  "version": "0.20.0",
+  "description": "Drive real Chrome tabs from an agent: extract page content as markdown or HTML, run site commands (Reddit, LinkedIn, Hacker News, Google), screenshot pages, and inspect relay and node status \u2014 over a relay to a browser extension, no headless farm. Plus a passthrough exec for any otto subcommand.",
+  "duration_classes": {
+    "fast": "<~1s \u2014 status or cheap call",
+    "med": "~1-5s \u2014 moderate work",
+    "slow": "~5-30s \u2014 heavy / multi-step"
+  },
+  "methods": [
+    {
+      "method": "otto.exec",
+      "kind": "utility",
+      "summary": "Run any otto subcommand. Payload is {\"args\":[...]} \u2014 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.",
+      "params": {
+        "args": "array (required) \u2014 verbatim otto argv, e.g. [\"status\",\"--nodes\",\"--json\"]"
+      },
+      "duration": "med"
+    },
+    {
+      "method": "otto.status",
+      "kind": "utility",
+      "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 \u2014 an empty node list means no Chrome extension node is paired/online.",
+      "duration": "fast"
+    },
+    {
+      "method": "otto.commands",
+      "kind": "utility",
+      "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\",\"<domain>\",\"--json\"].",
+      "duration": "med"
+    },
+    {
+      "method": "otto.extract",
+      "kind": "utility",
+      "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.",
+      "params": {
+        "url": "string (required) \u2014 page URL to extract from"
+      },
+      "duration": "slow"
+    },
+    {
+      "method": "otto.extract.format",
+      "kind": "utility",
+      "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.",
+      "params": {
+        "format": "string (required) \u2014 markdown | distilled_html | clean_html | raw_html | text",
+        "url": "string (required) \u2014 page URL to extract from"
+      },
+      "duration": "slow"
+    },
+    {
+      "method": "otto.screenshot",
+      "kind": "utility",
+      "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.",
+      "params": {
+        "url": "string (required) \u2014 page URL to screenshot"
+      },
+      "duration": "slow"
+    },
+    {
+      "method": "otto.test",
+      "kind": "utility",
+      "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.",
+      "params": {
+        "command": "string (required) \u2014 command id, e.g. getPosts",
+        "payload": "string (required) \u2014 command input JSON object string; use {} if none",
+        "site": "string (required) \u2014 website domain, e.g. reddit.com"
+      },
+      "duration": "slow"
+    },
+    {
+      "method": "otto.cmd",
+      "kind": "utility",
+      "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.",
+      "params": {
+        "action": "string (required) \u2014 action name, e.g. command.list or primitive.tab.open",
+        "payload": "string (required) \u2014 JSON object string for the action payload; use {} if none"
+      },
+      "duration": "med"
+    },
+    {
+      "method": "otto.logs",
+      "kind": "utility",
+      "summary": "Read recent relay logs as JSON. For filtered queries (level/source/since/request-id) use otto.exec with [\"logs\",\"list\",...,\"--json\"].",
+      "duration": "fast"
+    },
+    {
+      "method": "otto.logs.status",
+      "kind": "utility",
+      "summary": "Relay log storage status as JSON (retention, counts, sizes). Check whether logging is healthy and how much history is available.",
+      "duration": "fast"
+    },
+    {
+      "method": "otto.client.status",
+      "kind": "utility",
+      "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.",
+      "duration": "fast"
+    },
+    {
+      "method": "otto.authcode",
+      "kind": "utility",
+      "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 <code>` via otto.exec).",
+      "duration": "fast"
+    },
+    {
+      "method": "otto.extension.info",
+      "kind": "utility",
+      "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.",
+      "duration": "fast"
+    },
+    {
+      "method": "otto.agent.status",
+      "kind": "utility",
+      "summary": "Which agent frameworks (claude, codex, cursor, vscode, \u2026) currently have the Otto MCP server registered, as JSON.",
+      "duration": "fast"
+    },
+    {
+      "method": "otto.help",
+      "kind": "meta",
+      "summary": "This document \u2014 every method with params, kind, and duration class.",
+      "duration": "fast",
+      "typical_roundtrip": "instant (local, no backend call)"
+    }
+  ]
+}
+
Vanilla · smolvm --help (133 ms)
Usage: otto [options] [command]
+
+Automate web workflows on real browser tabs without hosting a browser farm.
+
+Options:
+  -V, --version                    output the version number
+  -h, --help                       display help for command
+
+Commands:
+  start [options]                  Start relay (daemon by default, or attached
+                                   for development)
+  stop                             Stop relay daemon if it is running
+  restart [options]                Restart relay daemon
+  status [options]                 Show relay daemon status
+  relay:start [options]            Start relay in attached foreground mode
+                                   (legacy alias)
+  config [options]                 Configure relay and defaults
+  setup [options]                  Guided controller setup including relay
+                                   daemon readiness, extension acquisition, and
+                                   Chrome handoff instructions
+  extension                        Manage extension artifact installation for
+                                   setup
+  settings                         Edit controller-global settings stored in
+                                   ~/.otto/config.json
+  client                           Manage independently registered controller
+                                   clients
+  authcode                         List pending auth codes
+  pair <code>                      Approve pairing code and store controller
+                                   tokens
+  revoke                           Revoke stored refresh token from relay and
+                                   clear local controller auth
+  cmd [options]                    Send a command to a target node
+  test [options] <site> <command>  Run a website command for local developer
+                                   testing
+  commands                         Discover available commands from target node
+  logs                             Read relay logs
+  listener                         Manage long-lived node listeners
+  extract-content [options] [url]  Extract page content with one command
+                                   (markdown, distilled_html, clean_html,
+                                   raw_html, or text)
+  screenshot [options] <url>       Capture a screenshot of a page and open it
+                                   locally
+  mcp                              Model Context Protocol server operations
+  agent                            Manage agent framework integrations
+  help [command]                   display help for command
+
+ +

Per-command detail

+ +
+

Version

+

enumerated → otto --version

+
+
Vanilla CLI
otto-darwin-arm64 --version
exit 0240 ms
0.20.0
+
Pilot app store
pilotctl appstore call io.pilot.otto otto.exec '{"args": ["--version"]}'
exit 0695 ms
0.20.0
+
+
adapter overhead: +455 ms + (vanilla 240 ms · pilot 695 ms)
+
+
+

Relay status

+

otto status --nodes --json (relay not running here)

+
+
Vanilla CLI
otto-darwin-arm64 status --nodes --json
exit 0124 ms
{
+  "running": false,
+  "daemon": null,
+  "suggestedCommand": "otto start",
+  "logsFollowCommand": null,
+  "nodes": []
+}
+
Pilot app store
pilotctl appstore call io.pilot.otto otto.status '{}'
exit 0379 ms
{
+  "running": false,
+  "daemon": null,
+  "suggestedCommand": "otto start",
+  "logsFollowCommand": null,
+  "nodes": []
+}
+
+
adapter overhead: +255 ms + (vanilla 124 ms · pilot 379 ms)
+
+
+

Controller client status

+

otto client status (always JSON)

+
+
Vanilla CLI
otto-darwin-arm64 client status
exit 0125 ms
{
+  "relayUrl": "ws://127.0.0.1:8787?role=controller",
+  "relayHttpUrl": "http://127.0.0.1:8787",
+  "controllerClientId": null,
+  "controllerName": null,
+  "controllerDescription": null,
+  "hasAccessToken": false,
+  "hasRefreshToken": false,
+  "secretSource": "missing"
+}
+
Pilot app store
pilotctl appstore call io.pilot.otto otto.client.status '{}'
exit 0481 ms
{
+  "relayUrl": "ws://127.0.0.1:8787?role=controller",
+  "relayHttpUrl": "http://127.0.0.1:8787",
+  "controllerClientId": null,
+  "controllerName": null,
+  "controllerDescription": null,
+  "hasAccessToken": false,
+  "hasRefreshToken": false,
+  "secretSource": "missing"
+}
+
+
adapter overhead: +356 ms + (vanilla 125 ms · pilot 481 ms)
+
+
+

Discover node commands

+

otto commands list --json (needs a paired node)

+
+
Vanilla CLI
otto-darwin-arm64 commands list --json
exit 1134 ms
+── stderr ──
+Missing targetNodeId. Set with `otto config --node-id` or pass --node-id
+
Pilot app store
pilotctl appstore call io.pilot.otto otto.commands '{}'
exit 11098 ms
+── stderr ──
+Missing targetNodeId. Set with `otto config --node-id` or pass --node-id
+
+
adapter overhead: +964 ms + (vanilla 134 ms · pilot 1098 ms)
+
diff --git a/docs/samples/otto-ab-cases.json b/docs/samples/otto-ab-cases.json new file mode 100644 index 0000000..ed85335 --- /dev/null +++ b/docs/samples/otto-ab-cases.json @@ -0,0 +1,4 @@ +[{"label":"Version","note":"enumerated → otto --version","vanilla":["--version"],"method":"otto.exec","payload":{"args":["--version"]}}, + {"label":"Relay status","note":"otto status --nodes --json (relay not running here)","vanilla":["status","--nodes","--json"],"method":"otto.status","payload":{}}, + {"label":"Controller client status","note":"otto client status (always JSON)","vanilla":["client","status"],"method":"otto.client.status","payload":{}}, + {"label":"Discover node commands","note":"otto commands list --json (needs a paired node)","vanilla":["commands","list","--json"],"method":"otto.commands","payload":{}}] diff --git a/submissions/io.pilot.otto/submission.json b/submissions/io.pilot.otto/submission.json new file mode 100644 index 0000000..34b53a8 --- /dev/null +++ b/submissions/io.pilot.otto/submission.json @@ -0,0 +1,331 @@ +{ + "id": "io.pilot.otto", + "version": "0.20.0", + "description": "Drive real Chrome tabs from an agent: extract page content as markdown or HTML, run site commands (Reddit, LinkedIn, Hacker News, Google), screenshot pages, and inspect relay and node status — over a relay to a browser extension, no headless farm. Plus a passthrough exec for any otto subcommand.", + "email": "hello@telepat.io", + "backend": { + "type": "cli", + "command": [ + "otto" + ] + }, + "methods": [ + { + "name": "otto.exec", + "description": "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.", + "latency": "med", + "params": [ + { + "name": "args", + "type": "array", + "required": true, + "description": "verbatim otto argv, e.g. [\"status\",\"--nodes\",\"--json\"]" + } + ], + "cli": { + "passthrough": true + } + }, + { + "name": "otto.status", + "description": "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.", + "latency": "fast", + "cli": { + "args": [ + "status", + "--nodes", + "--json" + ] + } + }, + { + "name": "otto.commands", + "description": "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\",\"\",\"--json\"].", + "latency": "med", + "cli": { + "args": [ + "commands", + "list", + "--json" + ] + } + }, + { + "name": "otto.extract", + "description": "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.", + "latency": "slow", + "params": [ + { + "name": "url", + "type": "string", + "required": true, + "description": "page URL to extract from" + } + ], + "cli": { + "args": [ + "extract-content", + "${url}", + "--format", + "markdown", + "--json" + ] + } + }, + { + "name": "otto.extract.format", + "description": "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.", + "latency": "slow", + "params": [ + { + "name": "url", + "type": "string", + "required": true, + "description": "page URL to extract from" + }, + { + "name": "format", + "type": "string", + "required": true, + "description": "markdown | distilled_html | clean_html | raw_html | text" + } + ], + "cli": { + "args": [ + "extract-content", + "${url}", + "--format", + "${format}", + "--json" + ] + } + }, + { + "name": "otto.screenshot", + "description": "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.", + "latency": "slow", + "params": [ + { + "name": "url", + "type": "string", + "required": true, + "description": "page URL to screenshot" + } + ], + "cli": { + "args": [ + "screenshot", + "${url}", + "--json" + ] + } + }, + { + "name": "otto.test", + "description": "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.", + "latency": "slow", + "params": [ + { + "name": "site", + "type": "string", + "required": true, + "description": "website domain, e.g. reddit.com" + }, + { + "name": "command", + "type": "string", + "required": true, + "description": "command id, e.g. getPosts" + }, + { + "name": "payload", + "type": "string", + "required": true, + "description": "command input JSON object string; use {} if none" + } + ], + "cli": { + "args": [ + "test", + "${site}", + "${command}", + "--payload", + "${payload}", + "--json" + ] + } + }, + { + "name": "otto.cmd", + "description": "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.", + "latency": "med", + "params": [ + { + "name": "action", + "type": "string", + "required": true, + "description": "action name, e.g. command.list or primitive.tab.open" + }, + { + "name": "payload", + "type": "string", + "required": true, + "description": "JSON object string for the action payload; use {} if none" + } + ], + "cli": { + "args": [ + "cmd", + "--action", + "${action}", + "--payload", + "${payload}", + "--json" + ] + } + }, + { + "name": "otto.logs", + "description": "Read recent relay logs as JSON. For filtered queries (level/source/since/request-id) use otto.exec with [\"logs\",\"list\",...,\"--json\"].", + "latency": "fast", + "cli": { + "args": [ + "logs", + "list", + "--json" + ] + } + }, + { + "name": "otto.logs.status", + "description": "Relay log storage status as JSON (retention, counts, sizes). Check whether logging is healthy and how much history is available.", + "latency": "fast", + "cli": { + "args": [ + "logs", + "status", + "--json" + ] + } + }, + { + "name": "otto.client.status", + "description": "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.", + "latency": "fast", + "cli": { + "args": [ + "client", + "status" + ] + } + }, + { + "name": "otto.authcode", + "description": "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 ` via otto.exec).", + "latency": "fast", + "cli": { + "args": [ + "authcode" + ] + } + }, + { + "name": "otto.extension.info", + "description": "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.", + "latency": "fast", + "cli": { + "args": [ + "extension", + "info" + ] + } + }, + { + "name": "otto.agent.status", + "description": "Which agent frameworks (claude, codex, cursor, vscode, …) currently have the Otto MCP server registered, as JSON.", + "latency": "fast", + "cli": { + "args": [ + "agent", + "status", + "--json" + ] + } + } + ], + "listing": { + "display_name": "Otto", + "tagline": "Drive real Chrome tabs from an agent — extract, automate, screenshot, no headless farm", + "app_description": "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 & tab control** — `otto.screenshot` (viewport or full page) and `otto.cmd` for low-level primitives (tab open/navigate/query, DOM extract).\n- **Status & 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.", + "license": "MIT", + "homepage": "https://docs.telepat.io/otto", + "source_url": "https://github.com/telepat-io/otto", + "categories": [ + "automation", + "browser", + "web" + ], + "keywords": [ + "otto", + "browser", + "automation", + "chrome", + "scraping", + "extract", + "markdown", + "screenshot", + "agent", + "web", + "relay", + "extension" + ] + }, + "vendor": { + "name": "Telepat", + "url": "https://telepat.io", + "agent_usage": "Agents call curated methods (otto.extract, otto.test, otto.screenshot, otto.status, otto.commands, ...) or otto.exec with a verbatim otto argv to drive a real Chrome tab via the relay; output returns as JSON or {stdout,stderr,exit}.", + "capabilities": "Extract page content (markdown/HTML/text); run registered site commands (Reddit/LinkedIn/HN/Google); screenshot pages; send low-level tab/DOM primitives; inspect relay status, connected nodes, logs, client identity, extension, and agent integrations; reach any otto subcommand via passthrough." + }, + "artifacts": [ + { + "os": "darwin", + "arch": "arm64", + "url": "https://pub-f09f9a4ea848491198d48e329ba030e3.r2.dev/io.pilot.otto/0.20.0/darwin-arm64/otto-0.20.0-darwin-arm64.tar.gz", + "sha256": "b803292b97d36a78116786106ad0b11876be7cd03b1d10bad318c1ab6405a4cd", + "unpack": "tar.gz", + "exec_path": "otto-0.20.0-darwin-arm64/otto", + "order": 1, + "role": "binary" + }, + { + "os": "darwin", + "arch": "amd64", + "url": "https://pub-f09f9a4ea848491198d48e329ba030e3.r2.dev/io.pilot.otto/0.20.0/darwin-amd64/otto-0.20.0-darwin-amd64.tar.gz", + "sha256": "ffb446fe7fdd666395776ee4679011103dca288b13a47f08c75dd7884cbcaac6", + "unpack": "tar.gz", + "exec_path": "otto-0.20.0-darwin-amd64/otto", + "order": 1, + "role": "binary" + }, + { + "os": "linux", + "arch": "arm64", + "url": "https://pub-f09f9a4ea848491198d48e329ba030e3.r2.dev/io.pilot.otto/0.20.0/linux-arm64/otto-0.20.0-linux-arm64.tar.gz", + "sha256": "a0dfdfc2ea5e361112aa48d8bbf92e65573fe47643e573f535594239cbba1177", + "unpack": "tar.gz", + "exec_path": "otto-0.20.0-linux-arm64/otto", + "order": 1, + "role": "binary" + }, + { + "os": "linux", + "arch": "amd64", + "url": "https://pub-f09f9a4ea848491198d48e329ba030e3.r2.dev/io.pilot.otto/0.20.0/linux-amd64/otto-0.20.0-linux-amd64.tar.gz", + "sha256": "8e148e7604a6b4ba639ef50c5215ae198f699cd7f6d544e29131fee59cb1d3af", + "unpack": "tar.gz", + "exec_path": "otto-0.20.0-linux-amd64/otto", + "order": 1, + "role": "binary" + } + ] +}