通过 CLI 或 MCP 驱动 macOS、Windows、Linux 上的原生 GUI 应用,按元素索引或像素坐标操作。
浏览器
Qirabot
试用Drive any GUI with natural language — click, type, extract, and verify on web browsers, Android, iOS, desktop apps, and games — using the Qirabot Python SDK....
它能做什么
Drive any GUI with natural language — click, type, extract, and verify on web browsers, Android, iOS, desktop apps, and games — using the Qirabot Python SDK. Use this when the user wants to automate, test, or scrape a user interface by describing elements in plain language instead of CSS/XPath selectors; when driving a mobile app or a native desktop/game where DOM-based tools don't work; or for visual UI verification, screenshots, and RPA. Triggers include: automate a website or app, UI/end-to-end test, fill a form, scrape a page, tap or click a button, verify what's on screen, drive an Android/iOS app, automate a desktop application.
技能文档
Step 0 — Preflight (always run first)
Do NOT write an automation script before the environment checks out. Run:
python scripts/preflight.py browser # or: android | ios | desktop
It verifies Python version, QIRA_API_KEY, that qirabot is importable, and
target-specific bits (e.g. adb devices). If it fails, stop and fix what it
prints — don't proceed and debug a half-set-up run.
One interpreter, one source of truth. Preflight validates one Python and,
on success, prints its absolute path (interpreter: ... and a run line). Run
your script with that exact path, never a bare python — otherwise the run
can drift to a different env than the one you just checked (the #1 false-"Ready"
trap). Whatever already works (an existing venv, the user's global) is fine — the
point is to reuse the validated one, not to force a new venv.
Bootstrap only when preflight reports something missing. Prefer an isolated venv over the user's global Python (and re-run preflight with that venv's Python so it becomes the validated interpreter):
# browser / iOS / desktop can share one venv:
python3 -m venv .qira-venv && source .qira-venv/bin/activate # Windows: .qira-venv\Scripts\activate
pip install "qirabot[browser]" # → also: playwright install chromium
# or qirabot[appium] (iOS: + Appium server & WebDriverAgent) / qirabot[desktop]
# the airtest backends (Android, iOS, and window-scoped Windows desktop) need
# their OWN venv on Python 3.10-3.12 — airtest pins numpy<2 and would conflict a
# shared env:
python3.12 -m venv .qira-venv-airtest && source .qira-venv-airtest/bin/activate
pip install "qirabot[airtest]"
export QIRA_API_KEY="qk_..." # from https://app.qirabot.com
Step 1 — Pick a target and start from a template
| Target | Template | Extra |
|---|---|---|
| Web browser (Qirabot launches Chromium) | templates/browser.py | qirabot[browser] + playwright install chromium. Also supports connecting to an existing Chrome via cdp_url (e.g. Browserless/Browserbase). |
| Android / iOS — Airtest (no Appium server, fastest start) | templates/android.py (Android starter; for iOS keep the API, swap the connect_device string) | qirabot[airtest] (Python 3.10-3.12) |
Android / iOS via Appium, or any Selenium driver (you build the driver, then bind()) | templates/bolt_on.py | qirabot[appium] / qirabot + selenium |
Desktop — Windows & macOS (bind() your driver) | templates/bolt_on.py | qirabot[desktop] (whole screen, any OS) · qirabot[airtest] (Windows only, one window) |
Copy the template, fill in the TODOs (start URL / app package, and the task),
then run it with the interpreter preflight echoed (its absolute path), not a
bare python. templates/bolt_on.py shows the bind-an-existing-driver pattern
with Selenium as the runnable example plus Appium (iOS/Android), pyautogui
(whole-screen desktop, any OS), and Airtest (window-scoped Windows desktop)
variants in comments; see references/REFERENCE.md for the full per-platform
action matrix and bind() details.
Step 2 — Hand the task to qirabot (default), drop to primitives only to optimize
Default: give the whole task to bot.ai.
from qirabot import StepResult
def on_step(step: StepResult) -> None: # live trace -> stdout (see below)
label = "done" if step.finished else step.action_type
print(f" step {step.step}: {label} {step.params} — {step.decision}")
result = bot.ai(target, "Add the cheapest item to the cart and check out",
max_steps=15, on_step=on_step)
print(result.success, result.output)
bot.ai offloads the perceive → decide → act loop to qirabot, which manages its
own step history and self-heals when a step misfires.
Keep the task string a concise goal, not a step-by-step script. bot.ai is
smart enough to plan its own clicks — over-specifying ("click Search, then type
X, then click the first result, then…") fights the model, locks in a brittle
path, and burns extra steps. Write what success looks like, not how to get
there. Good: "Add the cheapest in-stock item to the cart and check out".
Bad: a 6-step click-by-click recipe.
The examples here pass the target explicitly (bot.ai(target, ...)). If you
bind() a stable target first — as the android.py and bolt_on.py templates
do — drop the leading arg: bot.ai("..."), bot.click("..."). (Keep the explicit
form for Playwright so new-tab follows stay visible — see references/REFERENCE.md.)
Always pass on_step. Until it returns, bot.ai is a black box — result
only lands at the end. on_step fires after every step and prints the model's
running decision + action to stdout, which is your one live window into the
run: a stuck, looping, or failed run becomes debuggable straight from the
console, without opening the HTML report. (StepResult also carries .output
and token/duration counts — see references/REFERENCE.md.)
Drop to the per-step primitives only as a deliberate optimization — when you want strict, reproducible determinism, or you're codifying a stable flow to run repeatedly (e.g. a CI regression check). They cost less per action and are reproducible, but are brittle to UI changes:
bot.click(target, "Login button")
bot.type_text(target, "Email field", "a@b.com", press_enter=True)
bot.double_click(target, "the file name to rename") # double-click
bot.long_press(target, "the message bubble", duration=2.5) # mobile: context menu
bot.key_down(target, "w"); bot.key_up(target, "w") # desktop: hold/release a key (pair them)
text = bot.extract(target, "the displayed account balance") # read one thing
bot.wait_for(target, "the dashboard finished loading") # gate, raises on timeout
extract() reads values off the screen; verify() returns a bool the script
can branch on. See Step 3 for when to use which after bot.ai.
See references/REFERENCE.md for the full API: constructor options, bind(),
navigation/scroll/keys, the per-platform action matrix, and errors.
Step 3 — Check the result by who consumes it
Every run writes a self-contained HTML report with per-step screenshots to
./qira_runs///report.html (unless report=False). bot.ai leaves
three signals after it returns — pick by who acts on them:
- A human/agent will read the result → open the report and look at the step
screenshots. Do NOT trust
result.success: it's the same model that just acted, reporting on itself, and can claim victory after clicking the wrong button. - The script must branch on the outcome (CI gate,
if logged_in skip login, conditional flow) →bot.verify(target, "..."). Independent vision call, returnsbool, costs one AI call. The bool must drive something — otherwise it's a billed call whose result goes nowhere, and the screenshot already tells the human reviewer the same thing for free. - The script needs to read a value (price, username, status) →
bot.extract(target, "..."). Beware ambiguous locates:extract("the logged-in username")can grab a rotating search-box hint instead — scope the phrase and cross-check against the screenshot.
When a run fails (result.success=False, or the screenshot looks wrong), the
stdout on_step trace is the fastest entry point — find the step where the
model started looping or chose a wrong action, then jump to that step's
screenshot in the report.
Embed a screen video in the report. The report auto-discovers a file named
recording.mp4 in bot.report_dir and embeds it as a `` at the top
(next to the step screenshots) — just put one there before bot.close():
- Desktop / browser → let the SDK record the host screen for you:
Qirabot(record=True)(or envQIRA_RECORD=1) runs ffmpeg intorecording.mp4, no extra code. - Android / iOS (or any native framework) → host capture can't see the
device, so record the device with its own recorder and write it to
bot.report_dir/recording.mp4. Start beforebot.aiand stop beforebot.close()(close scans for the file):- Airtest (Android):
device().start_recording(output=os.path.join(bot.report_dir, "recording.mp4"), max_time=1800), thendevice().stop_recording(output=...)in afinally. - Appium (iOS/Android):
driver.start_recording_screen(), then writebase64.b64decode(driver.stop_recording_screen())to that same path.
- Airtest (Android):
See references/REFERENCE.md (the record row) for details.
Notes
- One script run = one Qirabot session = one task. State (the live
page/driver) does not survive across separate
pythoninvocations, so put a whole task in one script. To reuse a login across runs, open with a persistent profile:bot.open(url, user_data_dir=os.path.expanduser("~/.qira-profiles/"))(log in once, later runs start authenticated — seereferences/REFERENCE.md). NOTE: pass an absolute path — qirabot/Playwright do NOT expand~, so a literal"~/..."creates a./~/dir in the CWD. Useos.path.expanduser. - Confirm before irreversible or outward-facing actions done under the user's identity (posting a comment, purchasing, deleting): gather/read first, report exactly what you're about to do, get the user's go-ahead, then act. Keep the read step and the action step separate.
- Costs real credits per AI call. Watch for
InsufficientBalanceError. Pick the cheapest model that fits viaQirabot(model_alias=...)—fast/balancedfor simple flows, stepping up only when needed (tiers in REFERENCE). Long human-in-the-loop waits (QR/OTP) poll with billed AI calls — raise thewait_forintervalor poll the live driver instead (see REFERENCE). bot.close()(or thewithform) finalizes the task and writes the report — always close, even on error.
相关技能
AI 驱动的 Android 自动化 — 截屏、点击、滑动、输入、启动应用、UI 识别、多设备群控 | Android automation via ADB, screen capture, tap, swipe, type text, app control, multi-device, phone RPA, adb bot
在脚本里驱动真实 Chrome 完成网页交互:导航、填表、点击、截图、抽取数据。
Interact with the desktop GUI — take screenshots, list/raise windows, click with grid targeting, type text, press key combos. Use when you need to see the sc...
Real-browser QA, repair, release, and regression
Use when AI agents need to read, inspect, operate, navigate, debug, or verify browser state through the omnibot CLI and connected Chromium extension.