# AXBOT Agent API

Base address: `$AXBOT` (from AXBOT > Settings > Agent mode). Every path below starts with it; a request whose path
does not start with the current key gets 404. Requests with an `Origin` header (web pages) get 403.

## HTTP

- `GET $AXBOT/` the guide (SKILL.md), `GET $AXBOT/api.md` this file, `GET $AXBOT/tools` the tools as JSON
  (same as MCP `tools/list`).
- `POST $AXBOT/tools/<tool>`: body is a JSON object of arguments (empty body = no arguments); `<tool>` with or without
  the `axbot_` prefix. 200 with the text result (`image/png` for screenshots); 400 bad arguments or body;
  404 unknown tool; 405 not POST; 409 the user has taken over (paused, handing over, or confirming), or Agent mode
  was turned off; 422 the tool failed. Error bodies are plain text.

## MCP

Streamable HTTP at `$AXBOT/mcp`, protocol versions 2025-11-25, 2025-06-18 and 2025-03-26. One JSON-RPC message per
POST; responses are always `application/json` (no SSE). `initialize` returns an `Mcp-Session-Id` header; send it on
every later request (missing: 400; unknown or expired: 404, then initialize again). Turning Agent mode off,
refreshing the key, or restarting AXBOT invalidates all sessions. Tool failures return `isError: true` with the
same texts as the HTTP error bodies; unknown tools are JSON-RPC errors (-32602); batches are not supported (-32600).

## Tools

`tab` is a tab id from `axbot_tabs` (`t3`) or a CDP target id; when omitted, the current tab. `target` is a ref from
the latest snapshot of that page (`@12`), a CSS selector, or `text=Visible text`, and must match exactly one element.

| Tool | Parameters | Result |
|---|---|---|
| `axbot_tabs` | | Tabs grouped by Space (`Space s1 "Name" (current)`), private tabs in their own group; one line per tab: id, flags (`current`, `private`, `loading`, `not loaded`), title, url |
| `axbot_tab` | `action: new\|select\|close\|move`, `tab?`, `url?`, `space?`, `private?`, `activate?` | new: opens `url` (default about:blank) in the current Space, in `space`, or as a private tab, waits for the page, switches to it unless `activate: false`. select: brings `tab` to the front. close: closes `tab` (regular tabs go to recently closed). move: moves a regular `tab` to `space`. The older parameter name `sphere` also works |
| `axbot_space` | `action: new\|switch\|rename\|delete`, `name?`, `space?` | new: creates a Space named `name`. switch: shows `space` (its start page). rename: renames `space` to `name`. delete: deletes `space` and closes its tabs after the user confirms on the phone (the last Space cannot be deleted). `space` is an id (`s2`) or a name. The older name `axbot_sphere` (with `sphere`) also works |
| `axbot_navigate` | `url?`, `tab?`, `action?: goto\|reload\|back\|forward`, `waitUntil?: load\|domcontentloaded\|commit`, `timeout?` (s, default 30) | Without `tab`: opens `url` in a new tab. With `tab`: goto / reload / back / forward there. Only http, https and about:blank. Receipt |
| `axbot_snapshot` | `tab?`, `scope?: viewport\|full` | Header (tab, url, title, events) and the element list |
| `axbot_click` | `target`, `tab?` | Receipt |
| `axbot_fill` | `target`, `value`, `tab?` | Text field and textarea: sets the value (input and change events). Select: option by value or text. Checkbox or radio: `true` / `false`. Receipt |
| `axbot_press` | `key`, `target?`, `tab?` | Key on `target` or the focused element: Enter (submits the form of an input, activates links and buttons), Tab, Escape, Backspace, Delete, Space, ArrowUp/Down/Left/Right, or one character. Receipt |
| `axbot_scroll` | `dx?`, `dy?`, `target?`, `tab?` | Scrolls the page or `target` by CSS pixels; `target` alone scrolls it into view. Receipt with the scroll position |
| `axbot_screenshot` | `tab?`, `fullPage?` | PNG of the visible page (up to 1170 px wide), or with `fullPage` the whole page at the screen's width, up to 8 screens |
| `axbot_evaluate` | `script`, `arg?`, `tab?` | Runs `script` as the body of an async function in the page (`return` a value; the argument is `arg`). The JSON of the value, or `undefined`. 10 s timeout, result up to 1 MB |
| `axbot_wait` | `url?` (glob with `*`, else substring), `selector?` (visible), `text?`, `ms?`, `timeout?` (s, default 30), `tab?` | Returns when all given conditions hold, or after `ms`; fails with "Timed out" |
| `axbot_console` | `tab?`, `after?`, `level?: log\|info\|warn\|error\|debug` | Lines `#12 [error] 10:23:01.200 message` (newest 50 without `after`), then `next after: <n>` |
| `axbot_scripts` | `action: list\|install\|enable\|disable\|source\|delete`, `name?`, `namespace?`, `source?`, `url?` | list: name, namespace, version, enabled, matches. install: from `source` or `url`; same @name and @namespace updates it (stored values kept). source: the script text, or replaces it when `source` is given. delete: the user confirms on the phone (up to 60 s); otherwise "nothing was deleted". Changes apply when pages reload |
| `axbot_handoff` | `message`, `timeout?` (s, default 50, max 600) | Shows `message` on the phone and waits for the user to tap 完成 (Done). Fails with "not finished yet" on timeout; call again to keep waiting |

Receipt of an action or navigation:

```
filled detail (if any)
tab: t3
url: https://example.com/next
title: Next page
The page navigated.
New tabs: t7
Event: confirm: Delete this? (dismissed)
```

`New tabs` lists tabs that appeared during the call (the tab `axbot_navigate` opened, windows the page opened).

Snapshot lines (indented by nesting):

```
- heading "Sign in" [@1] level=1
- form
  - textbox "Email" [@2] value=""
  - textbox "Password" [@3] value="••••"
  - checkbox "Remember me" [@4] unchecked
  - button "Continue" [@5]
- link "Forgot password?" [@6] → /reset
- text "Some paragraph"
```

Refs are unique until AXBOT restarts: a ref from another page or tab never points at a different element; it fails
as stale. An element that was removed or replaced is stale too.

Error texts include: `The user has taken over AXBOT. Wait and retry later.` · `Agent mode was turned off on the phone.` ·
`No tab t9. Call axbot_tabs to list the open tabs.` · `ref @7 is stale ...` · `#x matched 2 elements; it must match
exactly one.` · `Navigation failed: <reason>` · `Timed out after 30 s waiting for the page (load).`

## CDP subset

HTTP: `GET $AXBOT/json/version`, `GET $AXBOT/json` and `$AXBOT/json/list` (all tabs; `id` is the target id, private
tabs have `description: "private"`), `GET $AXBOT/json/protocol`, `PUT $AXBOT/json/new?<url>`,
`GET $AXBOT/json/activate/<id>`, `GET $AXBOT/json/close/<id>`. Each target's `webSocketDebuggerUrl` is
`ws://<host>/<key>/devtools/page/<id>`.

chrome-remote-interface: `CDP({target: webSocketDebuggerUrl, local: true})`, or pass `host`, `port` and
`alterPath: p => p.startsWith('/<key>/') ? p : '/<key>' + p` to `CDP()` and `CDP.List()`.

| Method | Notes |
|---|---|
| `Page.navigate` | `url`; returns after the page loaded, `errorText` on failure |
| `Page.reload` | Returns after the page loaded |
| `Page.captureScreenshot` | `format: png\|jpeg`, `quality`, `clip {x, y, width, height}` (relative to the visible page), `captureBeyondViewport` (whole page) |
| `Page.bringToFront` | |
| `Runtime.evaluate` | `expression`; promises are awaited and values are returned by value (`result.value`); exceptions in `exceptionDetails` |
| `Target.getTargets`, `Target.createTarget`, `Target.closeTarget`, `Target.activateTarget` | All tabs (private tabs have `browserContextId: "private"`, the others `"default"`); new targets open in the current Space |

The browser WebSocket (`webSocketDebuggerUrl` from `/json/version`) supports `Browser.getVersion` and the four Target
methods. Everything else fails with -32601 `'<method>' wasn't found`; there are no events except
`Inspector.detached` when a tab closes. While the user has control, CDP calls fail with -32000 and discovery
endpoints other than `/json/version` with 503.
