# Overview (/docs) **AskUI** is agentic UI test automation based on **Computer Use Agents (CUA)**. It lets non-technical people automate **Desktop, Mobile & Web** applications without writing code, there is no selector to write and no recording to maintain. You describe a step in plain language ("click the login button", "fill in the email field with the QA credentials"), a CUA agent carries it out on the real screen, and a report shows you exactly what happened and why. You author and run tests in the **Desktop App**, integrate everything into your CI and development workflow with the **AskUI CLI**, rely on **AgentOS** to make any OS available to the CUA agent, and manage your workspace centrally in the **AskUI Hub**. ## How these docs are organized [#how-these-docs-are-organized] Go from zero to a passing test in under 10 minutes. Covers account creation, installation, and your first run. Install AskUI Desktop, connect your devices, and follow the workflow: write tests, run them, read the results. Test cases, plans, procedures, and prompts, how to author tests the agent runs reliably. Run from the app, schedule recurring runs, or go headless in CI with the CLI. The runtime layer that makes any OS available to the CUA agent. Installation, deployment modes, and enterprise configuration. Workspaces, access tokens, and plans in the AskUI Hub. ## The four components [#the-four-components] | Component | What it is | When you need it | | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | | **AskUI Desktop** | GUI app for editing and running tests on your local environment, with one-click device management & provisioning and scheduled runs | Always, this is where you write and review tests | | **AskUI CLI** | Headless runner (`askui run`) that integrates AskUI into your CI and development workflow | CI pipelines, scheduled runs, multi-device fleets | | **AgentOS** | Makes any OS available to the CUA agent, keyboard, mouse, and screen | Desktop and Android targets (installed automatically for local runs) | | **AskUI Hub** | The central management platform, workspace, members, access tokens, and usage | Account setup, tokens for CI, billing | ## Not sure where to start? [#not-sure-where-to-start] Go to the **[Quickstart](/docs/quickstart)**, it walks you through account creation, installation, and a first passing test in under 10 minutes. # Projects (/docs/projects) A **Project** is your testware in one folder, it lives on your device and syncs via Git. Test cases, test plans, reusable keywords, environment definitions, the tooling the agent may use: every artifact is a plain file. | Folder / file | In tester terms | Example | | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | | `tests/` | Test suites and test cases. A file is a case (steps, expected results); a sub-folder is a suite with its own `setup.md` / `teardown.md` (entry criteria and cleanup); `rules.md` = standing test instructions; [`ui.md`](/docs/writing-tests/agents-and-prompts#ui-information) = how the application under test works | `checkout/pay_with_card.md` | | `plans/` | Test plans: which cases make up the smoke set, the regression pack, and on which device they run | [`smoke.yaml`](/docs/writing-tests/plans) | | `procedures/` | Keywords, as in keyword-driven testing: write a sequence once, call it from any case with parameters | [`login_to_ui.md`](/docs/writing-tests/procedures) | | `utils/` | The permitted tooling and output conventions: [built-in tools](/docs/extending/tools), [MCP servers](/docs/extending/mcp), [custom C# tools](/docs/extending/custom-tools), the [report format](/docs/writing-tests/agents-and-prompts#report-format) | `format.md`, `custom_tools/query_admin_api.cs` | | `devices.json` | The test environments, each with its own [prompt text](/docs/writing-tests/agents-and-prompts#device-prompt), see [Devices](/docs/devices) | , | | `schedules.json` | The execution schedule, [recurring runs](/docs/running-tests/scheduling) | , | | `agent_workspace/` | Test evidence: [execution logs, reports, screenshots](/docs/results/run-report). Generated per run, not versioned | , | **Test case formats:** Markdown is the default, but the runner also reads `.txt`, `.csv`, one case per row, the natural fit for data-driven testing, `.pdf` (an exported or scanned specification can be executed directly), and `.json`. A new Project comes pre-seeded with this scaffold, fill in the placeholders instead of starting blank. ## Git: Versioning & Sync [#git-versioning--sync] Every artifact above is a plain text file, deliberately. A Project is persisted **as code** and synchronized via Git, which gives you configuration management of the complete testware: branches and reviews for test changes, history to diff yesterday's case against today's, and reproducibility, a colleague clones the repository and has the identical suites, environments, and toolbox. The app has Git built in, no terminal needed for the daily loop: **Start versioning** 1. Click **Init git** in the top bar (shown when the project folder is not a repository yet). This also writes the project's `.gitignore`. **Commit and sync** The source-control flyout, changed files, commit message field, and the sync row 1. Click the branch chip in the top bar, a dot marks uncommitted changes, `↓`/`↑` how far you are behind/ahead of the remote. 2. Review the changed files, type a commit message, and commit. 3. **Sync** pulls the remote's changes and pushes yours. Conflicts block the sync until you resolve them in the flyout, keep yours, take theirs, or mark resolved after editing. **Get an existing project** 1. On the Home page, choose **Clone from Git** and paste the repository URL (`https://…` or `git@…`). **Keep run artifacts out** The seeded `.gitignore` excludes `agent_workspace/` (test evidence, regenerated every run) and the run cache. If a project has no `.gitignore`, or run artifacts show up in the changes list, the flyout offers **Add .gitignore for run artifacts**, one click. Credentials never need ignoring: they live in the app's encrypted [secret store](/docs/extending/secrets), not in the project folder. The deliberately small scope, commit everything, sync, resolve, covers the tester's daily loop; branch management and partial staging stay in your Git client of choice. Which team owns which repository: [Sharing the project](/docs/concepts/team-setups). # Quickstart (/docs/quickstart) Find your first bug in 10 minutes. This guide takes you from a blank machine to your first test run, no selectors, no code, just plain language. Four steps: download AskUI Desktop, sign in, walk the onboarding wizard, and run the template's example test on your own machine. A Windows or macOS machine. No prior automation experience required. *** ## Step 1: Download AskUI Desktop (2 min) [#step-1-download-askui-desktop-2-min] Grab the installer for your platform and run it. It's self-contained, no extra runtimes needed. Run the `.exe` and follow the guided setup. Open the `.dmg` and drag AskUI Desktop into Applications. You'll grant screen and input permissions during the onboarding wizard in Step 3. These links point to the current release (v0.5.0). The [Releases page](https://github.com/askui/integrated-task-platform/releases/latest) always lists the newest installers, and they're also on your [AskUI Hub](https://hub.askui.com) account page. *** ## Step 2: Sign up or log in (2 min) [#step-2-sign-up-or-log-in-2-min] Launch AskUI Desktop and sign in with your AskUI account. **New to AskUI?** Click **Sign up** to create an account with your work email, accept the terms, and verify your email from the link we send. Accounts and billing live in the [AskUI Hub](https://hub.askui.com). **Already have an account?** Click **Log in** and authenticate in your browser. The same login works across Desktop, the CLI, and the Hub. Authentication uses Auth0 (OIDC) and opens in your system browser. *** ## Step 3: Walk the onboarding wizard (3 min) [#step-3-walk-the-onboarding-wizard-3-min] On first launch, AskUI Desktop opens a short setup wizard. **Welcome.** A quick tour of what AskUI does, click **Get started**. **Grant system permissions** *(macOS only).* Allow **Screen Recording** and **Accessibility** so the agent can see the screen and control input. The status flips green automatically once granted. **Create your first project, Start from template.** Choose **Start from template** (recommended) and pick an empty folder. AskUI scaffolds the default template: `tests/` (with `ui.md` and `rules.md`), `procedures/`, and `utils/`, pre-filled with an example test and the context files (`ui.md`, `rules.md`), ready to run. **You're set.** The final screen maps out where everything lives. Click **Start testing** to open your new project. *** ## Step 4: Run your first test locally (3 min) [#step-4-run-your-first-test-locally-3-min] The default template ships with a runnable example test, run it against your own machine to see a full pass end to end. **Open the example test** in `tests/`. It's plain Markdown, readable steps, no code or selectors. Leave it as-is for this first run. **Run it locally.** Start the run against your local machine (this computer). AskUI Desktop launches the agent, which acts on the screen step by step and streams progress into **Live Run**. **Read the report.** Each step shows its status (`PASSED`, `FAILED`, `WARN`, `SKIPPED`, or `BROKEN`) and a screenshot. A green run means every step actually passed, the agent doesn't improvise its way to done. Once the example passes, open `tests/ui.md` on the Tests page and describe your own app, its main screens, how to tell you're signed in, and any quirks. It's the single most important file for reliable runs. See [Prompting best practices](/docs/best-practices/prompting-best-practices). *** ## What's next [#whats-next] You have a working project. Here is where to go from here: Learn how to structure prompts so your runs stay reliable as your test suite grows, the four-file layout, `rules.md`, and how to avoid brittle tests. Understand what each folder in a Project does and how the runner picks up setup, teardown, and shared procedures automatically. Once your project runs locally, move it to CI in minutes with `askui run`. Works with GitHub Actions, GitLab CI, and any headless environment. Running tests on a remote machine or in a multi-device fleet? Learn how to install and configure AgentOS as a background service. # Plans & billing (/docs/account-billing/billing) Billing is handled per **workspace** in the AskUI Hub. Each workspace has a **subscription** to a plan, and your runs are metered against it. ## Subscriptions [#subscriptions] A subscription has one or more **items** (the plans/products you're paying for) and a current billing period: * **Trial**: new subscriptions may start in a trial. The Hub shows whether you're on a trial and when it ends. * **Billing period**: each subscription has a current period (start → end). Usage and renewals are tracked against this period. * **Allowed usage**: each plan grants an amount of included usage for the period. ## Usage metering [#usage-metering] Every run records **usage events** against the workspace. Each event is attributed to: * the **workspace** it ran in, * the **user** or **access token** that triggered it, and * a **timestamp**. This is what lets you see usage in the Hub broken down by who (or which CI token) is consuming it. Runs from the CLI in CI are attributed to the [access token](/docs/account-billing/workspaces#access-tokens) that authenticated them. ## Plans [#plans] Plans differ by price and included usage: * **Product / name**: what the plan is. * **Price**: an amount and currency, billed on a recurring interval. * **Included usage**: the allowance per period before overage applies. For specific plan names and pricing, visit [askui.com](https://www.askui.com) or contact [sales@askui.com](mailto:sales@askui.com). For enterprise and on-premise terms see [AgentOS, Enterprise](/docs/agentos/reference/enterprise). # Members (/docs/account-billing/members) Each AskUI workspace can have multiple members. Members share access to the workspace's projects, access tokens, and usage data. You manage membership from **Settings** in the AskUI Hub. ## Roles [#roles] Every member is assigned one of three roles when invited. Roles cannot be changed after a member joins, to change a role, remove the member and re-invite them with the new role. | Role | What they can do | | ---------- | ------------------------------------------------------------------------------------------------------------------------- | | **Owner** | Full control: manage subscription, billing, and other owners. Can delete the workspace. | | **Admin** | Add and remove non-owner members, manage workspace resources and settings. Cannot manage billing or delete the workspace. | | **Member** | View workspace resources and use the platform. Cannot add or remove members or change settings. | ## Invite a member [#invite-a-member] Go to **Settings** in the left sidebar of the AskUI Hub. Open the **Members** section. Click **Invite Workspace Member**. Enter the invitee's email address, select their role, and send the invitation. The invitee receives an email with an invitation link. Invitations expire after **7 days** if not accepted. ## Accept an invitation [#accept-an-invitation] When you receive a workspace invitation: Click the link in the invitation email. You are taken to the **Invitations** page in the Hub, which shows all your pending invitations with their workspace, assigned role, and expiry date. Click **Accept** to join the workspace, or **Decline** to reject it. ## Remove a member [#remove-a-member] Go to **Settings** in the Hub and open the **Members** section. Find the member in the list and click the remove (trash) icon next to their name. Confirm the removal when prompted. Once a member joins, their role is fixed. If you need to change it, remove them and invite them again with the correct role. # Usage dashboard (/docs/account-billing/usage-dashboard) The usage dashboard in the AskUI Hub gives you a live view of how your workspace is consuming its plan allowance. Find it under **Billing** in the Hub. ## Key metrics [#key-metrics] At the top of the dashboard you will see three summary cards: | Metric | What it shows | | ----------------------- | ------------------------------------------------------------- | | **Total Events** | Total executions in the selected date range | | **Unique Users** | Number of distinct users or access tokens that triggered runs | | **Avg. Events per Day** | Daily average over the selected period | Below the summary cards you will also see your subscription limit and the current renewal date. ## Filtering by date range [#filtering-by-date-range] Use the date picker in the top-right corner of the dashboard to select a custom date range. This lets you compare usage across billing periods or zoom in on a particular sprint or release cycle. ## Usage over time chart [#usage-over-time-chart] The chart shows execution volume per user per day. Each user (or CI access token) is represented by a distinct color. Use the checkboxes below the chart to show or hide individual users, select **All** or **None** to toggle quickly. This view is useful for: * Identifying peak activity periods * Seeing which users or CI tokens are consuming the most usage * Spotting unexpected spikes that might indicate a misconfigured pipeline ## Usage by access token [#usage-by-access-token] Runs triggered from CI via an access token appear in the chart attributed to that token. If you have multiple CI pipelines, give each pipeline its own access token (see [Workspaces and access tokens](/docs/account-billing/workspaces)) so you can distinguish their usage in the dashboard. # Workspaces (/docs/account-billing/workspaces) A **workspace** is the top-level container for your AskUI usage. It owns: * **Members**: the people with access, each with a privilege level. * **Access tokens**: credentials that let AskUI Desktop and the CLI act on behalf of the workspace. * **Usage & billing**: runs are metered against the workspace's plan (see [Plans & billing](/docs/account-billing/billing)). You manage workspaces in the **AskUI Hub**. ## Members & invites [#members--invites] Invite teammates from the Hub; each member belongs to the workspace with a privilege level that governs what they can do. Pending invites appear until accepted. ## Access tokens [#access-tokens] Access tokens authenticate non-interactive clients, most importantly the **CLI in CI**, where there's no browser to log in with. In the Hub, open **Tokens** and create a new token. Give it a **name** (e.g. `ci-smoke-runner`) and an **expiry**. Tokens can be long-lived or time-boxed, prefer an expiry for CI. **Copy the token value immediately**: only its name and a hash are stored, so the raw value is shown once and can't be retrieved later. Provide it to the CLI (e.g. via an environment variable in your pipeline), see [Running from the CLI](/docs/running-tests/cli). Treat access tokens like passwords. Store them in your CI secret store, never in a Project's files. Rotate by creating a new token and deleting the old one. # AgentOS Overview (/docs/agentos) AgentOS is the runtime layer that gives AI agents direct control over a machine's operating system, keyboard, mouse, screen, and system-level functions. It sits between the agent and the OS, handling the low-level interactions so agents can focus on tasks. **Designed for everyone, not just developers.** AgentOS is built so that non-technical users can install it and get it running without writing code or configuring system internals. The UI installer guides you through setup, and sensible defaults mean you don't need to touch configuration files to start. **Platform independent.** AgentOS runs on Windows, macOS, and Linux. In [Companion Mode](/docs/agentos/understanding/control-modes), it can also control Android devices, iOS Simulators (experimental), and any machine reachable through hardware interfaces, regardless of what OS the target runs. ## How it works [#how-it-works] AgentOS operates in two **control modes**: * **Host Mode**: AgentOS runs directly on the target machine as software. It controls the desktop via OS-level APIs with full access to screenshots, input, windows, and processes. * **Companion Mode**: AgentOS runs on an external device (e.g. Raspberry Pi) and controls the target through hardware interfaces (USB, Bluetooth, HDMI capture). No software installation on the target required. Both modes expose the same **capabilities**, the building blocks for screen reading, input simulation, and window management. ## Why AgentOS? [#why-agentos] Building a Computer Use Agent proof-of-concept is straightforward. Getting it to **production** is a different story. The gap between "works on my machine" and "runs reliably at scale" is where most teams get stuck, especially in CI/CD, where VMs start at the logon screen, automation needs an interactive session, and OS security blocks input injection from non-interactive processes. AgentOS solves session management, login automation, and privilege escalation so the agent can do its work. ## What's next? [#whats-next] # Release Notes (/docs/agentos/release-notes) ## Versioning [#versioning] AgentOS follows [CalVer](https://calver.org/) (Calendar Versioning) with the format **`YY.MM.PATCH`**: * **YY**: two-digit year (e.g. `26` for 2026) * **MM**: month (e.g. `2` for February) * **PATCH**: incremental patch number within that month Example: **26.2.2** = 2026, February, patch 2. **AgentOS uses the same version as the installer and the `askui-agent-os` pip package.** If you install the service with version **26.2.2**, the included AgentOS is also **26.2.2**. ## Releases [#releases] For a full list of versions and changes, see the [release history on PyPI](https://pypi.org/project/askui-agent-os/#history). # Agent behavior (/docs/best-practices/agent-behavior) The system prompt is assembled at run start from the project's files: the device profile's prompt, `tests/ui.md`, `utils/format.md`, and each folder's `rules.md` and `ui.md`. It applies to every test in the project. When tests fail consistently, this is often the fix, which file holds what: [What goes where](/docs/best-practices/prompting-best-practices). ## Error discipline: built in [#error-discipline-built-in] The agent's identity and its always-on rules are built into the app, they are not a file you edit. The core is the error discipline: ```md title="built-in capabilities (excerpt)" ## Error Handling - You have a maximum of **2 attempts per step**. If a step does not succeed after 2 attempts, stop immediately. Do not try a third time. - Never try creative or alternative ways to accomplish a step that didn't work as written. ``` * **Two attempts, then `FAILED`**: no third try, no workarounds, no navigating back to retry. A green run means the steps actually passed, not that the agent improvised its way to "done". * **Infrastructure errors are different**: connection lost, session expired, RPC error → status `BROKEN`, a diagnosis hint in the report, and `exception_tool` aborts the whole run (nothing can pass on broken infrastructure). The triage this enables: [Analyzing failures](/docs/best-practices/analyzing-failures). When a suite genuinely needs different behaviour, write a [rule](#rules-targeted-patches-that-win): rules land at the end of the system prompt and take precedence over the built-in instructions. ## Device prompt: only what the agent can't see [#device-prompt-only-what-the-agent-cant-see] Each device profile carries a **Prompt** field (Devices page → Edit) with quirks of **this machine** that the screen doesn't show. The agent sees the screen, OS and display basics rarely need describing. ```md title="Prompt field of the device profile" * Always execute on display 1 — display 2 shows the corporate dashboard. * The corporate lock screen appears after 5 minutes of inactivity. ``` The text lives with the profile in `devices.json`, so retargeting a project at a different machine means picking a different profile, no file editing. ## UI information: your biggest lever [#ui-information-your-biggest-lever] `tests/ui.md` is where the agent learns your application. The agent has no built-in knowledge of your app, everything it must recognise has to be written down. This is the file you invest the most in, and the first place to look when the agent [wanders](/docs/best-practices/analyzing-failures#the-agent-takes-a-lot-of-steps). ```md title="tests/ui.md" You are operating: Contoso Orders — order entry for the sales back office. ## Navigation The application has these primary areas: - Dashboard — overview & KPIs - Records — data entry & search - Settings — account & configuration ## State indicators Login state is shown top-right: a green dot means signed in, red means the session expired — sign in again. ## Dialogs & quirks Destructive actions open a centered confirmation dialog that must be confirmed or dismissed before continuing. The confirmation pop-up stays open until you click OK — clicking elsewhere does not close it. ``` What belongs here: * **Navigation**: the primary areas and where key actions live. * **State indicators**: what "signed in", "loading", "error" look like, so the agent reads the screen correctly. * **Non-standard interactions**: anything that would surprise a first-time user: drag-and-drop patterns, lazy loading, single-page navigation. * **Naming conventions**: what areas and views are called, so tests can reference them by name. * **What not to do**: destructive actions that are easy to trigger. A suite that exercises a different part of the system can add its own `ui.md` in its folder, it accumulates after the top-level file, closest to the test last. ## Report format: the report contract [#report-format-the-report-contract] `utils/format.md` defines the report the agent writes: the Markdown structure and the status vocabulary (`PASSED`, `FAILED`, `SKIPPED`, `WARN`, `BROKEN`). Edit it under **Extending → Report Format**. Keep the standard vocabulary, the runner parses the report's `**Status:**` line, and the [Runs and Dashboard pages](/docs/results) count results from it. Tailor the sections if your organisation needs different evidence; the shape is explained in [Run report](/docs/results/run-report#test-report). ## Rules: targeted patches that win [#rules-targeted-patches-that-win] A `rules.md` next to your tests patches the prompt, `tests/rules.md` for the whole project, a folder's `rules.md` for that suite only. Rules are appended at the very end of the system prompt behind an explicit note that they take precedence, so this is the place to correct built-in behaviour. A good rule reads like a bug fix: * **How the agent identifies the situation**: what it sees on screen. * **What to do**: the exact sequence. * **What not to do**: rule out the wrong approach explicitly. ```md title="tests/rules.md" ## Interaction - Never use keyboard shortcuts — operate the application through its menus, like our users do. ## Recoveries - If the scanner stops responding, run the restart_scanner tool and repeat the step. Do not mark the step FAILED on the first scanner timeout. ``` ## Style principles [#style-principles] * **Plain Markdown, one concern per `##` section**: that's what the scaffold ships and what keeps the files auditable. * **One language**: clear English throughout the prompt, tests, and all inputs. Mixed languages degrade performance. * **No contradictions**: two rules that conflict produce undefined behaviour, and a rule that contradicts `ui.md` makes the agent guess. Review across files. * **Overly specific is right**: if you feel you are being too detailed, you are doing it right. Only you know your UI. After a prompt change, run the affected folder and read the [run report](/docs/results/run-report), the **Agent Interpretation** per step shows whether the new wording landed the way you meant it. The run's conversation log also records the exact system prompt per phase, expand the **System prompt** section under the act header to see precisely what the agent got. # Analyzing failures (/docs/best-practices/analyzing-failures) The [test report](/docs/results/run-report) tells you **what** failed. This page is the loop for **why**, and where the fix belongs. ## Find the cause [#find-the-cause] 1. Start at the [summary report](/docs/results/run-report#summary-report): which cases didn't pass, and with which status? * **`FAILED`**: two possible truths, step 2 decides which: * **The test told the agent the wrong thing** → fix the test ([Fix it](#fix-it), below). * **The application misbehaved** → report it as a defect, with the test report and its screenshots attached as evidence. * **`BROKEN`**: infrastructure, not the application. The agent's report already carries its own diagnosis hint, which kind of problem it saw and what to check, so start there. The usual kinds: * **Device connection dropped**: AgentOS unreachable, emulator died, browser session gone → [Troubleshooting](/docs/troubleshooting/connection-sessions). * **AI model unreachable**: network, proxy, expired token → [Troubleshooting](/docs/troubleshooting/model-providers). * **Test machine not usable**: locked screen, display asleep → fix the machine state; recurring cases belong in [rules](/docs/writing-tests/step-constructs#beyond-steps). * **Peripheral failed**: scanner, printer → fix the hardware, or arm the agent with a [rule](/docs/writing-tests/setup-teardown-rules#rules) plus a [tool](/docs/extending/custom-tools): "if the scanner stops responding, use the `restart_scanner` tool and repeat the step." * **Admin rights missing**: UAC prompt, service restart, installing software → run the affected action outside the test, or enable **Allow control of administrative applications** in the [AgentOS service installation](/docs/agentos/installation/service). * **Clicks and typing don't arrive**: the run looks alive, screenshots work, but nothing happens. Either an admin-rights issue (an elevated window swallows input): start the controller (AgentOS) with admin rights, or non-standard behavior of your device: [contact AskUI](/docs/support/get-help). * **A referenced tool is missing**: the test names a tool that isn't in the run's toolbox → enable it in the [Tool Store](/docs/extending/tools), or check `utils/custom_tools/` and the [MCP configuration](/docs/extending/mcp). * **`WARN`**: passed with a caveat, read the report's **Issues** section, then decide: * **Standard behavior of your application** (a known pop-up, a slow first load)? Make it expected, a [rule](/docs/writing-tests/setup-teardown-rules#rules) or an [optional step](/docs/writing-tests/step-constructs#optional), and the warning disappears from future runs. * **A genuine anomaly**? Keep an eye on it across the next runs, and if it persists or worsens, report it as a defect, with the reports as evidence. * **`SKIPPED`**: an entry criterion wasn't met, or an [optional step](/docs/writing-tests/step-constructs#optional) didn't apply. Check the **Preconditions** section. 2. Open the failing case's [test report](/docs/results/run-report) and read the failed step: * **Agent Interpretation**: did the agent understand the step the way you meant it? If not, the defect is in the test. * **Expected vs. Actual**: plus the step screenshot, if the expectation is right and the application really did something else, you've found a product defect. 3. Still unclear? Switch from the test report to the [conversation log](/docs/results#conversation-log), it shows what the agent actually did, in detail: every decision, tool call, and screenshot on the way to the failure. 4. Before closing: scan **Issues**, also on tests that passed. The agent notes anomalies there (slow responses, odd dialogs) that are often the early warning for the next run's failure. ## Fix it [#fix-it] Match what you saw to the pattern, each shows the file to change, before and after. ### The agent misclicks [#the-agent-misclicks] The [locator](/docs/writing-tests/step-constructs#locators) is ambiguous on this screen. Escalate in this order: 1. **Quote the exact label** the UI shows, `"Sign-Up"` beats "the login button". 2. **Add relations**: position and neighbors ([locator kinds](/docs/writing-tests/step-constructs#locators)).
```md title="❌ tests/login_test.md — before" 2. Please press the login button. ```
```md title="✅ tests/login_test.md — after" 2. Press the "Sign-Up" button, top right, next to "Log in". ```
3. **Still misclicking?** Tell the agent to use the **Screen zoom** [tool](/docs/extending/tools) for small targets, and add a verification step so the click's effect is checked:
```md title="❌ tests/signup_test.md — before" 4. Accept the terms. ```
```md title="✅ tests/signup_test.md — after" 4. Use the zoom tool to click the "Accept AGB" checkbox. 5. Check afterwards that the checkbox is checked. ```
### The agent takes a lot of steps [#the-agent-takes-a-lot-of-steps] **How you see it:** the [conversation log](/docs/results#conversation-log)'s TEST header shows the tool-call count per case, compare it with earlier runs of the same case (a case that normally takes \~13 calls suddenly needs 45). Watching [live](/docs/running-tests#watch-it-live), wandering looks like repeated screenshots and back-and-forth navigation; the token numbers per step add up to the cost of it. **Why:** it is unsure how your application behaves, teach it in [UI information](/docs/writing-tests/agents-and-prompts#ui-information) and make vague goals precise.
```md title="❌ tests/ui.md — before" ## Dialogs & quirks ```
```md title="✅ tests/ui.md — after" ## Dialogs & quirks The confirmation pop-up stays open until you click **OK** — clicking elsewhere does not close it. ```
### FAILED, but the behavior is actually correct [#failed-but-the-behavior-is-actually-correct] The agent judged against the wrong picture: your expected result is under-specified, state precisely what it looks like.
```md title="❌ tests/login_test.md — before" 2. Click Login — the user is logged in. ```
```md title="✅ tests/login_test.md — after" 2. Click Login — the start screen shows the green signed-in dot at the top right. ```
### PASSED, but it actually failed [#passed-but-it-actually-failed] The success criterion is too loose to catch the defect, add an explicit [verification step](/docs/writing-tests/step-constructs#verifications).
```md title="❌ tests/create_record.md — before" 3. Click Save. ```
```md title="✅ tests/create_record.md — after" 3. Click Save. 4. Verify the new record appears in the list with status "Active". ```
### The agent operates the UI wrong [#the-agent-operates-the-ui-wrong] Shortcuts, keyboard instead of the numpad, it doesn't know your house style. Teach it in [UI information](/docs/writing-tests/agents-and-prompts#ui-information) or, per suite, in [rules](/docs/writing-tests/setup-teardown-rules#rules): ```md title="➕ tests/rules.md — add" ## Interaction - Never use keyboard shortcuts — operate the application through its menus, like our users do. - Enter numbers via the on-screen numpad with mouse clicks. ``` ### Random real-world disruptions [#random-real-world-disruptions] The app hangs, the printer is empty, the environment, not the test. Give the agent the manual tester's [recoveries](/docs/writing-tests/step-constructs#beyond-steps): ```md title="➕ tests/rules.md — add" ## Recoveries - If the application hangs, restart it and repeat the current step once. - If the printer reports empty, ignore the print result and continue. ``` ### Odd path, but the right result [#odd-path-but-the-right-result] That's [non-determinism by design](/docs/concepts/test-automation-harness#why-execution-differs), change nothing; judge the result, not the path. ### Not the agent's behavior? [#not-the-agents-behavior] * **Wrong starting state** → the suite's [setup](/docs/writing-tests/setup-teardown-rules). * **Credentials failed** → [secrets](/docs/extending/secrets), values are per machine; a colleague's fresh clone starts without them. * **The device didn't come up** → [Devices](/docs/devices) and [Troubleshooting](/docs/troubleshooting/connection-sessions). * **The application genuinely misbehaved** → your bug tracker. The test report with its screenshots **is** the incident evidence, attach it. # What goes where (/docs/best-practices/prompting-best-practices) AskUI Desktop separates three concerns that are easy to mix up: * **Who the agent is**: the system prompt: built-in capabilities, the device prompt, app knowledge, report format, your rules. * **What to do on this run**: test files (`tests/`): the steps for each scenario. * **Shared lifecycle**: `setup.md`, `teardown.md`, `rules.md`: what runs around groups of tests. Getting this right is what makes a project maintainable: when a run misbehaves, you know which file to open. | Content | Where | | ---------------------------------------------------- | --------------------------------------------------------------------------- | | Agent identity and error discipline | Built into the app, not editable | | Facts about the test machine the screen doesn't show | The device profile's **Prompt** field (`devices.json`) | | App knowledge: navigation, state indicators, quirks | `tests/ui.md` | | Report structure and status vocabulary | `utils/format.md` (**Extending → Report Format**) | | Standing corrections that override everything | `tests/rules.md` | | Behaviour for one suite only | `/rules.md` (and `/ui.md` for suite-specific app knowledge) | | Shared preconditions | `/setup.md` | | Shared cleanup | `/teardown.md` | | Reusable step sequences | `procedures/.md` | | One test scenario | `tests/.md` | ## The system prompt [#the-system-prompt] Assembled at run start, applies to every test. The parts have different lifecycles, keeping them separate means a change to one never risks the others: * **Capabilities**: built in and constant; correct them with rules, not by editing. * **Device prompt**: changes per machine; lives on the device profile, so picking a different profile retargets the run. * **`tests/ui.md`**: grows as you learn the app; your biggest lever. * **`utils/format.md`**: typically shared org-wide. * **`tests/rules.md`**: appended last, takes precedence on conflicts. What to write in each: [Agent behavior](/docs/best-practices/agent-behavior). ## Test files (`tests/`) [#test-files-tests] A test file describes **what to do in this specific scenario**, nothing else: * **Belongs in a test file**: the scenario's steps with expected results, credentials by name, procedure calls. * **Doesn't belong**: app knowledge (→ `tests/ui.md`), device facts (→ the device profile's Prompt), steps every test needs (→ setup/teardown), sequences shared between tests (→ procedures). How to write the steps themselves: [Writing good tests](/docs/best-practices/writing-good-tests). ## Setup, teardown, and rules [#setup-teardown-and-rules] Three conventional files per test folder, picked up automatically, setup cascades outer-first, teardown unwinds in reverse ([details](/docs/writing-tests/setup-teardown-rules)). The one to remember: when a suite needs different behaviour, add a `rules.md` in its folder, project-wide corrections go to `tests/rules.md`, which changes every test in the project. ## Procedures (`procedures/`) [#procedures-procedures] A sequence used by more than one test or setup file, called explicitly from a step, fixed in one place ([details](/docs/writing-tests/procedures)). Setup/teardown run automatically for a folder; a procedure only runs where a step calls it. # What the agent may do (/docs/best-practices/security) An agent run can do whatever the tools it was given allow, with the rights of the session it runs in. Both are yours to set. The rule of thumb: **grant the least a test needs, and make every grant visible in the project**. Where each grant lives, so a reviewer can see it: [Enterprise fit](/docs/concepts/enterprise-fit#what-the-agent-may-do-on-a-machine). ## The session decides the floor [#the-session-decides-the-floor] The agent acts as the logged-in user, so that account's rights are the ceiling of everything it can do, on the operating system and in the application under test. Create accounts for testing on both levels: **On the operating system.** One dedicated local account per test machine, not a personal and not an administrative one: * **Standard user, no administrator group.** If the account can install software or write outside its profile, so can a run. * **No domain-wide rights.** A local account, or a domain account whose group memberships are scoped to the test machines, never one that also carries access to production systems, file shares or mailboxes. * **Own profile, nothing personal in it.** The agent sees whatever the desktop shows: no private mail client, no signed-in browser profile with saved passwords, no VPN client that grants more reach than the test needs. * **Auto sign-in without a personal password.** A shared lab machine needs an unlocked session; give it a session that costs you nothing if someone reads the screen over the tester's shoulder. * **Elevation off unless a suite needs it.** Driving elevated windows requires enabling ["Allow control of administrative applications"](/docs/agentos/installation/service). If one suite needs it, give that suite its own machine rather than switching it on lab-wide. **In the application under test.** A test user per suite, provisioned like any other user of your product: * **The role the scenario needs, nothing above it.** A checkout test does not need an admin role; if a test needs admin, that is a separate suite with its own account. * **Read-only where the test only verifies.** The same applies to the [SQL tool's](/docs/extending/tools#sql-database) database user. * **Never a production account, and never a real person's.** Test accounts are disposable, personal accounts are not, and a failed run leaves screenshots of whatever that account can see. **Around both.** Test machines should reach the system under test and nothing else, and the [AgentOS port](/docs/concepts/enterprise-fit#what-talks-to-what) should be restricted to the machines allowed to start runs. ## Allowlist the domains, nothing more [#allowlist-the-domains-nothing-more] Two different machines need two different allowlists, and the shorter one is the test machine's: * **The machine that starts runs** (a tester's PC or a CI runner) needs outbound HTTPS to AskUI for sign-in, workspace and licence checks, and to the model endpoint. The exact domains are in [Network requirements](/docs/reference/network-requirements); allowlist those, not `*`. * **Test machines** need the application under test and nothing else. They do not talk to AskUI or to the model provider, the machine driving the run does that. Deny the rest of their outbound traffic and you have removed the route that a badly written custom tool would need to leak anything. * **With your own model endpoint**, the model domain moves inside your network, and with [on-premise inference](/docs/concepts/enterprise-fit#what-leaves-the-network-and-how-to-stop-it) it disappears from the allowlist entirely. * **Runtime downloads are separate entries**: browser bundles, the Android SDK toolchain, and NuGet feeds for [custom tools](/docs/extending/custom-tools) resolve through your own `NuGet.config`, so an internal mirror keeps them off the public internet. Pre-provision them and the machines stay closed. * **Allowlist inside the app as well.** Network rules stop a host being reachable; the [HTTP client tool's](/docs/extending/tools#http-client) **Allowed hosts** stops a step from *asking*, and it lives in `utils/tools.json` where a reviewer sees it. Same for [MCP servers](/docs/extending/mcp): pin the endpoint, prefer internal servers. ## The toolbox decides the ceiling [#the-toolbox-decides-the-ceiling] Device tools (screenshot, click, type) always exist. Everything with reach beyond the UI is off until someone enables it, keep it that way unless a test needs it, and scope it when you do: | Tool | Scope it with | | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | | [Shell script](/docs/extending/tools#shell-script) | One fixed script path per tool, so the agent runs *that* script, not arbitrary commands | | [SQL database](/docs/extending/tools#sql-database) | Named allowlisted statements; leave **Allow raw SQL** off, and connect with a read-only user where the test only verifies | | [HTTP client](/docs/extending/tools#http-client) | **Allowed hosts**, so a step can't call an arbitrary endpoint | | [File exists](/docs/extending/tools#file-exists), [List](/docs/extending/tools#list-remote-files) / [Read remote file](/docs/extending/tools#read-remote-file) | A **base directory**, plus allowed extensions for listings | Two grants deserve a real review, because they are code and third-party reach: * **[Custom tools](/docs/extending/custom-tools)** run with the rights of the run and can do anything C# can. Developer-owned, reviewed like production code, and never a thin wrapper around "run whatever the agent passes". * **[MCP servers](/docs/extending/mcp)** hand the agent someone else's tools. Prefer internal servers, pin the endpoint, and know what each server exposes. ## Credentials [#credentials] * **Only as [named secrets](/docs/extending/secrets).** Steps reference the name; the value is substituted at execution time and redacted from reports and logs. A credential in a test file is a credential in your Git history. * **Test accounts, not real ones.** Minimal rights in the system under test, and never a production account reused for testing. * **Rotate them like any other credential**, and remember values are per machine: a colleague's fresh clone starts without them, which is the point. ## Test data and screenshots [#test-data-and-screenshots] * Every step's screenshot becomes [evidence](/docs/results/run-report) on disk, and the same screenshot is what the model sees. If your test data contains personal data, both facts matter. * Prefer **synthetic or anonymised data**. Where a screen unavoidably shows real data, choose the model placement to match: [your own tenancy or on-premise inference](/docs/concepts/enterprise-fit#what-leaves-the-network-and-how-to-stop-it). ### On a tester's own machine [#on-a-testers-own-machine] A run on someone's working PC captures whatever the display shows, so Outlook, Teams or an open browser end up in the evidence and in the model request. Two habits prevent that: * **Scope capture to the window under test.** Instead of driving the whole display, have the agent pick the application's window: it lists the open windows and then attaches that one as its capture surface, so every screenshot afterwards contains only that window. Put it in the folder's [rules](/docs/writing-tests/setup-teardown-rules#rules) so it applies to every test: ```md title="tests/rules.md" ## Interaction - Before the first step, list the open windows and select the window of the application under test, so screenshots capture only that window. ``` Where a suite runs on a dedicated machine, a [remote computer profile](/docs/devices/remote-computer) is the cleaner answer, nothing private is on that desktop in the first place. * **Delete run folders you no longer need.** Each run keeps full-resolution screenshots of every step under `agent_workspace//`. Keep the runs you still reason about, delete the rest; they are gitignored, so they only ever existed on that machine. Archive deliberately in [CI](/docs/guides/askui-in-ci) instead of hoarding locally. Test evidence is yours either way: it stays in the project folder under your own retention rules. ## Make grants reviewable [#make-grants-reviewable] Everything above is a file in the project, so a pull request shows it: * `utils/tools.json`, which tools are enabled, with their scoping values * `utils/mcp.json`, which MCP servers a run connects to * `utils/custom_tools/*.cs`, the code the agent can call * `devices.json`, which machines a run may drive Review those diffs the way you review dependency changes. A test that suddenly needs the shell tool is a design question, not a checkbox. ## Checklist [#checklist] * [ ] Outbound allowlist per machine role: run starters reach AskUI and the model endpoint, test machines reach only the system under test. * [ ] Dedicated OS account per test machine: standard user, no domain-wide rights, nothing personal in the profile, elevation off unless required. * [ ] Application test users carry only the role their scenario needs, and database users are read-only where the test only verifies. * [ ] Only the tools a test needs are enabled, each scoped (path, statements, hosts, base directory). * [ ] Raw SQL off. * [ ] No credentials in test files, named secrets only, test accounts only. * [ ] Synthetic or anonymised test data, or a model placement that matches the data's sensitivity. * [ ] Runs on a personal machine scope capture to the application's window, and old `agent_workspace/` runs get deleted. * [ ] Custom tools and MCP servers reviewed like code. * [ ] `tools.json`, `mcp.json`, `devices.json` changes reviewed in pull requests. # Writing good tests (/docs/best-practices/writing-good-tests) A test file is plain Markdown: preconditions, numbered steps, postconditions. The agent reads it, acts on the real screen, and writes a [report](/docs/results/run-report). Whether the run is reliable depends almost entirely on how clearly the steps are written. The bar to clear: **someone who has never seen the app should be able to execute the test from the file alone.** ## One goal per test file [#one-goal-per-test-file] One coherent scenario with one verifiable outcome per file. When a two-goal test fails, you can't tell which goal failed.
```md title="❌ tests/registration_and_login.md" # Registration and Login ## Steps 1. Register a new account, then log in with the new credentials. ```
```md title="✅ tests/registration_test.md" # New User Registration ## Steps 1. Open the registration page. 2. Fill the form with the test data. 3. Submit — the confirmation page "Welcome aboard" is shown. ```
## Steps the agent can act on [#steps-the-agent-can-act-on] The agent identifies elements from screenshots. Vague descriptions force it to guess, the [locator vocabulary](/docs/writing-tests/step-constructs#locators) makes each step unambiguous. **Quote the exact label and anchor the position:**
```md title="❌ vague" 3. Click the button. ```
```md title="✅ specific" 3. Click "Save" — bottom right of the dialog, below the comment field. ```
**Name the feature that makes an element unique:**
```md title="❌ vague" 5. Click the icon. ```
```md title="✅ specific" 5. Click the red trash-can icon in the row labelled "Draft report". ```
**Small targets: use the Screen zoom tool**: enable it in the [Tool Store](/docs/extending/tools#screen-zoom) first, then say so in the step, with a verification after the click: ```md 4. Use the zoom tool to click the "Accept AGB" checkbox. 5. Check afterwards that the checkbox is checked. ``` **Every step states its expected result.** A step without a verification always passes:
```md title="❌ always passes" 6. Click Submit. ```
```md title="✅ verifiable" 6. Click Submit — the banner "Changes saved" appears at the top of the page. ```
Where the outcome isn't visible in the same place you acted, make the check its own [verification step](/docs/writing-tests/step-constructs#verifications), the agent reports it separately, so you see which half broke: ```md 7. Click "Save". 8. Verify the order appears in "Records" with status "New". 9. Verify the response of `GET /api/orders` contains the new order number. ``` This is also the fix when a test reports `PASSED` although the feature is broken: the success criterion was too loose to catch it ([more](/docs/best-practices/analyzing-failures#passed-but-it-actually-failed)). ## Preconditions: is the test applicable? [#preconditions-is-the-test-applicable] Preconditions are the test's **entry criteria**: the agent checks them first, and a test whose criteria aren't met is reported `SKIPPED`, not `FAILED`, it never ran, so it can't have failed. That distinction keeps your pass rate honest. ```md title="tests/cancel_order_test.md" ## Preconditions - Signed in as a user with the "Sales" role - At least one order with status "New" exists ## Steps 1. Open "Records" and select the newest order with status "New". 2. Click "Cancel order" and confirm — the status changes to "Cancelled". ## Postconditions - Test passes if the order is listed as "Cancelled" and no longer editable ``` * **Preconditions**: what must be true *before* the steps make sense. Name state you don't create in the test itself: a role, existing data, a starting screen. If setup already establishes it, one line ("Signed in, start screen visible") is enough. * **Postconditions**: the overall pass criterion, checked at the end. Write it as the sentence that decides the test: *"Test passes if …"*. Preconditions the agent can't decide from the screen belong in [setup](/docs/writing-tests/setup-teardown-rules) instead, seeding the order, granting the role, so the test is applicable by construction. The opposite of an entry criterion is an [optional step](/docs/writing-tests/step-constructs#optional): a step that sometimes doesn't apply *within* an otherwise valid test. ## Never embed credentials [#never-embed-credentials] Test files are version-controlled; credentials must not be. Reference them by name, the values live encrypted in [Extending → Secrets](/docs/extending/secrets) and substitute at execution time, hidden from the model and redacted from reports:
```md title="❌ never" 1. Sign in as "admin@example.com" with password "hunter2". ```
```md title="✅ by name" 1. Sign in with the QA credentials, the secrets QA_USERNAME and QA_PASSWORD. ```
## Repeated sequences → procedures [#repeated-sequences--procedures] The same multi-step sequence in more than one test, signing in, reaching a starting state, belongs in a [procedure](/docs/writing-tests/procedures). A changed flow (new login page, renamed field) is then fixed in one place: ```md title="tests/checkout_test.md" 1. Run procedure `login_to_ui[username, password]` with the QA credentials. 2. Add the first product to the cart. ``` ## Shared state → setup and teardown [#shared-state--setup-and-teardown] Preconditions every test in a folder needs, logging in, seeding data, belong in the folder's `setup.md`, cleanup in `teardown.md` ([how they cascade](/docs/writing-tests/setup-teardown-rules)). Keep a precondition inline only when just some tests need it. Unlike procedures, setup and teardown run automatically, nothing calls them. Three order tests that each opened the app and signed in:
```md title="❌ tests/create_order_test.md" ## Steps 1. Open the application and wait until it is fully visible. 2. Sign in with the QA credentials. 3. Open "Records" and create an order for customer "Contoso", it appears with status "New". 4. Sign out. ```
```md title="✅ tests/create_order_test.md" ## Preconditions - Signed in, start screen visible ## Steps 1. Open "Records" and create an order for customer "Contoso", it appears with status "New". ```
The shared steps move up one level, into the folder every order test lives in: ```md title="tests/setup.md" ## Setup Steps 1. Open the application under test and wait until it is fully visible. 2. Sign in using the `login_to_ui` procedure with the QA credentials, the secrets named `QA_USERNAME` and `QA_PASSWORD`. 3. Verify the start screen has loaded before any test starts. ``` ```md title="tests/teardown.md" ## Teardown Steps 1. Delete the orders created during the test. 2. Sign out and close the application under test. ``` Each test now reads as its own scenario, the sign-in flow is defined once, and a failing setup blocks the tests below it instead of failing three times in a row. ## When to reach for a tool [#when-to-reach-for-a-tool] Most steps are UI interaction. A [tool](/docs/extending/tools) is right when the screen isn't the best source of truth, enable it in the Tool Store first, then name it in the step ([syntax](/docs/writing-tests/step-constructs#tool-invocations)): * **Verify what the screen can't show**: the record in the database, the API response, the exported file. The UI can claim success while the data is wrong. ```md 8. Verify the "open_orders" SQL statement lists the order with status "New". ``` * **Get data right instead of letting the agent guess**: dates, conversions, generated values. ```md 3. Enter the date three days from today into "Delivery date". ``` * **Prepare and clean state**: in [setup and teardown](/docs/writing-tests/setup-teardown-rules), seeding via SQL or an API call is faster and more reliable than clicking the same forms before every test. * **See what the screen hides**: the [zoom tool](/docs/extending/tools#screen-zoom) for small targets, the QR scanner for encoded content, a remote file for the application's log. * **Recover from infrastructure**: a [rule](/docs/writing-tests/setup-teardown-rules#rules) plus a tool ("if the scanner stops responding, run the `restart_scanner` tool and repeat the step") turns a `BROKEN` run into a passing one. **Don't route around the UI under test.** If the user journey is what you're testing, click it, a tool that performs the user's action instead makes the test pass without testing anything. Create an order through the UI, then *verify* it with SQL. ## Non-deterministic execution [#non-deterministic-execution] Two runs of the same case can take different paths, by design ([why](/docs/concepts/test-automation-harness#why-execution-differs)). The same step, two runs, both `PASSED`, here the **environment** differed:
```md title="Run 1 — 11 tool calls" 3. Open "Records" and create an order for "Contoso". Agent Interpretation: clicked "Records" in the left sidebar, then "New order". ``` ```md title="Run 2 — 14 tool calls" 3. Open "Records" and create an order for "Contoso". Agent Interpretation: a survey pop-up covered the sidebar, dismissed it, then clicked "Records" and "New order". ```
It also happens with an identical environment, when your UI offers **two equivalent ways** to do the same thing:
```md title="Run 1" 5. Search for order "4711". Agent Interpretation: clicked the magnifier icon, which opened the extended search panel, entered "4711" and confirmed. ``` ```md title="Run 2" 5. Search for order "4711". Agent Interpretation: typed "4711" into the search field in the toolbar and pressed Enter. ```
None of these runs is wrong: the order was found, the order exists, which is what the steps demanded. For a tester this means: * **Judge the result, not the path**: the report's expected vs. actual per step is the contract; the exact clicks are the execution log, not the specification. * **Precise expected results = stable outcomes**: the agent has freedom in *how*; your steps define *what must be true afterwards*. The tighter the expected result, the less room for a wrong interpretation:
```md title="❌ passes on any screen" 4. Save the order — it worked. ```
```md title="✅ one true outcome" 4. Save the order — it appears in "Records" with status "New" and today's date. ```
* **Rules constrain the freedom**, [rules.md](/docs/writing-tests/setup-teardown-rules#rules) removes paths you never want taken: ```md title="➕ tests/rules.md" ## Interaction - Never change application settings to make a step work. - Search from the toolbar field — do not use the extended search panel behind the magnifier icon. ## Error handling - If an error dialog appears, document it and mark the step FAILED, never dismiss it and continue. ``` * **Watch a run when in doubt**: the [live conversation log](/docs/running-tests#watch-it-live) shows the path the agent chose, and why. ## Checklist [#checklist] Before committing test files: * [ ] One goal per file, with a verifiable outcome. * [ ] Labels quoted, positions anchored, no bare "click the button". * [ ] Every acting step states what must be true afterwards. * [ ] Outcomes that aren't visible where you acted have their own `Verify` step. * [ ] Preconditions name the entry criteria; postconditions state the pass criterion. * [ ] No credentials in any file, only named references. * [ ] Repeated sequences in `procedures/`, not copy-pasted. * [ ] Shared preconditions in `setup.md`, shared cleanup in `teardown.md`. # Computer Use Agent (/docs/concepts/computer-use-agent) AskUI executes tests with a **Computer Use Agent (CUA)**: an AI agent that operates real software through the same channel a human tester does: the screen, the mouse, the keyboard. There is no selector, no recording, no object map. You write the test as numbered steps in a Markdown file, in the same wording you would hand a colleague, and the agent carries it out. ## The loop [#the-loop] For every step of your test the agent repeats this cycle, often several times, until the step's expected result is reached or its attempts run out: 1. **Screenshot**: read the screen of the device. 2. **Decide**: interpret your step against what is actually visible, like a tester following instructions. 3. **Act**: through a [tool](/docs/extending/tools): click, type, scroll, or anything else the toolbox allows. 4. **Verify**: compare what happened against the step's expected result. If it matches, the step gets its status and the agent moves on; if not, it loops again (within its [attempt limit](/docs/best-practices/agent-behavior#error-discipline-built-in)). Either way it lands in the [report](/docs/results/run-report). ## One cycle in the conversation log [#one-cycle-in-the-conversation-log] The same cycle as the app records it, [the log](/docs/results#conversation-log) is where you watch it happen:
2 TEST · tests/create_order_test.md PASS 13 tool calls
Step 2 from the test file: Click "New order". The empty order form opens.
Screenshot Take screenshot Contoso Orders, Records Export New order
Decide The Records list is visible. "New order" is top right, next to "Export". I will click it.
Act Click 1180, 96
Verify The empty order form is open. The expected result of step 2 is met.
Step 4: Verify order "4711" exists in the backend with status "New". Same cycle, but the truth is not on the screen.
Decide The order was created in the UI. The step asks me to confirm it in the backend, so I will use the HTTP client.
Act HTTP client GET api.example.com/orders/4711 → 200 OK {'{ "id": "4711", "customer": "Contoso", "status": "New" }'}
Verify The API returns the order with status "New". The UI and the backend agree.
The stage labels on the left are this page's four stages; the app itself shows the narration, the screenshots inline, and the tool-call chips with their results (plus tokens and latency per step). The cycle is the same whether the agent acts on the screen or calls a [tool](/docs/extending/tools) like the HTTP client. Only the "act" differs. Every element of the log: [Runs](/docs/results#conversation-log). ## Why not a script? [#why-not-a-script] A script is written for a finite set of application behaviors: one path through one version of one application, in one environment. Anything outside that set fails it: a renamed button, a machine that has drifted since the test was written, a survey pop-up nobody planned for. The agent decides from the live screen instead, so it also handles what nobody wrote down: another application, another environment, a state that has decayed. A random pop-up costs it a click, not the run. That same freedom is why [two runs can take different paths](/docs/concepts/test-automation-harness#why-execution-differs). ## What a CUA agent is made of [#what-a-cua-agent-is-made-of] What it is made of: two parts you choose, two we provide. These are not the [products you install](/docs/concepts/enterprise-fit#the-four-components), they are the pieces a run is assembled from: * **A CUA model**: the intelligence, and the part you pay per token for. It receives the screenshot and the step text and answers with the next action, so it must be **vision-capable**: a text-only model can't see the screen. Either you consume it through us (billed with your AskUI workspace) or you bring [your own provider](/docs/extending/model-providers#supported-models) and pay that vendor directly. Which model you pick drives both the run's cost and how reliably it reads your UI. * **Tools**: everything the agent *can* do, and the boundary of what a test can possibly do. We ship most of them: the device tools (screenshot, click, type) come with the device kind, and the [Tool Store](/docs/extending/tools) adds ready-made ones like SQL, HTTP or screen zoom. You extend from there where your product needs it, your own C# [custom tools](/docs/extending/custom-tools), or existing [MCP servers](/docs/extending/mcp), and you decide which of them a project actually gets. * **AskUI Desktop & AgentOS**: the infrastructure layer you don't have to build yourself. [AgentOS](/docs/agentos) gives the agent eyes and hands on a machine (Playwright covers browsers, adb covers Android), turning "click 1180, 96" into a real click on a real machine, across operating systems, remote machines, emulators and physical phones, with connection, sessions and screen capture already solved. AskUI Desktop is where you author tests, [connect devices](/docs/devices), start runs and read the results. * **The AskUI harness**: the test automation harness around the model: the plumbing a test framework normally gives you, built for an agent. This is the part we provide, and it decides how disciplined a run is ([in detail](/docs/concepts/test-automation-harness)): * **The loop**: screenshot, decide, act, verify, repeat, as above. * **Prompt assembly**: your [prompt files](/docs/best-practices/agent-behavior) plus the current test's steps, the folder's rules, and the names of available [secrets](/docs/extending/secrets), stitched into the instructions the model sees. * **The conversation**: the running transcript of screenshots, decisions and tool results. It is the agent's memory, re-sent on every turn, which makes it the run's evidence *and* its cost, the reason tools should [return little](/docs/extending/custom-tools#keep-results-small). * **Stop conditions**: two attempts per step and no creative retries, so a `PASSED` means the step actually passed; an infrastructure error ends the run as `BROKEN` instead of grinding on. * **The run lifecycle**: setup, the tests, teardown per folder, and the [report](/docs/results/run-report) written while it all happens ([details](/docs/concepts/test-automation-harness)). Next: how a whole run walks setup, tests and teardown ([Test automation harness](/docs/concepts/test-automation-harness)), how to write steps this loop executes reliably ([Writing good tests](/docs/best-practices/writing-good-tests)), and what it means to bring this into your environment ([Enterprise fit](/docs/concepts/enterprise-fit)). # Enterprise fit (/docs/concepts/enterprise-fit) Everything here answers one question: what does bringing AskUI into your environment actually mean? The short version, screenshots of your applications go to an AI model for the agent's decisions; everything else (testware, reports, secrets) stays on your machines. Straight to your questions: | If you are | Start at | | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **A software architect** | [The four components](#the-four-components), [What talks to what](#what-talks-to-what), [Concurrency and upgrades](#concurrency-and-upgrades) | | **IT security** | [What leaves the network](#what-leaves-the-network-and-how-to-stop-it), [What the agent may do on a machine](#what-the-agent-may-do-on-a-machine), [Telemetry](#telemetry-what-we-see), [Inbound ports](#what-talks-to-what), [hardening a run](/docs/best-practices/security) | | **Compliance** | [Data protection](#data-protection), [What is stored where](#what-is-stored-where), [What is downloaded at runtime](#what-is-downloaded-at-runtime) | | **The team running the lab** | [Running the lab machines](#running-the-lab-machines), [Infrastructure requirements](#infrastructure-requirements) | The full picture, in the order a review usually asks for it: ## Start simple: one computer [#start-simple-one-computer] The smallest setup is one machine: [AskUI Desktop](/docs/get-started/install-desktop) and the application under test side by side on the tester's PC, with the [project](/docs/projects), tests, prompts and reports, in a folder next to them. The only thing that leaves the machine is the inference traffic: the screenshot, the step text and the conversation of the current test: The **model provider** is the AI service that makes the agent's decisions: the AskUI hub by default, or one you bring yourself, the choice, and what it means for your data, is in [What leaves the network](#what-leaves-the-network-and-how-to-stop-it). Nothing to provision, no server, no CI: install, sign in, write a test, run it ([first run](/docs/get-started/first-run)). Most teams stay here for their first weeks. ## Expand to scale [#expand-to-scale] When tests should run without a tester present, the same [project](/docs/projects) moves outward in three steps, each one optional and independent. The [AskUI CLI](/docs/running-tests/cli) runs it headless, the same way Desktop does interactively: Every box is one real thing you provision, and every group is optional: VMs at your cloud provider, machines in your own lab, a rack of phones and [simulators](/docs/devices/ios-simulator). Browsers are the exception, they need no machine of their own: Playwright runs on whichever machine started the run. Desktop and the CI pipeline drive the same targets from the same project, so a test written on a tester's PC runs unchanged in the pipeline. * **Remote test machines**: the application under test moves off the tester's PC onto dedicated machines running [AgentOS](/docs/devices/remote-computer), so a run can't disturb anyone's desktop and several tests can run at once. * **The project in Git**: the same folder for everyone, reviewed like code ([versioning](/docs/projects#git-versioning--sync)). * **CI pipeline**: the [CLI](/docs/running-tests/cli) runs the same project headless on every merge or on a [schedule](/docs/running-tests/scheduling), against the same machines ([AskUI in CI](/docs/guides/askui-in-ci)). Who owns which part of that setup: [Sharing the project](/docs/concepts/team-setups). ## The four components [#the-four-components] A raw CUA can drive a screen. Turning that into test automation an enterprise runs every day, on its own machines, inside its own network, under its own governance, takes four things, and each one runs somewhere you control: | Component | Role | | ----------------- | ---------------------------------------------------------------------------------------------------------------------------- | | **AskUI Desktop** | Where you author, run, and review, [projects](/docs/projects), [devices](/docs/devices), [reports](/docs/results/run-report) | | **AskUI CLI** | The same runs, headless, [CI and scheduled execution](/docs/running-tests/cli) | | **AgentOS** | Gives the agent eyes and hands on a machine: screen, keyboard, mouse, [details](/docs/agentos) | | **AskUI Hub** | Workspace, members, tokens, billing, [account](/docs/account-billing/workspaces) | Where each one runs, what it talks to, and what it stores follows below; the enterprise questions, proxy, air-gapped operation, CI runners, are in [Infrastructure requirements](#infrastructure-requirements). ## What talks to what [#what-talks-to-what] | Connection | Protocol | Notes | | ---------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------- | | Desktop/CLI → AgentOS | gRPC, port 23000 (app-spawned) or 26000 (installed service) | Screen, keyboard, mouse of a [desktop machine](/docs/devices/remote-computer) | | Desktop/CLI → browser | Playwright, local | [Web profiles](/docs/devices/web-browser), no AgentOS involved | | Desktop/CLI → Android | adb, local/USB/wireless | [Emulators](/docs/devices/android-emulator) and [phones](/docs/devices/android-phone) | | Desktop/CLI → model provider | HTTPS | See below, the only place test content leaves your network | | Desktop → AskUI Hub | HTTPS | Sign-in, tokens, usage. Not involved in test execution itself | Read the first row as an **inbound port on the target machine**: AgentOS listens there, and Desktop or the CLI connects in. Nothing else in the picture listens; every other arrow is outbound from the machine that starts the run. Restrict the AgentOS port to the machines that are allowed to drive tests. Endpoints and firewall rules: [Network requirements](/docs/reference/network-requirements). ## What leaves the network (and how to stop it) [#what-leaves-the-network-and-how-to-stop-it] Each [loop iteration](/docs/concepts/computer-use-agent#the-loop) sends the current **screenshot, the step's text and the conversation so far** (earlier screenshots, decisions and tool results of this phase) to the model provider. That is the inference the agent's decisions are made of, and the only test content that travels at all. Where it travels is your choice: * **AskUI hub** (default), inference runs through us, billed with your workspace. * **Your own cloud tenancy**: with [BYOM](/docs/extending/model-providers) the traffic goes to an endpoint you own instead, so it stays inside contracts and a cloud account you already hold. This is what most IT-security reviews approve. Your Anthropic account, [Azure AI Foundry](https://learn.microsoft.com/azure/ai-foundry/) and gateways behind [Microsoft Entra](/docs/extending/model-providers) work out of the box. **AWS Bedrock**, **GCP Vertex AI** and internal gateways with their own authentication scheme need that scheme implemented, so if your models sit behind one, [talk to us](/docs/support/get-help), we support you in getting it wired up. * **On-premise inference**: point BYOM at a vision model you host yourself (vLLM, SGLang) and nothing leaves your network at all. If you don't have the hardware for it, we can supply a local deployment on NVIDIA hardware you purchase, [talk to us](/docs/support/get-help). ## What the agent may do on a machine [#what-the-agent-may-do-on-a-machine] The blast radius is the toolbox, not the machine. The agent can only act through tools it was given, and you decide which: * **Screen, keyboard, mouse** come with the device and are always there. Within a session the agent can do what the logged-in user can do. * **Reach beyond the UI is opt-in**: the shell, SQL and file tools in the [Tool Store](/docs/extending/tools) are off until someone enables them, and enabling them is recorded in `utils/tools.json` in the project, so it shows up in review. * **Custom tools are code**: a `.cs` file in [`utils/custom_tools/`](/docs/extending/custom-tools) runs with the permissions of the run, which is why they belong to developers and get reviewed like any other code in the repository. * **Elevation is a deliberate switch**: without ["Allow control of administrative applications"](/docs/agentos/installation/service) the agent cannot drive elevated windows. * **Credentials never reach the model**: steps reference [secrets](/docs/extending/secrets) by name, values are substituted at execution time and redacted from reports and logs. How to keep that reach as small as a test needs, account rights, scoping each tool, what belongs in review: [What the agent may do](/docs/best-practices/security). ## Telemetry, what we see [#telemetry-what-we-see] * **The hub** sees sign-in, tokens and usage counters for billing, not your test content ([usage dashboard](/docs/account-billing/usage-dashboard)). * **Model traffic** goes to the provider you chose, and only that provider, see above. * **OpenTelemetry tracing is off by default.** It exists for teams that want traces in their own collector and is enabled explicitly with `ASKUI__OTEL_*` environment variables, pointing at an endpoint you own. * **Reports and screenshots stay local**, in the project folder. Nothing uploads them anywhere. ## Data protection [#data-protection] * **Test content that travels** is limited to what the model provider needs for inference: the screenshot, the step text and the conversation of the current phase. Nothing else is transmitted, and with [on-premise inference](#what-leaves-the-network-and-how-to-stop-it) not even that. * **Screenshots can contain personal data** if your test data does. That is a processing decision on your side: choose the provider placement accordingly, and prefer synthetic or anonymised test data. * **Evidence lives with you**: reports, screenshots and the conversation log are files in your project, so your retention and deletion rules apply unchanged. * **DPA, retention at the hub, hosting region, and whether a provider trains on inputs** depend on the provider you choose and your contract with us: [ask us for the current documents](/docs/support/get-help) rather than assuming. ## What is stored where [#what-is-stored-where] | Data | Location | | ---------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | | Testware, tests, procedures, plans, rules | The [project folder](/docs/projects), plain files, yours to version | | Agent files, `tests/ui.md`, `tests/rules.md`, `utils/format.md`, tool and device configuration | Same folder, versioned alongside the testware | | Test evidence, reports, screenshots, logs | `agent_workspace/` inside the project, local | | Credentials for tests | The app's [secret store](/docs/extending/secrets), encrypted with your Windows/macOS user account, never in the project | | Sign-in tokens | Encrypted local storage on your machine | ## What is downloaded at runtime [#what-is-downloaded-at-runtime] For supply-chain review, the app fetches on demand, each after an explicit action on your side: browser bundles (first [web-profile](/docs/devices/web-browser) connect), the Android SDK toolchain (consent click on [Set up](/docs/devices/android-emulator)), NuGet packages declared by your [custom tools](/docs/extending/custom-tools) (resolved via your own `NuGet.config`, so enterprise feeds and mirrors apply), and connections to the [MCP servers](/docs/extending/mcp) your project registers. ## Running the lab machines [#running-the-lab-machines] What the team providing the machines needs to know: * **Interactive session required.** The agent works on a real desktop session: a locked screen or a machine with no session has nothing to drive, and a run against it ends as `BROKEN`. Keep sessions unlocked and screensavers/sleep disabled on test machines. * **Service or standalone.** AgentOS can run as an installed [Windows service](/docs/agentos/installation/service) (port 26000, starts with the machine, survives reboots, the choice for shared lab machines) or be started by the app on demand (port 23000, fine on a tester's own PC). * **Elevation.** Driving elevated windows requires enabling ["Allow control of administrative applications"](/docs/agentos/installation/service) during installation. * **Sizing.** Requirements per machine, including what a VM needs: [system requirements](/docs/agentos/reference/system-requirements). No GPU is needed on the test machine, inference happens at the model provider. * **Health.** The [Devices](/docs/devices) page shows connection state per profile before a run; when a machine misbehaves, the symptoms and checks are in [Connection & sessions](/docs/troubleshooting/connection-sessions). ## Concurrency and upgrades [#concurrency-and-upgrades] * **One run drives one device profile at a time.** Parallelism comes from starting more runs: several CI jobs, several machines, or a [multi-computer profile](/docs/devices/multi-computer) when one agent should hand over between machines inside a single test. * **Project files are versioned and migrate forward.** Device profiles and tool configuration carry a version and are migrated on first save by a newer app; renamed or removed built-in tools are mapped automatically. Because everything is a plain file in Git, an upgrade shows up as a diff you can review. ## Infrastructure requirements [#infrastructure-requirements] | Question | Answer | | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Operating systems** | AskUI Desktop: Windows and macOS. AgentOS on target machines: Windows 10+/Server 2019+, macOS 10.15+, Ubuntu 18.04+, [full matrix](/docs/agentos/reference/system-requirements) | | **Proxy** | A system/corporate proxy is supported app-wide (Settings → Network proxy), including NTLM/Kerberos authentication, covers sign-in, model provider, and MCP traffic. [Network proxy](/docs/troubleshooting/network-proxy) | | **Air-gapped / no AskUI account** | [License-key mode](/docs/get-started/licensing) removes the hub from the picture entirely: activate locally, bring your own model endpoint. Runtime downloads (browsers, Android SDK) still need a reachable mirror or pre-provisioned tooling | | **CI runners** | The [CLI](/docs/running-tests/cli) authenticates via `ASKUI_WORKSPACE_ID` / `ASKUI_TOKEN`. Headless browser targets run on a bare runner; desktop targets need a machine with [AgentOS](/docs/agentos/deployment/ci) and a real session | | **Team rollout** | Which teams run what, and on whose machines: [Sharing the project](/docs/concepts/team-setups) | # Sharing the project (/docs/concepts/team-setups) A [project](/docs/projects) is plain files, so sharing it is a Git question, not a product question. What changes between teams is only **where the repository lives** and **who owns which part of it**. ## What travels with the repository [#what-travels-with-the-repository] Everything that defines a run is in the folder, so a colleague's clone behaves like yours: * **Testware**: test cases, [procedures](/docs/writing-tests/procedures), [test plans](/docs/writing-tests/plans), and each folder's `rules.md`, `setup.md`, `teardown.md`. * **Agent files**: the [system-prompt files](/docs/best-practices/agent-behavior) folder, so everyone's runs get the same instructions and report format. * **Device profiles**: `devices.json`, so every member sees the same [devices](/docs/devices) list instead of wiring machines by hand. * **The toolbox**: `utils/tools.json`, `utils/mcp.json` and `utils/custom_tools/*.cs`, which is what makes every grant reviewable in a pull request ([hardening](/docs/best-practices/security)). ## What each member adds locally [#what-each-member-adds-locally] Three things deliberately do **not** travel, and a new member has to supply them: * **[Secrets](/docs/extending/secrets)**: values live encrypted on the machine, never in the project. A fresh clone starts without them, which is the point, everyone uses their own test credentials. * **Access to the machines**: a device profile names a host; whether you can reach it depends on your network and on [AgentOS](/docs/agentos) running there. * **App settings**: sign-in, the [model provider](/docs/extending/model-providers) choice, the proxy. These are per machine, not per project. Run artifacts go the other way: `agent_workspace/` and `.askui_cache/` are excluded by the scaffolded `.gitignore`, so reports and screenshots stay local instead of bloating the repository. Archive them in [CI](/docs/guides/askui-in-ci) if you need them long-term. ## Who owns which part [#who-owns-which-part] Roles, not job titles, one person often wears several: * **Test author**: writes cases and expected results, curates plans, keeps `tests/ui.md` current as the application changes. * **Developer**: fixes what a run exposes, owns [custom tools](/docs/extending/custom-tools), wires the suite into CI. * **Lab owner**: provisions the machines, keeps sessions unlocked and AgentOS installed ([running the lab](/docs/concepts/enterprise-fit#running-the-lab-machines)). * **Workspace admin**: seats and [members](/docs/account-billing/members), tokens, and the model provider the team runs on, which is also the cost lever. * **Reviewer**: approves changes to the toolbox and device profiles, the same way dependency changes get reviewed. ## Where the repository lives [#where-the-repository-lives] Three arrangements, all with the same project layout: ### QA owns the repository [#qa-owns-the-repository] The testing team holds the testware repo, authors in **AskUI Desktop**, runs against the team's [devices](/docs/devices), and [schedules](/docs/running-tests/scheduling) recurring suites. Failures go to development as [run reports](/docs/results/run-report), expected vs. actual per step with screenshots, so a developer can act without reproducing first. * **Pick this if** QA owns its own environments and release cadence. * **It needs**: Desktop per tester, one shared repository, and the environments as device profiles so every tester connects to the same list. ### The application repository owns the tests [#the-application-repository-owns-the-tests] The project folder lives **inside the app repo**. Developers author in Markdown next to the feature, run locally with Desktop or the [CLI](/docs/running-tests/cli), and CI executes the suite on every pull request ([AskUI in CI](/docs/guides/askui-in-ci)). A failed UI test blocks the merge like a failed unit test. * **Pick this if** UI tests should gate merges and live with the code they cover. * **It needs**: the CLI on the runner with `ASKUI_WORKSPACE_ID` / `ASKUI_TOKEN`, and a device the runner can reach, a [headless browser](/docs/devices/web-browser) needs nothing else, desktop targets need [AgentOS](/docs/agentos/deployment/ci) on a test machine. ### One repository, two roles [#one-repository-two-roles] Testers curate suites, expected results and [test plans](/docs/writing-tests/plans); developers wire the smoke plan into CI and fix against the reports. Git is the collaboration layer: changes arrive as pull requests either side can review, and [configuration management of the testware](/docs/projects#git-versioning--sync) comes for free. * **Pick this if** regression belongs to QA but a fast subset should gate CI, the common end state. * **It needs**: agreement on which plan gates merges (`smoke`) and which runs [on a schedule](/docs/running-tests/scheduling), plus who owns the results of each. ## Onboarding a new member [#onboarding-a-new-member] 1. Clone the repository and open the folder in AskUI Desktop. 2. Add your [secrets](/docs/extending/secrets), the names are already referenced by the tests. 3. Connect a [device](/docs/devices) from the shared profile list. 4. Run one existing test to confirm the setup before writing anything. # Test automation harness (/docs/concepts/test-automation-harness) The model decides; the **AskUI harness** runs the test. It is what a test framework would otherwise be, built for an agent: it walks your selection in **phases**, assembles what the agent is told for each one, holds the limits that stop a run from grinding, and writes the reports ([where it sits](/docs/concepts/computer-use-agent#what-a-cua-agent-is-made-of)). A **phase** is one of `setup.md`, a test case, or `teardown.md`, and one autonomous agent execution: read the file, drive the UI through the [loop](/docs/concepts/computer-use-agent#the-loop), write the report as it goes. Nothing is shared between phases except what you deliberately hand across, which is what keeps one test from poisoning the next. ## Where the tester's time goes [#where-the-testers-time-goes] With scripted automation, most of the effort goes into keeping the scripts alive: locators that moved, waits that were too short, reruns to tell flake from defect. That layer is gone here, nothing in a test encodes the UI's structure, so there is nothing to repair when the UI changes. The time moves to the part that actually needs a tester: reading the [report](/docs/results/run-report), judging whether the behavior was right, and writing up the defect with the evidence attached. For an organization that is the real shift, automation cost stops scaling with UI churn, and testing capacity goes into coverage and analysis instead of maintenance. Where that time is best spent: [Analyzing failures](/docs/best-practices/analyzing-failures). That only holds if a run is cheap, trustworthy and fast, which is what a CUA model left to itself is not. The three things the harness is built for: * **Token efficiency**: every turn re-sends the conversation, so the harness keeps it small: a fresh transcript per phase instead of one growing transcript per run, the stable parts of the prompt and the tool definitions cached between turns, screenshots downscaled before they are sent, and tool results kept short by design (the SQL tool pages at 20 rows rather than dumping a table). * **Reliability**: the same instructions assembled the same way for every phase, a hard attempt limit instead of endless retrying, one documented status vocabulary, and a clean transcript per test so yesterday's failure can't influence today's. A `PASSED` means the same thing in every project. * **Speed**: the agent chains several actions into one model request where it can, needs no waits because it reads the screen, and pays the compilation cost of your [custom tools](/docs/extending/custom-tools) only when their source changed. What's left is mostly model latency, which is why the model you pick shows up directly in run duration ([performance & cost](/docs/troubleshooting/performance-cost)). ## Phases [#phases] **setup.md** establishes the suite's entry criteria first; a failing setup records the tests it guards as broken, they never execute against a bad state. **teardown.md** runs last, even after failures. **rules.md** applies to every phase. In nested suites, setups run top-down, teardowns bottom-up, and rules accumulate per level. ([Where these files live](/docs/writing-tests/organisation).) ## What the harness owns [#what-the-harness-owns] What it hands each phase, what it enforces, and what it leaves behind: * **The project**: everything it reads comes from one folder: the [project](/docs/projects). Tests, prompts, procedures, plans, tool configuration and device profiles are plain files, so a run is fully defined by what is checked into your repository, the same folder produces the same run on a colleague's machine or a CI runner. * **The agent files**: *who* is testing: the four [system-prompt files](/docs/best-practices/agent-behavior) of the project, the agent's identity and error discipline, facts about the machine, knowledge of your application, and the report contract. They apply to every phase and change rarely. * **The testware**: *what* is tested: the phase's own file (`setup.md`, a test case, `teardown.md`), the folder's [`rules.md`](/docs/writing-tests/setup-teardown-rules#rules), any [procedures](/docs/writing-tests/procedures) its steps call, and the [test plan](/docs/writing-tests/plans) that selected it. This is what changes per scenario. Steps naming credentials get the [secret](/docs/extending/secrets) names, never the values, those substitute at execution time. * **The toolbox**: *what it may do*: device tools for the run's device kind plus the [tools you enabled](/docs/extending/tools); a tool whose device isn't part of this run is left out with a warning. * **The limits and the default behavior in error cases**: what happens when a step doesn't work out, so a result means the same thing in every project ([the discipline](/docs/best-practices/agent-behavior#error-discipline-built-in)): * **Two attempts per step**: then stop, no third try, no creative workarounds, no navigating back to retry. * **The application misbehaved** → the step is `FAILED` and the test aborts; remaining steps are not executed against a wrong state. * **A precondition wasn't met** → `SKIPPED`. It never ran, so it can't count as a failure. * **Infrastructure broke** (device connection, session, peripheral) → `BROKEN` with a diagnosis hint, and the run aborts instead of grinding on against a broken machine. * **A referenced tool is missing** → `WARN` if the agent reached the goal another way, `BROKEN` if the step depended on it, and the next test still runs. * **A custom tool doesn't compile** → the run aborts before the first step, with the compiler error as the first entry in the log. The step-level defaults come from the agent's instructions, so a suite can soften them in [`rules.md`](/docs/writing-tests/setup-teardown-rules#rules), for example a documented recovery ("restart the scanner and repeat the step") instead of a `BROKEN`. The compile abort is not one of them: the runner refuses to start. * **The memory**: one conversation per phase: the agent starts each test with a clean transcript, so a previous test can't confuse it. To carry a value across phases on purpose, a step tells it to write to the [scratchpad](/docs/writing-tests/agents-and-prompts), setup stores the order number, a later test reads it. * **The reporting**: the evidence. Every phase streams into the [live conversation log](/docs/running-tests#watch-it-live) while it runs. The agent writes its [test report](/docs/results/run-report) as it works, so each step carries its interpretation, expected vs. actual and a screenshot; the harness adds the run's [summary table](/docs/results/run-report#summary-report) that the [Dashboard](/docs/results/dashboard) counts, and keeps the [conversation log](/docs/results#conversation-log) as the audit trail. All of it is Markdown and PNGs under `agent_workspace/`, so CI can archive it and a reviewer can read it without the app. ## Why execution differs [#why-execution-differs] A CUA agent is not a script. It reads the screen before every step, like a human tester following your instructions, and decides how to carry the step out. Two runs of the same case can take different paths: one run sees a cookie banner and closes it first; the next doesn't get one. One finds the button immediately; another scrolls first. Different execution, same expected result, that is by design, and the [reason to use an agent at all](/docs/concepts/computer-use-agent#why-not-a-script). For reading results it means one thing: the step's **expected result is the contract**, the path is only the execution log. What this means for how you write and judge tests, precise expected results, rules that constrain the agent's freedom, judging outcomes rather than paths, is covered in [Writing good tests](/docs/best-practices/writing-good-tests#non-deterministic-execution). # Android emulator (/docs/devices/android-emulator) An **Android emulator** profile provisions a virtual Android device on this machine. The app creates it, boots it, and connects it, you never touch `avdmanager`. ## Create it [#create-it] 1. **Add device** → **Android emulator**. 2. Fill in the fields: * **Device type**: hardware profile: screen size, resolution *(select, default `Pixel 9`)* * **System image**: the Android version the device runs *(select, default `Android 34 · Google APIs`)* * **Lifecycle**: what Start and Stop do, see below *(select, default `Persistent`)* * **Headless**: boot without an emulator window *(toggle, default off)* 3. **Add device**. The Android emulator profile editor with device type, system image, and lifecycle **Lifecycle** decides how long the device lives: | Lifecycle | On Start | On Stop | | -------------- | ------------------------------ | ----------------------------------------- | | **Persistent** | Reuses the existing device | Shuts the emulator down, keeps the device | | **Ephemeral** | Creates a factory-fresh device | Deletes the device | | **Always-on** | Reuses the existing device | Leaves the emulator running | Persistent is the everyday choice. Ephemeral gives every session reproducible preconditions at the cost of a cold boot. Always-on skips even the shutdown, fastest turnaround, state carries over. ## Run it [#run-it] 1. **Start** on the profile card boots the emulator and connects it. 2. Pick the profile in the test's **Run on** dropdown and press **Run**. The card shows each state while Start works: | State on the card | What's happening | Notes | | --------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- | | **Set up phases**: *Downloading command-line tools… / Unpacking JDK… / Accepting licenses… / Installing emulator… / Downloading system image…* | One-time tooling bootstrap, only when no Android SDK exists, runs after your consent click | Minutes, once per machine | | **Creating…** | Building the virtual device | First Start only, and every Start with an **Ephemeral** lifecycle | | **Booting…** *(· 42s)* | The emulator is cold-booting; the counter shows elapsed time | First boot takes several minutes, later boots are faster. If the emulator crashes on the machine's GPU, Start retries once with software graphics | | **Ready** | Boot completed, device connected, green dot | An emulator that was already running skips straight here, never rebooted | A Start that hangs in **Booting…** past \~8 minutes times out with an error, the emulator may still come up; Start again reconnects to it. Testing on a physical phone instead? See [Android phone (real device)](/docs/devices/android-phone), discovered via USB and added as a profile with one click. # Android phone (real device) (/docs/devices/android-phone) A physical Android phone or tablet is discovered automatically and turned into a profile with one click, it doesn't go through the Add-profile dialog. **Preconditions:** Developer options and **USB debugging** enabled on the device; connected via USB (accept the debugging prompt on the phone), or reachable wirelessly. ## Create it [#create-it] 1. Plug the device in. It appears under **Android devices** on the [Devices](/docs/devices) page, use the refresh button if it doesn't. 2. **Details** shows what was discovered: model, Android version, state. 3. Click **Add as profile**, the device becomes a regular profile card, named after the model, bound to its serial. ## Run it [#run-it] 1. **Connect** the profile card. 2. Pick the profile in the test's **Run on** dropdown and press **Run**. Keep the device awake and unlocked during runs, the agent acts on the real screen. ## Wireless [#wireless] No USB: enable wireless debugging on the device, then enter its `ip:port` in the field next to **Connect wireless**. The device joins the list and can be added as a profile the same way. A device shown as `offline` or `unauthorized` can't be added, reconnect the cable and accept the debugging prompt on the device. # Cross-platform (/docs/devices/cross-platform) A **Cross-platform** profile bundles a desktop, an Android device, and a web browser into one profile, for scenarios that will span all three (start a flow on the phone, finish it on the desktop). The profile connects and reports the status of each surface, but running tests against it is not supported yet. Until it is, split the scenario across single-surface profiles and run the parts separately. ## Create it [#create-it] 1. **Add device** → **Cross-platform**. 2. Configure the desktop (host, port, display), the Android serial, and the browser. 3. **Add device**: then **Connect** to see all three surfaces' status. # Devices (/docs/devices) Tests run on devices: this machine, a browser, a phone. A **device profile** describes how to reach one. Connected profiles appear in every test's **Run on** picker, they are your test environments. The Devices page with three device profiles, Windows Desktop, Chrome Browser, and a Pixel 9 Android emulator | On the page | Meaning | | ------------------- | ------------------------------------------------------------------------- | | **Windows Desktop** | This machine's desktop via the AskUI Agent OS, native applications | | **Chrome Browser** | A local Chrome window the app launches itself, web tests | | **Pixel 9** | An Android emulator, created and booted by the app | | **Connect / Start** | Opens the session. Green dot = ready. Tests only run on connected devices | | **Probe** | Checks reachability without connecting | A new project starts with a **Local** profile (this machine) and, where the machine supports it, a ready-made **Android Emulator** profile. Deleted defaults stay deleted. ## Create a profile [#create-a-profile] 1. Click **Add device**. 2. Pick the kind. 3. Enter a name and the kind's fields. The optional **Prompt** field holds what the agent gets told about this device on every run, quirks the screen doesn't show ("always execute on display 1"). 4. Click **Add device**, then **Connect** the new card. The Add device dialog with the device-kind picker | Kind | Device | Notes | | ------------------------------------------------------ | ----------------------------------------------------------------- | ------------------------------------------------------------------------ | | [**Remote computer**](/docs/devices/remote-computer) | Any machine running [AgentOS](/docs/agentos), host, port, display | Test on a dedicated machine instead of your own | | [**Web browser**](/docs/devices/web-browser) | Local browser session, Chromium, Firefox, or WebKit | Optional start URL, headless | | [**Android emulator**](/docs/devices/android-emulator) | Virtual device on this machine | Device type + Android version; created on first Start | | [**iOS simulator**](/docs/devices/ios-simulator) | Apple simulator | macOS only, greyed out on Windows | | [**Multi computer**](/docs/devices/multi-computer) | Several desktops, one agent | The test names the machine per step ("on the server …, on the client …") | | [**Cross-platform**](/docs/devices/cross-platform) | Desktop + Android + web in one profile | Connect/status only, runs not supported yet | | [**Android phone**](/docs/devices/android-phone) | A physical device via USB or wireless | Not in this dialog, added from the **Android devices** list below | Each kind has its own page with the exact fields and setup. Missing tooling (e.g. no Android SDK) shows up on the profile card as a one-click setup or as manual steps with exact commands. ## Android devices (discovery) [#android-devices-discovery] The **Android devices** section lists what `adb` sees: USB-connected phones (USB debugging enabled) and already-running emulators. **Add as profile** turns a discovered device into a regular profile, see [Android phone](/docs/devices/android-phone). For a wireless device, enter its `ip:port` and click **Connect wireless**. ## How a test picks its device [#how-a-test-picks-its-device] The test names its target ("Run this on the **Windows Desktop** device"); the **Run on** picker confirms it. Pick a different connected profile to run the same test on another environment. ## It uses your mouse and keyboard [#it-uses-your-mouse-and-keyboard] A desktop run on this machine is a real user session: the agent moves the pointer, types, and needs the application in the foreground. Don't work on the machine during a run, use a browser, emulator, or remote profile to keep working. ## Where profiles live [#where-profiles-live] `devices.json` in the project, including each profile's **Prompt** text. Colleagues get the same device list and only connect. See [How a Project is organized](/docs/projects). # iOS simulator (/docs/devices/ios-simulator) An **iOS simulator** profile provisions an Apple simulator. Apple ships the simulator exclusively with Xcode on a Mac. On Windows this kind is greyed out in the Add-profile dialog, running AskUI Desktop on Windows cannot drive an iOS simulator, not even a remote one. **Preconditions:** a Mac running AskUI Desktop, Xcode command-line tools (`simctl`), and `idb`, the profile card lists anything missing with the exact install commands. ## Create it [#create-it] 1. **Add device** → **iOS simulator**. 2. Fill in the fields: * **Device type**: the iPhone / iPad model to simulate *(select, default `iPhone 15`)* * **Runtime**: the iOS version; empty picks the newest installed *(select, optional)* * **Lifecycle**: same semantics as the [Android emulator](/docs/devices/android-emulator#create-it) *(select, default `Persistent`)* 3. **Add device**. ## Run it [#run-it] 1. **Start**: the simulator is created on first use and booted; later Starts reuse it. 2. Pick the profile in the test's **Run on** dropdown and press **Run**. # Multi computer (/docs/devices/multi-computer) A **Multi computer** profile puts several desktops under **one** agent. The test switches machines by name mid-test, for anything where two machines must interact: client and server, sender and receiver. ```md 1. On the **server**, start the message service. 2. On the **client**, send a message to the server. 3. On the **server**, the message appears in the log. ``` **Preconditions:** every machine runs [AgentOS as a service](/docs/agentos/installation/service) (port 26000) and is reachable over the network. ## Create it [#create-it] 1. **Add device** → **Multi computer**. 2. Add one row per machine (at least two). **Add from profile…** copies an existing Remote-computer profile into a row. Per row: * **Name**: how tests refer to the machine: role names (`server`, `client`), not hostnames *(text, required)* * **Host**: machine name or IP *(text, required)* * **Port**: the AgentOS port *(number, default `26000`)* * **Display**: which screen to drive on that machine *(number, default `1`)* 3. **Add device**. The Multi computer profile editor with one row of name, host, port, display per machine ## Run it [#run-it] 1. **Connect**: one session covering all machines. 2. Pick the profile in the test's **Run on** dropdown and press **Run**. The first row starts active; the agent switches whenever a step names another machine. # Remote computer (/docs/devices/remote-computer) A **Remote computer** profile drives a desktop machine through [AgentOS](/docs/agentos): your own PC, or a dedicated test machine so your mouse and keyboard stay free. **Preconditions:** for a remote machine, [AgentOS installed as a service](/docs/agentos/installation/service) on it (listens on port 26000) and reachable over the network. For this PC: none, the seeded **Local** profile starts its own AgentOS. ## Create it [#create-it] 1. **Add device** → **Remote computer**. 2. Fill in the fields: * **Host**: machine name or IP; `localhost` for this PC *(text, required)* * **Port**: the AgentOS port; 26000 = installed service *(number, default `26000`)* * **Display**: which screen to drive on a multi-monitor machine *(number, default `1`)* * **Use system proxy**: route the connection through your system proxy *(toggle, default off)* 3. **Add device**. The Remote computer profile editor with host, port, and display fields ## Run it [#run-it] 1. **Connect** on the profile card, the status dot turns green. 2. Pick the profile in the test's **Run on** dropdown and press **Run**. The agent sees and acts on exactly one display per session. The session is a real user session on that machine, pointer, keyboard, foreground windows. Nobody should work on it during a run. # Web browser (/docs/devices/web-browser) A **Web browser** profile tests web applications in a browser that AskUI Desktop launches and controls itself. No AgentOS, no separate install. ## Create it [#create-it] 1. **Add device** → **Web browser**. 2. Fill in the fields: * **Browser**: Chromium, Firefox, or WebKit *(select, default `Chromium`)* * **Start URL**: full URL every session opens with, e.g. `https://staging.example.com` *(text, optional)* * **Headless**: no visible window; the agent still sees the page through screenshots *(toggle, default off)* 3. **Add device**. The Web browser profile editor with browser choice, start URL, and headless toggle ## Run it [#run-it] 1. **Connect**: the first connect downloads the browser bundle once, expect a short wait. 2. Pick the profile in the test's **Run on** dropdown and press **Run**. Headless keeps your screen free; use a visible window when you want to watch. One profile per environment works well: `Staging web app`, `Prod smoke`, same tests, different start URL. # General (/docs/faq/general) ### What is AskUI? [#what-is-askui] AskUI is an AI-driven UI automation platform. You describe what to do in plain language, and an AI agent acts on the real screen, clicking, typing, and navigating, then produces a step-by-step report with screenshots. No selectors, no recording, no code required. ### What makes AskUI different from other automation tools? [#what-makes-askui-different-from-other-automation-tools] Traditional tools rely on CSS selectors, XPath, or element IDs that break when the UI changes. AskUI reads the screen visually, so tests are resilient to layout changes and work across any interface, including embedded UIs and legacy apps where the DOM is inaccessible. ### What platforms and interfaces does AskUI support? [#what-platforms-and-interfaces-does-askui-support] * **Desktop:** Windows, macOS, Linux * **Mobile:** Android, iOS (Simulators, experimental) * **Web:** Any browser * **Embedded / hardware:** Devices without software access via Companion Mode ### Is AskUI secure? [#is-askui-secure] Yes. AskUI is ISO 27001 certified and GDPR compliant. On-premise and air-gapped deployment options are available for customers who need their data to stay within their own infrastructure. See the [Trust Center](https://trust.askui.com) for details. # Getting started (/docs/faq/getting-started) ### How do I get started? [#how-do-i-get-started] Follow the [Quickstart](/docs/quickstart), it takes under 10 minutes and covers account creation, installation, and running a first test. ### Do I need to write code? [#do-i-need-to-write-code] No. Tests are written in plain Markdown. There is no API to learn and no programming language required. ### Can I try AskUI for free? [#can-i-try-askui-for-free] Yes. Sign up at the [AskUI Hub](https://hub.askui.com) to start a free trial with full feature access. # Overview (/docs/faq) What AskUI is, how it works, platform support, and security. First steps, free trial, and whether you need to write code. CI/CD, model providers, virtual machines, proxy, and installation requirements. Run status meanings, reports, and what a run costs. Plans, on-premise options, billing errors, and reading credit consumption. What you can automate, including embedded and proprietary UIs. *** Experiencing a specific error or unexpected behavior? See [Troubleshooting](/docs/troubleshooting) for step-by-step fixes, or [Get help](/docs/support/get-help) to contact the team. *** ## Find your question [#find-your-question] The docs answer these directly, each question links to the page that answers it. ### Getting started & concepts [#getting-started--concepts] | Question | Answered in | | ------------------------------------------------------- | ---------------------------------------------------------------------------------------- | | What is a CUA agent, and how does AskUI execute a test? | [How AskUI works](/docs/concepts/computer-use-agent) | | Why did the agent do it differently than last run? | [Test automation harness](/docs/concepts/test-automation-harness#why-execution-differs) | | What leaves our network, and what is stored where? | [Enterprise fit](/docs/concepts/enterprise-fit) | | Proxy, air-gapped use, CI runners, OS support? | [Infrastructure requirements](/docs/concepts/enterprise-fit#infrastructure-requirements) | | Should testers, developers, or both own the testware? | [Sharing the project](/docs/concepts/team-setups) | | Can I run without an AskUI account? | [License key activation](/docs/get-started/licensing) | ### Devices [#devices] | Question | Answered in | | -------------------------------------------------------- | ------------------------------------------------------------------------------------------ | | Which device kinds exist, and how do I create a profile? | [Devices](/docs/devices) | | How does a test know which device to use? | [Devices → How a test picks its device](/docs/devices#how-a-test-picks-its-device) | | Does a desktop run take over my mouse and keyboard? | [Devices → It uses your mouse and keyboard](/docs/devices#it-uses-your-mouse-and-keyboard) | | What do the emulator's Booting / Ready states mean? | [Android emulator → Run it](/docs/devices/android-emulator#run-it) | | How do I test on a real Android phone? | [Android phone](/docs/devices/android-phone) | | Can I test iOS from Windows? | [iOS simulator](/docs/devices/ios-simulator) | | Can one agent drive several machines in one test? | [Multi computer](/docs/devices/multi-computer) | ### Writing tests [#writing-tests] | Question | Answered in | | --------------------------------------------------------- | --------------------------------------------------------------------------------------- | | How do I create a test case, and what shape does it have? | [Test cases](/docs/writing-tests) | | Which file formats can a test case have? | [Test case formats](/docs/writing-tests#anatomy--formats) | | When do I use setup.md, teardown.md, rules.md? | [Setup, Teardown & Rules](/docs/writing-tests/setup-teardown-rules) | | How do I reuse a step sequence across tests? | [Procedures](/docs/writing-tests/procedures) | | How do I keep credentials out of test files? | [Secrets](/docs/extending/secrets) | | Can one case target desktop and mobile together? | [Test cases → Target multiple platforms](/docs/writing-tests#target-multiple-platforms) | | How do I skip a case temporarily? | [Test cases → skip](/docs/writing-tests#skip) | | How do I group tests into smoke / regression sets? | [Plans](/docs/writing-tests/plans) | | What can a step express, conditions, waits, checks? | [Step constructs](/docs/writing-tests/step-constructs) | | How do I write steps the agent executes reliably? | [Writing good tests](/docs/best-practices/writing-good-tests) | ### Running & results [#running--results] | Question | Answered in | | ------------------------------------------------------------ | ------------------------------------------------------------- | | How do I start a run, and what happens during one? | [Running a test](/docs/running-tests) | | Can I watch the agent while it works? | [Running → Watch it live](/docs/running-tests#watch-it-live) | | How do I run suites automatically every day? | [Scheduling](/docs/running-tests/scheduling) | | How do I run headless in CI? | [AskUI in CI](/docs/guides/askui-in-ci) | | How do I read the report, and what do the statuses mean? | [Run report](/docs/results/run-report) | | Where do I see trends across runs? | [Dashboard](/docs/results/dashboard) | | A test failed, how do I find out why, and where do I fix it? | [Analyzing failures](/docs/best-practices/analyzing-failures) | ### Extending [#extending] | Question | Answered in | | ---------------------------------------------------------- | --------------------------------------------------------------------------------- | | What is the agent allowed to do, and how do I restrict it? | [Tools](/docs/extending/tools) | | The built-in tools aren't enough, now what? | [Custom tools](/docs/extending/custom-tools) · [MCP servers](/docs/extending/mcp) | | Can I use my own AI model instead of the AskUI hub? | [Model providers](/docs/extending/model-providers) | # Pricing & licensing (/docs/faq/pricing-licensing) ### How is AskUI priced? [#how-is-askui-priced] AskUI offers a free trial, team plans (pay-per-use), and enterprise plans with custom pricing and SLA. Contact [sales@askui.com](mailto:sales@askui.com) for enterprise terms. ### Is there an on-premise option? [#is-there-an-on-premise-option] Yes. Enterprise customers can deploy AskUI fully on-premise or in an air-gapped environment. Contact your account manager or [sales@askui.com](mailto:sales@askui.com). ### I get a billing or credit error during a run. [#i-get-a-billing-or-credit-error-during-a-run] This is an account issue, not a broken installation. It means AskUI could not authorize the run against your workspace, usually because credits are exhausted or the subscription has lapsed. Steps to resolve: 1. Open **AskUI Hub → Workspace → Billing** and check your subscription status and remaining credits. 2. If credits are exhausted, top up or upgrade your plan. 3. If the error persists on an active paid plan, contact [support@askui.com](mailto:support@askui.com) with your workspace ID and the error message from the run report. ### How do I see how many credits a run consumed? [#how-do-i-see-how-many-credits-a-run-consumed] * **Per run:** open the run report, the header shows total tokens and cost for that run. * **Across all runs:** go to **AskUI Hub → Workspace → Usage**. See the [Usage dashboard](/docs/account-billing/usage-dashboard) for a breakdown by run, test case, and access token. # Runs & reports (/docs/faq/runs-reports-cost) ### What is the difference between a failed and a broken status? [#what-is-the-difference-between-a-failed-and-a-broken-status] * **`FAILED`**: the agent completed the step but the outcome did not match expectations. This typically points to a bug in the application under test: a button did not appear, a value was wrong, a transition did not happen. Investigate the app. * **`BROKEN`**: the run could not complete a step due to an infrastructure or environment issue: AgentOS unreachable, step limit reached, model error, or network timeout. Investigate the environment, not the app. Check the [Troubleshooting guide](/docs/troubleshooting) first. * **`WARN`**: the step completed but something unexpected was noted. The run continues. See [Reading a run report](/docs/results/run-report) for the full status reference. # Technical (/docs/faq/technical) ### Can I use AskUI in CI/CD pipelines? [#can-i-use-askui-in-cicd-pipelines] Not yet. CI execution runs through the AskUI CLI (`askui run`), which is not publicly available yet. The setup is documented so you can plan for it: [AskUI in CI](/docs/guides/askui-in-ci) and [CI examples](/docs/agentos/deployment/ci-examples). ### Which AI models does AskUI use? [#which-ai-models-does-askui-use] By default, AskUI routes through the AskUI Hub's inference service, which serves more than one hosted model (e.g. Claude and Gemini). ### Does AskUI work with virtual machines? [#does-askui-work-with-virtual-machines] Yes. AgentOS works on VMware, VirtualBox, Hyper-V, and cloud VMs (AWS, Azure, GCP). For headless VM scenarios in CI, use AgentOS as an OS service, see [CI/CD integration](/docs/agentos/deployment/ci). ### Does AskUI work behind a corporate firewall or proxy? [#does-askui-work-behind-a-corporate-firewall-or-proxy] Yes. Configure it in the app under **Settings → Network proxy** (system proxy, manual address, NTLM/Kerberos): [Network proxy](/docs/troubleshooting/network-proxy). For the list of domains to allowlist, see [Network requirements](/docs/reference/network-requirements). ### What does our IT team need to allow for AskUI to work? [#what-does-our-it-team-need-to-allow-for-askui-to-work] All AskUI traffic uses standard HTTPS (port 443). The full list of domains and ports to allowlist is in [Network requirements](/docs/reference/network-requirements), that page is written so it can be shared directly with an IT department. Key notes for IT: * Both IPv4 and IPv6 are supported; no non-standard ports are required outbound (driving a remote test machine adds an inbound port on that machine, see Network requirements). * Contact [support@askui.com](mailto:support@askui.com) to request a one-pager formatted for IT firewall review. ### I don't have admin rights on the target machine. Can I still install and run AskUI? [#i-dont-have-admin-rights-on-the-target-machine-can-i-still-install-and-run-askui] AskUI Desktop installs per-user on Windows and macOS and does not require administrator rights for the standard installation. Limitations without admin rights: * **AgentOS in Host Mode** requires OS-level permission to simulate keyboard and mouse input. On locked-down machines, IT may need to whitelist the AgentOS process or grant input-simulation permissions. * **Running AgentOS as a system service** (for unattended or CI use) does require elevated privileges. If your machines are managed centrally, contact your IT team to request the necessary input-simulation permissions for the AgentOS executable. # Common use cases (/docs/faq/use-cases) ### What can I automate with AskUI? [#what-can-i-automate-with-askui] End-to-end testing, regression testing, cross-browser and mobile testing, RPA workflows, legacy system integration, data entry automation, and any scenario where the interface is the source of truth. ### Can AskUI automate embedded or proprietary UIs? [#can-askui-automate-embedded-or-proprietary-uis] Yes. Because AskUI reads the screen rather than the DOM, it works on any interface that produces a visible output, including embedded HMI screens, industrial control panels, and legacy applications with no accessible automation API. # Custom tools (/docs/extending/custom-tools) A **custom tool** is one C# file in `utils/custom_tools/`. It joins the agent's toolbox for every run of the project, for anything no built-in covers: your product's admin API, resetting test users, seeding data. Manage the files under **Extending → Custom Tools**. Custom tools are C# code with full machine access, running inside every run of the project. They should be implemented and validated by your developers or the AskUI Solution Engineering team, not edited ad hoc by test authors. The Custom Tools tab on the Extending page listing the project's .cs tool files with a drop zone * **File list**: every `.cs` file in `utils/custom_tools/`. The trash icon removes one: the file is deleted, the agent loses the tool on the next run. * **Drop zone**: drop `.cs` files or click to choose. Copying files into the folder manually works too, the folder is watched. * **Open folder**: opens `utils/custom_tools/` in your file explorer. * **Warnings**: the same NuGet package requested at different versions across files is flagged; the higher version wins at run start. There is no in-app code editor, write tools in your own IDE. ## Create a tool [#create-a-tool] 1. Write a class deriving from `Tool`: a name, a description (what the agent reads to decide when to call it), an input schema, and `InvokeAsync`: ```csharp title="utils/custom_tools/reset_test_user.cs" public sealed class ResetTestUserTool : Tool, ISecretsConsumer { private string _apiKey = ""; public ResetTestUserTool() : base( name: "reset_test_user", description: "Resets a test user to a clean state via the admin API.", inputSchema: new JsonObject { ["type"] = "object", ["properties"] = new JsonObject { ["username"] = new JsonObject { ["type"] = "string" }, }, ["required"] = new JsonArray("username"), }) { } public void UseSecrets(IReadOnlyDictionary secrets) => _apiKey = secrets.GetValueOrDefault("ADMIN_API_KEY", ""); public override async ValueTask InvokeAsync( JsonObject input, CancellationToken cancellationToken = default) { using var http = new HttpClient(); http.DefaultRequestHeaders.Add("X-Api-Key", _apiKey); var response = await http.PostAsync( $"https://admin.example.com/api/users/{input["username"]}/reset", content: null, cancellationToken); return response.IsSuccessStatusCode ? ToolResult.FromText($"User {input["username"]} was reset.") : ToolResult.Error($"Admin API returned {(int)response.StatusCode}."); } } ``` 2. Drop the file onto **Extending → Custom Tools**, or save it straight into `utils/custom_tools/`. 3. Add the secret it uses (`ADMIN_API_KEY`) under **Extending → Secrets**, never hard-code credentials into the file. 4. Use it in a [step](/docs/writing-tests/step-constructs#tool-invocations), the file compiles when the run starts: ```md title="tests/setup.md" 2. Use the reset_test_user tool for user "qa_user_1". ``` What the example uses, and what else a tool file can do: * **No boilerplate**: common namespaces (`System`, `System.Net.Http`, `System.Text.Json.Nodes`, the AskUI tool types) work without `using` directives. * **Secrets**: implement `ISecretsConsumer` and the run hands the tool the project's [named secrets](/docs/extending/secrets); `ADMIN_API_KEY` above comes from Extending → Secrets, not from the file. * **Device access**: a constructor asking for `IAgentOs` (desktop), `IWebAgentOs` (browser), `IAndroidAgentOs`, or `IIosAgentOs` gets the run's device layer injected. Parameterless (like above) works on every run; a tool whose device isn't part of the run is skipped with a warning. * **The .NET standard library**: available without any package: ZIP archives (`System.IO.Compression`), cryptography, regular expressions, XML, sockets, starting processes. Namespaces beyond the injected common ones need one `using` line: ```csharp using System.IO.Compression; ZipFile.ExtractToDirectory("export.zip", "export"); ``` * **NuGet packages**: for everything the standard library doesn't cover, declared per file at the top, `#:package Npgsql@8.0.3`, resolved through your normal `NuGet.config`, so enterprise feeds work unchanged. ## A tool using all of it [#a-tool-using-all-of-it] A visual reference check, it pulls a screenshot through the run's device layer (`IAgentOs` in the constructor), compares pixels with a NuGet package (`#:package`), and returns an **image** the agent can look at, not just text: ```csharp title="utils/custom_tools/compare_with_reference.cs" #:package SixLabors.ImageSharp@3.1.7 using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; public sealed class CompareWithReferenceTool : Tool { private readonly IAgentOs _agentOs; public CompareWithReferenceTool(IAgentOs agentOs) : base( name: "compare_with_reference", description: "Compares the current screen against a reference image. " + "Returns the deviation in percent and a difference image " + "with deviating pixels marked red.", inputSchema: new JsonObject { ["type"] = "object", ["properties"] = new JsonObject { ["reference"] = new JsonObject { ["type"] = "string", ["description"] = "Path to the reference PNG, e.g. utils/references/dashboard.png", }, }, ["required"] = new JsonArray("reference"), }) { _agentOs = agentOs; } public override async ValueTask InvokeAsync( JsonObject input, CancellationToken cancellationToken = default) { var screenshot = await _agentOs.ScreenshotAsync(cancellationToken); using var actual = Image.Load(screenshot.PngBytes); using var expected = Image.Load(input["reference"]!.GetValue()); expected.Mutate(e => e.Resize(actual.Width, actual.Height)); long deviating = 0; using var diff = new Image(actual.Width, actual.Height); for (var y = 0; y < actual.Height; y++) for (var x = 0; x < actual.Width; x++) { var same = actual[x, y] == expected[x, y]; if (!same) deviating++; diff[x, y] = same ? actual[x, y] : new Rgba32(255, 0, 0); } using var png = new MemoryStream(); await diff.SaveAsPngAsync(png, cancellationToken); var percent = 100.0 * deviating / (actual.Width * (long)actual.Height); return ToolResult.FromTextAndImage( $"{percent:F2}% of the pixels deviate from the reference (marked red).", ImageData.FromBytes(png.ToArray())); } } ``` ```md title="tests/dashboard_test.md" 5. Compare the screen with the reference "utils/references/dashboard.png", at most 1% of the pixels may deviate. ``` Because the constructor requires `IAgentOs`, this tool exists only on computer and web runs, on an Android run it is skipped with a warning. ## Keep results small [#keep-results-small] Everything a tool returns goes into the agent's conversation and is sent to the model on every following step, it costs [tokens](/docs/troubleshooting/performance-cost) for the rest of the test. Return what the agent needs to decide the step, not everything you have: * Cap lists and truncate long text, the built-in SQL tool pages at 20 rows for exactly this reason. * Aggregate instead of dumping, "3 files, newest: report.pdf" beats 500 file names. * Images are the most expensive result, return one, sized to what the agent must see. Files compile when a run starts (cached; unchanged files cost nothing). A file that doesn't compile **aborts the run**, with the error as the first entry in the conversation log, a broken tool is a broken test environment. # MCP servers (/docs/extending/mcp) A capability that already exists as an [MCP](https://modelcontextprotocol.io) server, a Jira bridge, an internal API gateway, doesn't need rebuilding as a custom tool. Register it; its tools join the agent's toolbox. ## Add a server [#add-a-server] 1. Open **Extending → MCP Servers**. 2. Click **Add MCP server**. 3. Enter **Name**, **URL** (SSE or HTTP), and optional **Headers**, one per line, e.g. `Authorization: Bearer ${MCP_TOKEN}`. The MCP Servers tab on the Extending page with the registered servers list This writes `utils/mcp.json` in the project, the whole team and the [CLI in CI](/docs/running-tests/cli) get the same server list: ```json title="utils/mcp.json" { "servers": { "issue-tracker": { "url": "https://mcp.example.com/sse", "headers": { "Authorization": "Bearer ${TRACKER_TOKEN}" } } } } ``` `${VAR}` values resolve at run start, from the project's [secrets](/docs/extending/secrets) first and the environment second, the token never lands in the file. Servers connect when a run starts. An unreachable server is retried once, then the run continues **without** it, with a warning in the log, an unavailable helper doesn't fail the suite, and the warning explains any missing tool. # Model providers (BYOM) (/docs/extending/model-providers) By default, AskUI Desktop runs inference through the **AskUI hub**, billed to your workspace, nothing to configure. **Bring your own model (BYOM)** points the agent at a model provider you control instead: your own Anthropic key, any OpenAI‑compatible API, or a self‑hosted server on your network. BYOM changes only **where inference runs**, the agent, prompts, tools, and run reports are identical. ## Where to configure it [#where-to-configure-it] Configure it under **Settings → Account → Model Provider**, switch an already‑running install to BYOM, or edit/remove an existing configuration. ## Choose an API type [#choose-an-api-type] Run against the **Anthropic Messages API** with your own key, Anthropic directly, [Azure AI Foundry](https://learn.microsoft.com/azure/ai-foundry/), or any Anthropic‑compatible endpoint (including a self‑hosted server such as vLLM). | Field | Required | Notes | | ------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | **Base URL** | Optional | Leave **blank** for Anthropic's own API. Set it for Azure AI Foundry or a self‑hosted Anthropic‑compatible endpoint. | | **Model** | Optional | Defaults to a current Claude model if left blank. See Anthropic's [model list](https://docs.anthropic.com/en/docs/about-claude/models/overview). | | **API key** | Required | Generate one in the [Anthropic console](https://console.anthropic.com/settings/keys). | OpenAI-compatible providers are experimental. They may work with capable vision models, but we do not test against them and cannot offer support for issues specific to this configuration. Run against any **OpenAI Chat Completions–compatible API**, [OpenRouter](https://openrouter.ai), OpenAI, or a self‑hosted server (vLLM, SGLang, llama.cpp, Ollama). | Field | Required | Notes | | ------------ | -------- | --------------------------------------------------------------- | | **Base URL** | Required | The endpoint, ending in `/v1`, e.g. `http://localhost:8000/v1`. | | **Model** | Required | The provider's model id, e.g. `Qwen/Qwen3-VL-…`. | | **API key** | Optional | Omit for local servers that don't require one. | **Authentication** has a second mode for a gateway fronted by **Microsoft Entra ID**: e.g. an internal LLM gateway of your company. Choose **Microsoft Entra (OAuth2 client credentials)** instead of **API key (or none)** and fill in the app registration: * **Tenant ID**: GUID or domain, e.g. `contoso.onmicrosoft.com` *(required)* * **Client ID**: the application (client) id of your app registration *(required)* * **Scope**: the resource scope, usually ending in `/.default`, e.g. `api:///.default` *(required)* * **Client secret**: stored encrypted on this device, like an API key *(required)* Saving acquires a token to verify the app registration; during runs, tokens are minted and refreshed automatically. The agent drives a UI from **screenshots**, so it needs a **vision‑capable** model. A text‑only model will connect but won't be able to see the screen. ## Supported models [#supported-models] * **Default**: `claude-sonnet-4-6`. Leave the **Model** field blank on the Anthropic tab and this is what runs. * **Claude models (recommended)**: the Anthropic Messages API is the tested path, whether you reach it through the AskUI hub, your own Anthropic key, Azure AI Foundry, or an Anthropic-compatible gateway. AWS Bedrock and GCP Vertex AI authenticate differently (SigV4, Google credentials), as do some internal gateways: either put something in front that re-exposes them as an Anthropic- or OpenAI-compatible endpoint, or [talk to us](/docs/support/get-help) and we help you get your authentication scheme supported. Any current Claude model with vision works; ids come from Anthropic's [model list](https://docs.anthropic.com/en/docs/about-claude/models/overview). Newer Claude generations also use adaptive thinking automatically. * **GPT-5.4 models**: supported through the OpenAI-compatible tab: `gpt-5.4`, `gpt-5.4-mini` and `gpt-5.4-nano`, from OpenAI directly or via OpenRouter. They see screenshots and call tools, so they drive a UI, they're just not the path AskUI tests against. * **Gemini vision models**: `gemini-2.5-pro`, `gemini-3-pro-preview` and the Flash variants work the same way, as long as your gateway exposes them OpenAI-compatibly (OpenRouter, or your own proxy). * **Self-hosted VLMs**: a screen-capable model such as `Qwen/Qwen3-VL-…` behind vLLM or SGLang, which keeps screenshots inside your own tenancy. * **What won't work**: text-only models, and models without tool/function calling. Every action the agent takes is a tool call on a screenshot; without both it cannot execute a step. Model choice is the main lever on run cost and duration, the trade-offs and what to watch: [Performance & cost](/docs/troubleshooting/performance-cost). ## Add a provider [#add-a-provider] Open **Settings → Account → Model Provider** (or reach it via license activation). Pick the **API type**, then fill in the base URL, model, and key per the table above. Select **Save**. AskUI Desktop makes a **test call** to the endpoint before saving, if the key, URL, or model is wrong, you'll see the error here rather than mid‑run. Run a test as usual. The agent now uses your provider. Behind a corporate proxy, configure network access **first**, the setup wizard's **Behind a proxy? Configure network access** section, or **Settings → Network proxy**: otherwise the test call can't reach the endpoint. Details: [Network proxy](/docs/troubleshooting/network-proxy). ## Gateway message transforms [#gateway-message-transforms] Some corporate gateways enforce rules **stricter than the stock OpenAI spec**, and reject the agent's requests with HTTP 400 even though the model behind them would accept them. For these, an operator project can normalize the outgoing `messages` array: drop a class implementing `IOpenAiMessageTransform` into `utils/message_transforms/`. ```csharp title="utils/message_transforms/gateway_normalization.cs" public sealed class GatewayNormalization : IOpenAiMessageTransform { public JsonArray Transform(JsonArray messages) { var output = new JsonArray(); foreach (var node in messages) { var message = (JsonObject)node!.DeepClone(); // Example gateway rule: an assistant message carrying // tool_calls must have content = null. if ((string?)message["role"] == "assistant" && message["tool_calls"] is JsonArray { Count: > 0 }) { message["content"] = null; } output.Add(message); } return output; } } ``` Transform files compile at run start exactly like [custom tools](/docs/extending/custom-tools), no `using` directives needed, a compile error aborts the run, and the same rule applies: **developer territory**. Multiple files compose in discovery order. Only the OpenAI-compatible provider consults them; the app ships no gateway-specific rules, your project owns them. ## How your credentials are stored [#how-your-credentials-are-stored] * The **API key** is stored **encrypted on this device** (on Windows, via DPAPI scoped to your user account). The non‑secret fields, provider, model id, base URL, are stored in plain local settings. * The key is passed to the run in memory and is **never written to the run report or logs**. * Editing other fields won't wipe a saved key, leave the key field blank to keep the existing one. ## Switching back to the AskUI hub [#switching-back-to-the-askui-hub] In **Settings → Account → Model Provider**, choose **Remove key**. This reverts to the AskUI hub default and forgets the stored key. (In License mode there is no hub default, so you replace the provider rather than removing it.) # Report format (/docs/extending/report-format) The report format tells the agent how to write test reports: the Markdown structure, the status vocabulary, and the artifact naming. It is one file, `utils/format.md`, global for every run of the project. 1. Open **Extending → Report Format**. 2. Edit the Markdown; changes save automatically. 3. If the project has no `utils/format.md` yet, click **Create utils/format.md**, it starts from the proven default. Two parts are load-bearing, keep them: * The **`**Status:**` line** of each report is parsed by the runner to set the run's result. Remove it and a passing test is recorded as BROKEN. * The **status definitions** (`PASSED`, `FAILED`, `SKIPPED`, `WARN`, `BROKEN`) are the [status vocabulary](/docs/results/run-report#test-report) your reports and the Dashboard count from. * The **artifact naming** (`{test_name}/{test_name}_report.md`, `step_{n}.png`) is how the app finds each test's report and screenshots. Everything else, the sections, the wording, the level of evidence, is yours to tailor: [the report contract](/docs/best-practices/agent-behavior#report-format-the-report-contract). # Secrets (/docs/extending/secrets) Test files are shared, reviewed, and versioned, credentials must never be in them. **Named secrets** keep the value on your machine only. ## Add a secret [#add-a-secret] 1. Open **Extending → Secrets**. 2. Click **Add secret**. 3. **Name** it (e.g. `QA_PASSWORD`), enter the **Value**, optionally a **Description**. 4. Enable **Agent may use this secret** if tests type it. The Secrets tab on the Extending page with the stored secrets list Values are stored encrypted on this machine, never in the project folder, never in version control. A colleague sees which names the project expects and enters their own values once. ## Use it in a test [#use-it-in-a-test] Reference the name, not the value: ```md Sign in with the QA credentials — the secrets named `QA_USERNAME` and `QA_PASSWORD`. ``` The agent sees only the name. It types a placeholder; the real value is substituted at execution time, hidden from the model, redacted from the conversation log and the reports. ## Use it in a tool config [#use-it-in-a-tool-config] A [tool](/docs/extending/tools), [custom tool](/docs/extending/custom-tools), or [MCP header](/docs/extending/mcp) references `${QA_PASSWORD}` and gets the value at run start. One limit: a value typed into a *visible* field appears on screenshots, redaction covers text, not pixels. Use masked password fields for genuinely sensitive data. # Tool Store (/docs/extending/tools) Everything the agent does happens through a **tool**, mouse, screenshot, file access, database query. The toolbox is the boundary of what a test can possibly do. Manage it under **Extending → Tool Store**. The Tool Store tab on the Extending page listing built-in tools with enable switches | Tier | Behavior | | ------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------- | | **Device tools** | Screenshot, click, type, injected automatically for the run's device kind. Always on, not listed | | **Default tools** | Enabled unless you switch them off | | **Optional tools** | Disabled until you enable them, typically tools with reach beyond the UI under test, like a shell or database access | | **[Custom tools](/docs/extending/custom-tools)** | Your own C# tools from `utils/custom_tools/`, always part of the run's toolbox once the file exists | | **[MCP tools](/docs/extending/mcp)** | Tools of the MCP servers registered in `utils/mcp.json`, connected at run start | Some tools take configuration when added, a connection string, a base URL. `${VAR}` values resolve at run start, from the project's [secrets](/docs/extending/secrets) first and the environment second; credentials belong in [named secrets](/docs/extending/secrets). Choices are saved to `utils/tools.json`, the whole team runs with the same toolbox. An untouched tool follows its tier default. ```json title="utils/tools.json" { "tools": { "datetime": true, "qr_scan": true, "http_request": { "enabled": true, "config": { "AllowedHosts": "api.example.com" } }, "shell_script": { "enabled": true, "config": { "ToolName": "restart_scanner", "ScriptPath": "C:/qa/restart_scanner.ps1", "Description": "Restarts the barcode scanner service." } } } } ``` `true`/`false` is the shorthand for tools without configuration; a configured tool stores `enabled` plus its values. A tool that isn't listed follows its tier default. Edit via the UI, the file is just what gets committed. ## The tools in the store [#the-tools-in-the-store] All store tools are currently **Optional**, off until you enable them. Grouped by where they reach; required parameters in bold. Every tool heading is a link, copy it to point a colleague at exactly one tool. ### Seeing the screen better [#seeing-the-screen-better] #### Screen zoom [#screen-zoom] A zoomed-in crop of a screen region (computer device). * **Use it when:** the agent keeps missing small targets, tiny checkboxes, dense tables. The last rung of the [misclick ladder](/docs/best-practices/analyzing-failures#the-agent-misclicks). ```md 4. Use the zoom tool to click the "Accept AGB" checkbox. ``` #### QR scanner [#qr-scanner] Scan and decode a QR code from the screen or an image (computer, web, Android). * **Use it when:** the application generates a QR code, invoice, ticket, and the test must verify it encodes the right content. ```md 6. Scan the QR code on the invoice — it encodes the order number from step 2. ``` ### Test data [#test-data] #### Date & time [#date-time] The current date/time; the agent can ask with a day offset (1 = tomorrow). * **Use it when:** a step needs a real date, "enter a delivery date three days from today", or verifies a timestamp the UI shows. * **Parameters:** Format, Timezone. ```md 3. Enter the date three days from today into "Delivery date". ``` #### Number converter [#number-converter] Convert between decimal, hex, binary, octal. * **Use it when:** the application shows values in one base and the test data is in another, hex device IDs, register values. ```md 5. Verify the "Device ID" field shows the hex value of 305419896. ``` ### Beyond the UI: on this machine [#beyond-the-ui-on-this-machine] #### HTTP client [#http-client] HTTP requests (GET, POST, …) against APIs and webhooks; header values support `${VAR}` [secrets](/docs/extending/secrets). * **Use it when:** cross-checking the UI against the backend, after checkout, verify via the API that the order really exists, or triggering a webhook as test setup. * **Parameters:** Allowed hosts (empty = any). ```md 8. Perform a GET request to https://api.example.com/orders — the new order is in the response. ``` #### SQL database [#sql-database] Run allowlisted SQL statements via any ODBC driver; raw SQL is a separate, dangerous opt-in. * **Use it when:** verifying the record actually landed in the database, or seeding and cleaning test data in [setup and teardown](/docs/writing-tests/setup-teardown-rules). * **Parameters:** **ODBC driver**, **Server**, **Database**, credentials, Allowed statements (`name: SQL` per line, the agent runs statements by these names), Allow raw SQL, full list in the add dialog. ```md 9. Run the "open_orders" SQL statement — the new order appears with status NEW. ``` #### Shell script [#shell-script] Run a pre-configured shell/batch script; the agent invokes it by the name you give it. * **Use it when:** a script already solves it, restarting a scanner service as a [recovery](/docs/writing-tests/step-constructs#beyond-steps), resetting the test database. * **Parameters:** **Tool name**, **Script path**, **Description**. ```md title="tests/rules.md" - If the scanner stops responding, run the restart_scanner tool and repeat the step. ``` #### File exists [#file-exists] Check whether a file or directory exists on this machine. * **Use it when:** the test ends in an export or download, verify the file actually appeared. * **Parameters:** **Base directory**. ```md 7. Check that the file "order_export.pdf" exists in C:/exports. ``` ### Files on the controlled machine [#files-on-the-controlled-machine] For runs where the application under test is on **another machine** (computer device) and writes files there. #### List remote files [#list-remote-files] List files in a directory on the machine being controlled. * **Use it when:** checking the export folder on the test machine after the run's actions. * **Parameters:** **Base directory**, Allowed file extensions. ```md 5. List the files in the export folder — a new PDF was created. ``` #### Read remote file [#read-remote-file] Read a file's text content from the controlled machine. * **Use it when:** the content matters, not just the existence, verify a log line or an exported CSV on the test machine. * **Parameters:** **Base directory**. ```md 6. Read the exported CSV — it contains the order number from step 3. ``` ## Using a tool in a test [#using-a-tool-in-a-test] Once enabled, a tool is available wherever steps live, test cases, [setup and teardown](/docs/writing-tests/setup-teardown-rules), and [procedure](/docs/writing-tests/procedures) bodies. Describe the action, or name the tool explicitly when two could match: ```md 6. Perform an HTTP GET request to `https://example.com` — the response status is 200. 7. Use the `sql_database` tool to run the statement `test_data`. ``` The full step vocabulary: [Step constructs → Tool invocations](/docs/writing-tests/step-constructs#tool-invocations). A step that names a tool the run doesn't have is flagged by the agent: **WARN** when it accomplished the step reliably another way, **BROKEN**, with a hint to enable the tool, when the step depends on it. Need more? [Custom tools](/docs/extending/custom-tools) for anything you can write in C#; [MCP servers](/docs/extending/mcp) for existing tool servers. # First run (/docs/get-started/first-run) Create a test in plain Markdown, run it on your own machine, and read what the agent did. This assumes you've [installed AskUI Desktop](/docs/get-started/install-desktop) and signed in. ## Create and run a test [#create-and-run-a-test] **Open or create a project.** Use the project from the onboarding wizard, or create a new one from the template. **Go to Tests** in the sidebar. **Create a test case.** Right-click in the file tree → **New Markdown**, name it `hello_world.md`, and write the steps in plain language: ```markdown # Hello World · Smoke Test ## Preconditions - The desktop is on the home screen ## Steps 1. Open the Notes app. 2. Create a new note. 3. Type "Hello World". ## Postconditions - Test passes if the note shows the text "Hello World". ``` **Run it.** With the test open, click **Run · Local**, the agent runs on **this machine** via the built-in `Local` device profile. (The Run button is a split button; use its dropdown to pick another device.) *** ## Analyse the run [#analyse-the-run] **Go to Runs** in the sidebar. The run streams in live and is saved when it finishes. ### Conversation log [#conversation-log] The **conversation log** is the run's detailed **test execution log**: it shows how the agent worked through your test case, step by step, like watching a tester do it and think out loud. It's the same view Live Run shows while a run is in progress. Here's what the `hello_world` run looks like:
Conversation 4 acts · 6 tool calls ▾ Autofollow
Quiet Detailed Raw
```json [ { "role": "user", "content": { "type": "act", "kind": "setup", "file": "setup.md" } }, { "role": "user", "content": { "type": "act", "kind": "test", "file": "tests/hello_world.md" } }, { "role": "assistant", "content": { "type": "text", "text": "I'll open Notes, create a note, and type the text." } }, { "role": "assistant", "content": { "type": "tool_use", "name": "click", "input": { "x": 134, "y": 174 } } }, { "role": "user", "content": { "type": "tool_result", "content": "clicked" } }, { "role": "assistant", "content": { "type": "tool_use", "name": "type", "input": { "text": "Hello World" } } }, { "role": "user", "content": { "type": "tool_result", "content": "typed" } }, { "role": "assistant", "content": { "type": "text", "text": "The note shows 'Hello World' — step verified." } }, { "role": "user", "content": { "type": "act", "kind": "teardown", "file": "teardown.md" } }, { "role": "assistant", "content": { "type": "tool_use", "name": "click", "input": { "x": 1884, "y": 21 } } }, { "role": "user", "content": { "type": "tool_result", "content": "clicked" } } ] ``` Follow it top to bottom, like watching over a colleague's shoulder: The run starts with **① Setup, ② Test, ③ Teardown**, the same three phases you know from any test run, each a numbered block with a **Pass / Fail** badge. In our run, act ① put the desktop into the starting state, then act ② picked up `hello_world.md`. Inside act ②, the agent first **tells you its plan** in plain language, *"I'll open Notes from the Start menu, create a note, and type the text."* These text lines are the agent thinking out loud; read them like a colleague narrating their work. Then it **acts on the screen**, the smaller rows, its *tool calls*. It takes a **screenshot** to see the desktop, **clicks** at position `134, 174` (where it spotted the Notes icon, the agent works in screen coordinates, like a human aiming the mouse), clicks again for a new note, and **types** `Hello World`. Every tool call shows its result (`→ clicked`); a failed one turns red with the error. Then it **checks its work**: a final screenshot, expanded so you see exactly what the agent saw, and its conclusion, *"The note shows Hello World, step verified."* That screenshot is your proof the pass is real. Act ③ cleans up (closing Notes), and the dashed **④ Upcoming** row at the bottom is the agent **predicting its next step**, during a live run you always see where it's heading before it gets there. If it's too much detail, switch from **Detailed** to **Quiet** for just the phases; **Raw** shows the underlying data. **Autofollow** keeps the view pinned to what the agent is doing right now. ### Test report [#test-report] Where the conversation log is the **test execution log**, the report is the **test execution report**: the structured record of one test case, its result, the evidence behind it, and any deviations. It follows the shape you know from manual test documentation. Here's the report for the `hello_world` run:

Test Case Report: hello_world

Test Case ID: hello_world
Date: 2026-07-17
Status: PASSED

Summary

The agent opened the Notes app, created a new note, and typed "Hello World". All steps passed; one incident was resolved during execution (see Issues).

Preconditions

1\. The desktop is on the home screen.

Test Steps

1. Open the Notes app , Status: PASSED

  • Agent Interpretation: Located the Notes icon on the taskbar and clicked it.
  • Expected: The Notes app opens.
  • Actual: Notes opened; a "What's new" popup appeared and was dismissed.

2. Create a new note , Status: PASSED

  • Agent Interpretation: Clicked the new-tab button to start an empty note.
  • Expected: An empty note is focused.
  • Actual: A new empty tab opened with the cursor in the text area.

3. Type "Hello World" , Status: PASSED

  • Agent Interpretation: Typed the text and took a screenshot to verify.
  • Expected: The note shows "Hello World".
  • Actual: The note shows "Hello World".
Notepad showing the text Hello World

Postconditions

1\. The note shows the text "Hello World".

Issues

1\. A "What's new" popup appeared after launching Notes and blocked the text area. Dismissed it and continued. Consider whether this popup should appear on every launch.

Conclusion

All steps passed. Creating and writing a note works as expected; the launch popup was the only deviation.

```markdown # Test Case Report: hello_world **Test Case ID:** hello_world **Date:** 2026-07-17 **Status:** PASSED ## Summary The agent opened the Notes app, created a new note, and typed "Hello World". All steps passed; one incident was resolved during execution (see Issues). ## Preconditions 1. The desktop is on the home screen. ## Test Steps 1. **Open the Notes app** — Status: **PASSED** - **Agent Interpretation:** Located the Notes icon on the taskbar and clicked it. - **Expected:** The Notes app opens. - **Actual:** Notes opened; a "What's new" popup appeared and was dismissed. 2. **Create a new note** — Status: **PASSED** - **Agent Interpretation:** Clicked the new-tab button to start an empty note. - **Expected:** An empty note is focused. - **Actual:** A new empty tab opened with the cursor in the text area. 3. **Type "Hello World"** — Status: **PASSED** - **Agent Interpretation:** Typed the text and took a screenshot to verify. - **Expected:** The note shows "Hello World". - **Actual:** The note shows "Hello World". - ![Step 3](step_3.png) ## Postconditions 1. The note shows the text "Hello World". ## Issues 1. A "What's new" popup appeared after launching Notes and blocked the text area. Dismissed it and continued. Consider whether this popup should appear on every launch. ## Conclusion All steps passed. Creating and writing a note works as expected; the launch popup was the only deviation. ```
Section by section: **Header:** Test case ID, execution date, overall status, your at-a-glance answer.\ **Summary:** The result in one or two sentences. Start here.\ **Preconditions:** The entry criteria the agent verified before executing, rules out an environment problem in disguise.\ **Test Steps:** Per step: status, **expected vs. actual result**, screenshot as evidence. This is where you localize which step diverged.\ **Postconditions:** The exit state the test asserted.\ **Issues:** Your incident log, deviations the agent hit during execution, including ones it resolved itself, like the "What's new" popup above, an unexpected dialog, or leftover data it had to delete first. A test can be `PASSED` and still list issues, and they often point at real findings a green checkmark would hide, review this section even when everything is green.\ **Conclusion:** The overall result and its justification. Five statuses exist, for steps and for the test overall, the test takes the worst status of its steps: **`PASSED`**: the actual result matched the expected one. The agent never bends a test to reach a pass.\ **`WARN`**: passed, but with a caveat worth your attention (slow response, minor visual deviation).\ **`FAILED`**: the step executed, but the actual result didn't match the expected one.\ **`SKIPPED`**: intentionally not executed, e.g. a precondition wasn't met.\ **`BROKEN`**: couldn't execute at all: a crash or an infrastructure problem, not a functional result. For details and the cross-run summary report, see [Reading a run report](/docs/results/run-report). And when the log or report shows the agent got something wrong, clicked the wrong element, misread a screen, drew the wrong conclusion, you don't debug code, you **teach it**: sharpen the wording of the test case, add a rule, or give it the missing knowledge in the prompts. How test cases, rules, and prompts work together is covered in [Prompting best practices](/docs/best-practices/prompting-best-practices). {/* TODO: retarget this link to the Concepts section once it exists. */}
Once the example passes, open `tests/ui.md` and describe your own app, its main screens, how to tell you're signed in, and any quirks. It's the single most important file for reliable runs. See [Prompting best practices](/docs/best-practices/prompting-best-practices). # Install AskUI Desktop (/docs/get-started/install-desktop) The entry point for authoring and running AI-driven UI tests. Runs on Windows and macOS. **Download the installer** for your platform: Also on your [AskUI Hub](https://hub.askui.com) account and the [Releases page](https://github.com/askui/integrated-task-platform/releases/latest) (always newest). **Run the installer.** Run the `.exe` and accept the prompts. Open the `.dmg` and drag AskUI Desktop to Applications. **Launch and sign in** with your AskUI account. On first launch the onboarding wizard sets up permissions and your first project. **Run [your first test](/docs/get-started/first-run).** # License key (/docs/get-started/licensing) There are two ways to run AskUI Desktop: | Mode | How you get in | Where inference runs | | ----------------- | ---------------------------------------------------------------------------- | ---------------------------------------------------------- | | **AskUI account** | [Sign in](/docs/get-started/install-desktop) with your AskUI account (Auth0) | AskUI hub, billed to your workspace | | **License key** | Activate a local license key, no account needed | **Your own model provider** (you add it during activation) | License mode is for teams that run against their **own** Anthropic or OpenAI‑compatible endpoint and don't want inference to route through the AskUI hub, air‑gapped setups, self‑hosted models, or an existing model contract. Because License mode never talks to the AskUI hub for inference, it **requires** a model provider. Activation walks you straight into [connecting one](/docs/extending/model-providers). ## Activate [#activate] **Open AskUI Desktop.** On the welcome screen choose **Activate with a license key** instead of signing in. **Paste your license key** and select **Continue**. **Add your model provider.** License mode runs on your own model, so the next step is the [model provider form](/docs/extending/model-providers). Enter your endpoint and key, then **Finish & open AskUI**. You're now in the app. AskUI Desktop remembers the license and model provider, so subsequent launches open straight into your projects. ## Managing your license [#managing-your-license] * Your license and its plan tier are shown in the **profile menu** (top‑right). * To switch machines or hand the seat back, **remove the license key** from the profile menu. Removing it returns you to the welcome screen. * If you later sign in with an AskUI account, the account takes precedence over a stored license key. Not sure which mode you want? If you don't already operate your own model endpoint, [sign in with an AskUI account](/docs/get-started/install-desktop) instead, it's the zero‑config path. ## Next [#next] # Uninstall AskUI (/docs/get-started/uninstall) Open **Settings** and go to **Apps** (or open **Control Panel** and go to **Programs and Features**). Find **AskUI Desktop** in the list of installed applications. Select it and click **Uninstall**, then follow the prompts. The uninstaller removes the application, its Start-menu and desktop shortcuts, and its registry entries. Your settings and sign-in data under `%LOCALAPPDATA%\AskUIDesktop` stay on disk, delete that folder too for a complete removal. **Silent uninstall:** ```powershell & "$env:LOCALAPPDATA\Programs\AskUI Desktop\uninstall.exe" /S ``` Open **Finder** and go to **Applications**. Drag **AskUI Desktop** to the Trash, or right-click and select **Move to Trash**. Empty the Trash to complete the removal. # AskUI in CI (coming soon) (/docs/guides/askui-in-ci) CI execution needs the AskUI CLI, which is not publicly available yet. This page describes the setup you will use once it ships, so you can plan for it. The project your team authors in AskUI Desktop will run unchanged on a build server, same testware, headless execution. ## 1: Get the CLI onto the runner [#1-get-the-cli-onto-the-runner] [Install the CLI](/docs/running-tests/install-cli) and provide credentials as environment variables: `ASKUI_WORKSPACE_ID` and `ASKUI_TOKEN` (create the token in the [Hub](/docs/account-billing/workspaces)). ## 2: Give it a device [#2-give-it-a-device] A [headless browser](/docs/devices/web-browser) runs on the bare runner. Desktop targets need a test machine with [AgentOS](/docs/agentos/deployment/ci) the runner can reach. ## 3: Run a plan [#3-run-a-plan] ```bash askui run --plan smoke --project-root . ``` Gate the pipeline on the exit code, and archive `agent_workspace/` as the build artifact, reports and screenshots included; the [CLI reference](/docs/running-tests/cli) shows the report-path and CI options. Which team runs what in CI, and who owns the results, is a working-model question: [Sharing the project](/docs/concepts/team-setups). # Test a web app (/docs/guides/test-a-web-app) The same journey as [Android](/docs/guides/test-an-android-app), for the web. ## 1: Define the browser [#1-define-the-browser] [Create a Web browser profile](/docs/devices/web-browser): pick Chromium, Firefox, or WebKit and set the **Start URL** to your application, one profile per environment (`Staging web app`, `Prod smoke`) keeps the same tests reusable across them. ## 2: Connect [#2-connect] **Connect** on the profile card, the first connect downloads the browser bundle once. No AgentOS, no further setup. ## 3: Write the test case [#3-write-the-test-case] [Create the case](/docs/writing-tests) and name the browser profile in it. Web-specific craft: describe elements as the user sees them ("the blue Checkout button in the cart"), state the expected page or dialog after every navigation, and put login into a [procedure](/docs/writing-tests/plans) with the credentials as [secrets](/docs/extending/secrets). ## 4: Run and analyze [#4-run-and-analyze] **Run on** the browser profile, headless keeps your screen free, a visible window lets you watch alongside the [live conversation](/docs/running-tests#watch-it-live). Failures land in the [run report](/docs/results/run-report) with a screenshot per step. # Test an Android app (/docs/guides/test-an-android-app) The whole journey for one goal: a passing (or usefully failing) test against an Android app. Each step links to the feature page with the full detail. ## 1: Define the device [#1-define-the-device] Emulator or real phone: * **Emulator**: [create an Android emulator profile](/docs/devices/android-emulator): device type, Android version, lifecycle. No phone needed; missing SDK tooling is a one-click **Set up**. * **Real phone**: enable USB debugging, plug it in, **Add as profile** from the discovered list: [Android phone](/docs/devices/android-phone). ## 2: Start it [#2-start-it] **Start** on the profile card. First emulator boot takes minutes, the [card walks through the states](/docs/devices/android-emulator#run-it) (Set up → Creating → Booting → Ready). Green dot = the device is an available test environment. ## 3: Write the test case [#3-write-the-test-case] [Create the case](/docs/writing-tests) under `tests/` and name the target device in it. Android-specific craft: * Name apps **as the user sees them** ("open the Calculator app"), not by package id, the agent works the launcher like a person. * **Verify the app is installed first.** Emulator images are lean; a stock Google-APIs image ships without Calculator, for example. Either state it as a precondition or pick an app the image has (Settings, Chrome, Clock). * Steps like swipes and the app drawer work in plain language: "open the app drawer", "swipe down to open notifications". ```md title="tests/open_clock_android.md" # Open the Clock app Run this on the **Pixel 9** device. ## Preconditions - The device shows the home screen. ## Steps 1. Open the app drawer. 2. Launch the **Clock** app. ## Postconditions - Test passes if the Clock app is open and shows the time. ``` ## 4: Run it and watch [#4-run-it-and-watch] Pick the Android profile in **Run on**, press **Run**, and open the **Runs** page, [the conversation streams live](/docs/running-tests#watch-it-live): every decision, tap, and device screenshot as it happens. ## 5: Analyze the result [#5-analyze-the-result] The [run report](/docs/results/run-report) gives per-step expected vs. actual with a screenshot each, your incident log when something failed. The [conversation log](/docs/results#conversation-log) holds the complete execution record. Remember the agent may have taken a different path than you imagined, [judge the result, not the path](/docs/best-practices/writing-good-tests#non-deterministic-execution). # Legacy SDKs (/docs/legacy) The Python SDK and TypeScript SDK are legacy products. They receive no bug fixes, security updates, or new features. We strongly recommend migrating to **AskUI Desktop** and the **AskUI CLI**. AskUI previously offered two code-based SDKs for authoring UI automation: * **Python SDK**: write automation scripts in Python against the AskUI runtime. * **TypeScript SDK**: write automation scripts in TypeScript/Node.js against the AskUI runtime. Both SDKs required writing code to interact with the AskUI agent. They are no longer actively developed or supported. ## Why we moved on [#why-we-moved-on] The SDK approach required users to learn an API, manage a language runtime, and maintain code as their UI changed. AskUI Desktop replaces all of that with plain-language prompts that describe what to do rather than how to do it, no selectors, no boilerplate, no SDK version upgrades. ## What to use instead [#what-to-use-instead] Author tests in plain Markdown and run them interactively on your machine. No code, no selectors, no SDK. Run the same projects headless in CI or on a schedule with a single command. Ships with the Desktop App installer. Get from zero to a passing test in under 10 minutes. # Python SDK (legacy) (/docs/legacy/python-sdk) The Python SDK is a legacy product. It receives no bug fixes, security updates, or new features. Use **AskUI Desktop** and the **AskUI CLI** for all new projects. The AskUI Python SDK allowed writing UI automation scripts in Python against the AskUI agent runtime. It is no longer actively developed or supported. ## Migrate to AskUI Desktop [#migrate-to-askui-desktop] AskUI Desktop replaces the SDK workflow entirely. Instead of writing Python code to interact with UI elements, you describe test steps in plain Markdown and the AI agent carries them out on the real screen. You do not need to rewrite automation logic line by line. The prompt-based approach means most test scenarios can be expressed more concisely than the equivalent SDK code. **[Get started with AskUI Desktop](/docs/get-started/install-desktop)** # TypeScript SDK (legacy) (/docs/legacy/typescript-sdk) The TypeScript SDK is a legacy product. It receives no bug fixes, security updates, or new features. Use **AskUI Desktop** and the **AskUI CLI** for all new projects. The AskUI TypeScript SDK allowed writing UI automation scripts in TypeScript/Node.js against the AskUI agent runtime. It is no longer actively developed or supported. ## Migrate to AskUI Desktop [#migrate-to-askui-desktop] AskUI Desktop replaces the SDK workflow entirely. Instead of writing TypeScript code to interact with UI elements, you describe test steps in plain Markdown and the AI agent carries them out on the real screen. You do not need to rewrite automation logic line by line. The prompt-based approach means most test scenarios can be expressed more concisely than the equivalent SDK code. **[Get started with AskUI Desktop](/docs/get-started/install-desktop)** # Environment variables (/docs/reference/environment-variables) ## Authentication [#authentication] | Variable | Description | | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | `ASKUI_WORKSPACE_ID` | Your workspace identifier. Required when using the AskUI Hub as the model provider. | | `ASKUI_TOKEN` | Your workspace access token. Required when using the AskUI Hub as the model provider. See [Workspaces](/docs/account-billing/workspaces). | ## AgentOS connection [#agentos-connection] | Variable | Default | Description | | ------------------------------------------ | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | `ASKUI_CONTROLLER_CLIENT_SERVER_AUTOSTART` | `true` | Set to `false` to prevent the CLI from starting a local AgentOS instance automatically. Use this when connecting to a remote AgentOS. | | `ASKUI_CONTROLLER_CLIENT_SERVER_ADDRESS` | `localhost:23000` | Address of the AgentOS gRPC server to connect to. Override when using a remote AgentOS instance. | # Glossary (/docs/reference/glossary) | Term | Definition | | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Access token** | A credential that authenticates the CLI or an external integration with the AskUI Hub. Every token belongs to exactly one workspace and has an expiry date. See [Workspaces](/docs/account-billing/workspaces). | | **AgentOS** | The runtime layer that gives the AI agent direct OS-level control: keyboard, mouse, screen capture, and system functions. Runs on Windows, macOS, and Linux. | | **Annotation** | A marked region around a UI element with metadata including its name, text content, and bounding box coordinates. | | **Bounding box** | A rectangle defined by coordinates that describes the location and size of a UI element on screen. | | **Companion Mode** | An AgentOS control mode where AgentOS runs on an external device (e.g. Raspberry Pi) and controls the target through hardware interfaces. No software installation on the target is required. | | **Credentials** | The combination of a **workspace ID** and an **access token** for the same workspace. | | **Element** | A graphical user interface component: a button, text field, menu item, image, etc. | | **Host Mode** | An AgentOS control mode where AgentOS runs directly on the target machine and controls it via OS-level APIs. | | **Inference** | The process of sending a screenshot to the AI model to identify and locate UI elements. | | **Project** | A folder structure created by AskUI Desktop containing tests, context files (ui.md, rules.md), procedures, and plans. The unit of work for authoring and running tests. | | **Procedure** | A reusable multi-step sequence (e.g. "log in") stored in `procedures/` and invoked from test steps by name. | | **Run report** | The output of a test run: a Markdown file with a status and screenshot per step. Statuses are `PASSED`, `FAILED`, `WARN`, `SKIPPED`, or `BROKEN`. | | **Workspace** | The account-level container in the AskUI Hub that owns access tokens, usage events, and billing. Every AskUI account belongs to one or more workspaces. | | **Workspace ID** | The unique identifier for a workspace. Used together with an access token to authenticate with the AskUI Hub. | # Network requirements (/docs/reference/network-requirements) Allowlist per **machine role**: the machine that starts runs needs AskUI and the model endpoint, a test machine needs neither. How to use that split as a security boundary: [What the agent may do](/docs/best-practices/security#allowlist-the-domains-nothing-more). ## Outbound, from the machine that starts runs [#outbound-from-the-machine-that-starts-runs] AskUI Desktop and the [CLI](/docs/running-tests/cli) need HTTPS (443) to: | Domain | Purpose | Still needed if… | | ---------------------- | -------------------------------------------- | ------------------------------------------------------------------- | | `auth.askui.com` | Sign-in (OIDC) | Not in [license-key mode](/docs/get-started/licensing) | | `workspaces.askui.com` | Workspace API, access-token validation | Not in license-key mode | | `inference.askui.com` | Model inference through the AskUI hub | Not with [your own model provider](/docs/extending/model-providers) | | `files.askui.com` | Installer and update downloads (release CDN) | Only for installing and updating | With your own provider, that endpoint replaces `inference.askui.com`, your Anthropic account, your Azure AI Foundry resource, or a host inside your own network. With **on-premise inference** no external model domain is needed at all. Desktop's sign-in callback uses the hostname `desktop-auth.askui.com`, which resolves to `127.0.0.1`. No outbound connection is made to it, but the name must be **resolvable**: a DNS setup that blocks unknown external names breaks the callback even though nothing leaves the machine. ## Outbound, from a test machine [#outbound-from-a-test-machine] A machine that only hosts the application under test needs **nothing from this list**. It talks to the application under test; the machine driving the run does the rest. Downloads are the exception, and only until the machine is provisioned: browser bundles for [web profiles](/docs/devices/web-browser), the Android SDK for [emulators](/docs/devices/android-emulator), and NuGet packages for [custom tools](/docs/extending/custom-tools), all resolvable from an internal mirror. ## Inbound [#inbound] | Port | Where | When | | ----- | ------------------------------------------------------------------------------------- | ------------------------------------- | | 23000 | The machine running [AgentOS](/docs/agentos), started by the app | Driving that machine from another one | | 26000 | Same, when AgentOS runs as an [installed service](/docs/agentos/installation/service) | Shared lab machines | Restrict those ports to the machines allowed to start runs. Local runs on a single PC need no inbound rule at all, the connection never leaves the machine. ## Proxy [#proxy] AskUI Desktop is configured **in the app**, under **Settings → Network proxy** (system proxy, manual address with bypass list, NTLM/Kerberos or stored credentials). Setup and what to check when connections fail: [Network proxy](/docs/troubleshooting/network-proxy). ## Air-gapped [#air-gapped] [License-key mode](/docs/get-started/licensing) plus a model endpoint inside your network removes every AskUI domain from the picture. Runtime downloads still need a reachable mirror or pre-provisioned tooling. What that setup looks like end to end: [Enterprise fit](/docs/concepts/enterprise-fit). # Dashboard (/docs/results/dashboard) Where a [run report](/docs/results/run-report) covers a single execution, the **Dashboard** rolls every run in the project into one view, the closest thing to a test execution status report across your whole suite. Open the **Dashboard** page when you want the trend rather than one result. The Dashboard in AskUI Desktop showing total runs, average pass rate, per-status counters, and a test-status-over-time chart Section by section: * **In flight**: what is running or queued right now — green dot running, amber dot queued with the reason it waits. Links to the [Runs page](/docs/running-tests#watch-it-live). Shown only while something is active. * **Upcoming schedules**: the next few [schedules](/docs/running-tests/scheduling) by their due time. Shown only when schedules exist. * **The verdict**: one sentence on the latest run — did it pass, and when. * **Needs attention**: the failing or broken tests of the latest run, each a link into its report. * **Trend**: pass-rate over the recent runs, once there are at least two. * **Recent runs**: the run history, newest first. The numbers derive from each run's [summary report](/docs/results/run-report#summary-report), the counting rules live there. # Runs (/docs/results) Every run is kept: its reports, screenshots, and the complete conversation. The **Runs** page is where you open them. ## Open a run's results [#open-a-runs-results] 1. Open the **Runs** page. 2. Pick the run in the sidebar, newest first, one entry per run with its pass tally. 3. Choose what to look at: * **Conversation log**: the full execution record (below). * **Summary report**: the run-level table, one row per test. * **The per-test entries**: each test's [test report](/docs/results/run-report) with its status badge. **Open in Explorer** on a test jumps to its files on disk, the run's folder is one level up. ## Conversation log [#conversation-log] Beside the written reports, every run keeps its full conversation, each agent message, tool call, and screenshot in order. Where the report gives the result, the log is the complete execution record: open it when a status alone doesn't explain what happened. The conversation log of a finished run, agent messages, tool calls, and screenshots in order Reading it element by element: * **Numbered circle + TEST header**: one phase (setup, a test case, teardown) with its file path, status badge (PASS/FAIL), and how many tool calls it took, this is where you see each test. Expanding a phase reveals a collapsed **System prompt** section, the exact standing instructions the agent received for that phase. * **Text lines**: the agent's narration, what it sees on screen and what it decides to do next. * **Chips**: tool calls, a screenshot, a keystroke, a click, or a named tool like *Save screenshot* / *Write file*, with the result behind it. * **`350 → 26`**: tokens in → out for that step, the cost signal of the run. * **`500ms`**: the step's latency. During a run the same view streams live, [Watch it live](/docs/running-tests#watch-it-live). ## Share results [#share-results] To hand a result to a developer or attach it to a ticket, zip the run's timestamped folder (**Open in Explorer** on a test, one level up), the reports are plain Markdown with the step screenshots next to them, readable anywhere. ## On disk [#on-disk] Each run is one timestamped folder under `agent_workspace/`: ``` /agent_workspace/ └── 2026-07-23_21-56-55/ ← one folder per run ├── conversation.json ← the conversation (the app re-renders it) ├── summary_report.md ← run-level table └── open_notepad_windows/ ← one folder per test ├── open_notepad_windows_report.md ← the test report ├── step_1.png └── step_2.png ``` Run folders are independent of each other, archive or delete old ones as your evidence-retention policy requires; the Runs list and [Dashboard](/docs/results/dashboard) reflect whatever folders exist. The folder is [gitignored](/docs/projects#git-versioning--sync) by design. From the CLI, `--workspace` overrides the location. # Run report (/docs/results/run-report) Two written reports per run, the test report per case and the run-level summary. Where they live and how to open them: [Runs](/docs/results). ## Test report [#test-report] Each test gets its own `_report.md` (with a `step_.png` screenshot for every step), the agent writes it while it executes. It is the primary record of what the agent did, what it expected, and what it actually observed.

Test Case Report: login_test

Test Case ID: login_test
Date: 2025-11-12
Status: WARN

Summary

The agent successfully logged in using the QA credentials and verified the dashboard was shown.

Preconditions

1\. Application is running and the login page is visible.

Test Steps

1. Navigate to the login page , Status: PASSED

  • Agent Interpretation: Opened browser and navigated to the login URL.
  • Expected: Login form visible.
  • Actual: Login form visible with username and password fields.
step_1.png

2. Enter QA credentials and submit , Status: WARN

  • Agent Interpretation: Filled the form using the QA credential secrets.
  • Expected: Dashboard page shown after successful sign-in.
  • Actual: Dashboard loaded with the welcome banner, but only after roughly 15 seconds.
step_2.png

Postconditions

1\. User is signed in and the dashboard is visible.

Issues

Sign-in took about 15 seconds, well above the usual 2–3 seconds. The dashboard did load completely, so step 2 is WARN rather than FAILED, but this is worth watching before it becomes a timeout.

Conclusion

The login flow works, with one caveat: sign-in is unusually slow. Functionally PASSED behaviour, reported as WARN because of the response time.

```markdown # Test Case Report: login_test **Test Case ID:** login_test **Date:** 2025-11-12 **Status:** WARN ## Summary The agent logged in using the QA credentials and verified the dashboard was shown — but sign-in was unusually slow (about 15 seconds). ## Preconditions 1. Application is running and the login page is visible. ## Test Steps 1. **Navigate to the login page** — Status: **PASSED** - **Agent Interpretation:** Opened browser and navigated to the login URL. - **Expected:** Login form visible. - **Actual:** Login form visible with username and password fields. - ![Step 1](step_1.png) 2. **Enter QA credentials and submit** — Status: **WARN** - **Agent Interpretation:** Filled the form using the QA credential secrets. - **Expected:** Dashboard page shown after successful sign-in. - **Actual:** Dashboard loaded with the welcome banner — but only after roughly 15 seconds. - ![Step 2](step_2.png) ## Postconditions 1. User is signed in and the dashboard is visible. ## Issues Sign-in took about 15 seconds — well above the usual 2–3 seconds. The dashboard did load completely, so step 2 is WARN rather than FAILED, but this is worth watching before it becomes a timeout. ## Conclusion The login flow works, with one caveat: sign-in is unusually slow. Functionally PASSED behaviour, reported as WARN because of the response time. ```
Section by section: * **Test metadata**: who, when, and how it went. * **Test Case ID**: ties the report to the [test case](/docs/writing-tests), its title ID or file name. * **Date**: when the test executed. * **Status**: the overall result, the `**Status:**` line is what the [runner parses](/docs/writing-tests/agents-and-prompts#report-format) as the run's result. One of: * `PASSED`, actual result matches expected. * `FAILED`, the step executed but the result didn't match. * `SKIPPED`, intentionally not executed (e.g. precondition not met). * `WARN`, passed, but with a caveat (slow response, minor visual deviation). * `BROKEN`, could not execute: crash or infrastructure failure. The overall status is the worst of the steps: `BROKEN` if any step broke, else `FAILED` if any failed, else `WARN`, else `SKIPPED` if all skipped, otherwise `PASSED`. * **Summary**: the outcome in two sentences, read this first. * **Preconditions**: whether the assumed starting state was actually met, a test that began from the wrong state fails here, not misleadingly in a step. * **Test Steps**: one entry per step. * **Agent Interpretation**: how the agent understood your instruction, check this when a step surprises you. * **Expected** / **Actual**: the step's contract and what was actually observed. * **Status**: the step's own status, same vocabulary as above. * **Screenshot**: the step's evidence (`step_.png`). * **Postconditions**: whether the overall pass criterion held at the end. * **Issues**: anything worth a look that isn't a failure, the incident notes. In the example above: the 15-second sign-in. * **Conclusion**: the agent's closing assessment of the whole case. The report's shape is defined by your project's [report format](/docs/writing-tests/agents-and-prompts#report-format). What to do with a failing report, triage, root cause, where the fix belongs: [Analyzing failures](/docs/best-practices/analyzing-failures). *** ## Summary report [#summary-report] `summary_report.md` in the run folder summarizes the whole run: a totals head (test-case count, per-status counts, run duration), one Markdown table across all tests with status and execution time per test, and detail sections that quote each warned, failed, or broken test's issues from its own report. ```markdown # Summary Report **Date:** 2026-08-06 **Total:** 3 Test Cases - **✅ Passed:** 2 - **❌ Failed:** 1 - **⏱️ Duration:** 00:04:03 | Test Case ID | Test Case Name | Status | Duration | | --- | --- | --- | --- | | login_test | login_test | ✅ Passed | 00:01:12 | | settings_test | settings_test | ✅ Passed | 00:00:48 | | checkout_test | checkout_test | ❌ Failed | 00:02:03 | # ❌ Fails ## checkout_test The pay button never appeared after entering the voucher code. ``` The detail sections carry each test's `## Issues` (else `## Conclusion`) section, so a red run can be triaged from this one document; a test that ran but produced no report reads "No report written". Tests that a [test plan](/docs/writing-tests/plans) selected but the run never reached are listed as `💥 Broken` with a duration of `—`, so nothing goes missing silently. The Dashboard and Runs pages in AskUI Desktop derive their pass/fail counters from this table. `WARN` counts as passed (tracked separately in the warning total). `SKIPPED` tests never executed and are excluded from the total. `BROKEN` tests without an execution time in the summary (tests that never started) are also excluded from the total, they show in the table but don't affect the pass rate. In CI, upload the whole workspace folder as a build artifact so the reports and screenshots stay attached to the run even when tests fail: ```yaml title=".github/workflows/ui-tests.yml" - uses: actions/upload-artifact@v4 if: always() with: name: askui-run path: agent_workspace/ ``` # CLI reference (Coming Soon) (/docs/running-tests/cli) The CLI runs the exact Projects you build in AskUI Desktop. The same `tests/`, `plans/`, `procedures/`, and `utils/` drive both, author in the app, run anywhere with the CLI. See [Install the CLI](/docs/running-tests/install-cli) for setup and authentication. ```bash askui run [] [options] ``` Run from your Project root (or pass `--project-root`). Without arguments, `askui run` executes the whole tests folder against your local desktop (`tests/`, or the folder `askui.json` names as the tests path). ## What a run does [#what-a-run-does] For every test, the agent works in **phases**: the folder's `setup.md` (if present) runs first, then the tests, then `teardown.md`, with any `rules.md` applied throughout. Each phase is one autonomous agent execution that reads the test file, drives the UI, and writes a report with screenshots. When you target a nested folder tree, setups run top-down, teardowns bottom-up, and `rules.*` and `ui.*` accumulate per level, always starting at the tests root, so `tests/rules.md` and `tests/ui.md` apply to every run shape; a failing setup blocks the tests it guards. ### The target [#the-target] | Target | Behavior | | ------------- | ------------------------------------------------------------------------------------------------------- | | *(none)* | Runs the Project's `tests/` folder. | | A folder | Runs every test in the folder recursively, with per-folder setup/teardown lifecycle. | | A single file | Runs one test, its ancestor folders' setups still run first (top-down) and teardowns after (bottom-up). | Relative targets resolve against `--project-root`. Supported test file types: `.txt`, `.md`, `.pdf`, `.csv`, `.json`. ### Test plans [#test-plans] ```bash askui run --plan smoke ``` `--plan ` loads `plans/.yaml`, a [test plan](/docs/writing-tests/plans), and runs exactly the tests it selects, in plan order. The plan's device list is ignored — the CLI runs on the surface its flags configure and prints a note saying so. A plan that selects no tests, or does not exist, is a configuration error (exit code 2). ## Run options [#run-options] | Option | Default | Description | | ---------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- | | `--plan ` | , | [Test plan](/docs/writing-tests/plans) (without extension) from the Project's `plans/` directory; its device list is ignored. | | `--project-root ` | current directory | The Project root (`tests/`, `procedures/`, `plans/`, `utils/`). | | `--workspace ` | `/agent_workspace/` | Output directory for reports, screenshots and the conversation. | ## Surface options [#surface-options] When the project's `devices.json` has exactly one profile matching the surface options, its name and [prompt text](/docs/writing-tests/agents-and-prompts#device-prompt) join the agent's system prompt, the same device knowledge as an in-app run. | Option | Default | Description | | -------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | | `--surface ` | `agent-os` | What the agent drives: `agent-os` (desktop), `web` (browser), or `android`. | | `--controller-host ` | `localhost` | [AgentOS](/docs/agentos) host (`agent-os` only). A local (loopback) AgentOS is started automatically; remote hosts are attached to. | | `--controller-port ` | `23000` | AgentOS gRPC port (`agent-os` only). | | `--display ` | `1` | Display to operate on (`agent-os` only). | | `--device-serial ` | first `adb` device | Android device serial (`android` only). | ```bash # Drive a remote machine's AgentOS on its second display askui run --controller-host 192.168.1.42 --display 2 # Run the suite against a browser askui run --surface web # Run against a specific Android device askui run --surface android --device-serial emulator-5554 ``` ## Model options [#model-options] By default, inference runs through the **AskUI hub**, billed to your workspace and authenticated with `ASKUI_WORKSPACE_ID`/`ASKUI_TOKEN`, nothing to configure. The hub serves more than one model. | Option | Default | Description | | ---------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `--model-provider

` | `askui` | `askui`, `anthropic`, `openai`, or `openai-compatible`. | | `--model-id ` | provider default | The model to use. With `askui`, selects the hosted model, e.g. `gemini-3.5-flash`; default is the workspace's Claude model. | | `--api-key ` | , | API key (BYOM providers only). | | `--endpoint-url ` | , | Custom base/endpoint URL. Required for `openai-compatible`; a URL ending in `/chat/completions` is used as-is, a base URL gets the path appended. | ```bash # Hosted models on the AskUI hub askui run # workspace default (Claude) askui run --model-id gemini-3.5-flash # hosted Gemini # Bring your own model askui run --model-provider anthropic --api-key $ANTHROPIC_API_KEY askui run --model-provider openai-compatible \ --endpoint-url http://localhost:8000/v1 \ --model-id Qwen/Qwen3-VL-30B-A3B-Instruct ``` The agent drives the UI from **screenshots**, so BYOM models must be **vision-capable**: a text-only model will connect but can't see the screen. ## Credentials and `.env` [#credentials-and-env] The CLI loads a `.env` file from the Project root at the start of every run, variables already set in the environment win. This carries the hub credentials (`ASKUI_WORKSPACE_ID`, `ASKUI_TOKEN`) and anything your own [helper tools](#helper-tools) read. Treat access tokens like passwords: in CI, inject them from the secret store instead of committing a `.env` file. See [Workspaces & access tokens](/docs/account-billing/workspaces). ## Helper tools [#helper-tools] The CLI extends the agent with your Project's custom tools: every `*.dll` in `/helpers/` is loaded, and each public tool class in it becomes available to the agent next to the built-in ones. A broken assembly never takes down the run, the problem is reported and the rest keeps loading. ## What a run produces [#what-a-run-produces] Each run gets its own workspace folder (see `--workspace`), containing: * **Per-test artifacts**: `/_report.md` with the result and step-by-step details, plus `step_.png` screenshots. * **`summary_report.md`**: the run at a glance — totals with per-status counts and run duration, one table over all tests with status and duration each, and detail sections quoting every warned, failed, or broken test's issues. Tests a plan selected but the run never reached appear as broken, so nothing goes missing silently. * **`conversation.json`**: the full agent conversation, which AskUI Desktop re-renders as the [conversation log](/docs/results#conversation-log). The console shows each phase as it starts and finishes (`[test] tests/login.md -> PASSED`) and ends with the totals. ## Exit codes [#exit-codes] | Code | Meaning | | ----- | -------------------------------------------------------------------------------------- | | `0` | All executed tests passed. | | `1` | At least one test failed or broke, or the run produced no result. | | `2` | Usage or configuration error (bad flags, missing project/target, unreachable surface). | | `130` | Interrupted (Ctrl+C), partial reports and the summary are preserved. | ## Running in CI [#running-in-ci] The exit codes make `askui run` CI-native: the job fails exactly when tests fail. A minimal GitHub Actions job: ```yaml title=".github/workflows/ui-tests.yml" jobs: ui-tests: runs-on: [self-hosted, askui] # a runner with AgentOS installed env: ASKUI_WORKSPACE_ID: ${{ vars.ASKUI_WORKSPACE_ID }} ASKUI_TOKEN: ${{ secrets.ASKUI_TOKEN }} steps: - uses: actions/checkout@v4 - run: askui run --plan smoke --workspace ./run-artifacts - uses: actions/upload-artifact@v4 if: always() with: name: askui-run path: ./run-artifacts ``` Pin `--workspace` to a fixed path so the artifact upload finds the reports, and upload with `if: always()` so failing runs keep their evidence. For setting up the machine under test, see [AgentOS CI deployment](/docs/agentos/deployment/ci). # Run a test (/docs/running-tests) ## Start a run [#start-a-run] 1. Open the test on the **Tests** page. 2. Pick a connected device in the **Run on** dropdown (see [Devices](/docs/devices)). 3. Press **Run**, or use its split menu to run the whole folder. For a saved multi-test selection, run a [test plan](/docs/writing-tests/plans) from the **Test Plans** page instead. The Run split button with its profile dropdown open, every connected device to pick from A test open on the Tests page with the Run on picker and Run split button ## If it can't start right away [#if-it-cant-start-right-away] A run needs its device to itself, and the app runs at most **two runs in parallel** (on different devices — two runs never share a device). When you press Run and the run cannot start immediately, a dialog asks what to do: * **Queue run**: the run waits its turn and starts automatically as soon as the device is free and a parallel slot opens. A queued run gives up after 30 minutes of waiting, with the reason recorded in its result. * **Don't start**: nothing is queued, nothing runs. Queued runs appear in the Runs sidebar under **Queued**, each with the reason it waits; the ✕ on the row cancels it. Runs started by a [schedule](/docs/running-tests/scheduling) skip the dialog and queue silently. Closing the app discards the queue — you are warned first when anything is still queued or running. ## What a run does [#what-a-run-does] The agent works in phases: the folder's `setup.md` first, then the tests, then `teardown.md`, with `rules.md` applied throughout. Each phase is one agent execution: read the file, drive the UI, write a report with screenshots. A failing setup records its tests as broken, the entry criteria weren't met. ## Watch it live [#watch-it-live] The conversation is the live test execution log, every message, tool call, and screenshot as it happens. Use it to catch unexpected behaviour before the report exists. 1. Open the **Runs** page. 2. Pick the run in the runs sidebar on the left, it lists every run of the project, and **several runs can be active at once**; each streams its own conversation. 3. Follow along, the controls at the top of the conversation: * **Autofollow**: keeps the view pinned to the newest entry while the run streams; scroll up to inspect something and it pauses, click it to snap back. * **Quiet**: just the story: the agent's narration, minimal noise. * **Detailed**: the default: narration plus every tool call with its result, tokens, and latency. * **Raw**: the underlying messages as JSON, for debugging. The Runs page showing an agent conversation with messages, tool calls, and step screenshots ### Reading the conversation [#reading-the-conversation] * **Numbered circle + TEST header**: one phase (setup, a test case, teardown) with its file path, status badge (PASS/FAIL), and how many tool calls it took, this is where you see each test. Expanding a phase reveals a collapsed **System prompt** section, the exact standing instructions the agent received for that phase. * **Text lines**: the agent's narration, what it sees on screen and what it decides to do next. * **Chips**: tool calls, a screenshot, a keystroke, a click, or a named tool like *Save screenshot* / *Write file*, with the result behind it. * **`350 → 26`**: tokens in → out for that step, the cost signal of the run. * **`500ms`**: the step's latency. The same view stays available after the run finishes, see the [conversation log](/docs/results#conversation-log) on the results page. After the run: [read the report](/docs/results/run-report). Recurring runs: [Scheduling](/docs/running-tests/scheduling). Headless / CI: [CLI](/docs/running-tests/cli). # Install the CLI (Coming Soon) (/docs/running-tests/install-cli) The AskUI CLI (`askui`) runs the same Projects you author in AskUI Desktop, without the UI. One command, `askui run`, executes your tests against a desktop, a browser, or an Android device and writes the same reports the app produces. Use it locally for scripted runs, in CI, or on a schedule. **Install the CLI** *(coming soon)* The CLI is **not yet publicly available**, the installer is in progress. This page documents what running it looks like so you can plan your CI setup; the steps below apply once the CLI ships. **Verify the install** ```bash askui --help ``` You should see the `askui run` usage with its options. **Set up the surface you want to drive** Desktop runs need [AgentOS](/docs/agentos) on the machine under test. On your own machine, the CLI **starts a local AgentOS automatically** for the run; if AgentOS is installed as a [service](/docs/agentos/installation/service), the CLI detects and attaches to it instead. For a remote machine, install AgentOS there and point the CLI at it with `--controller-host`. Nothing to install up front: on the first `--surface web` run, the CLI downloads the browser it drives (Chromium via Playwright) automatically. `adb` must be on your `PATH` and the device (or emulator) visible to `adb devices`. See the [ADB setup guide](/docs/agentos/deployment/local#android-setting-up-adb). **Authenticate** With the default model provider (the AskUI hub), the CLI reads two environment variables: ```bash export ASKUI_WORKSPACE_ID="" export ASKUI_TOKEN="" ``` Create the access token in the [AskUI Hub](https://hub.askui.com), see [Workspaces & access tokens](/docs/account-billing/workspaces). Instead of exporting, you can also put both lines in a `.env` file in your Project root; the CLI loads it on every run (variables already set in the environment win). **Run a Project** ```bash cd my-project askui run ``` See [Running from the CLI](/docs/running-tests/cli) for the full command reference, test plans, surfaces, model selection, and CI usage. # Scheduling (/docs/running-tests/scheduling) A schedule runs a test or [test plan](/docs/writing-tests/plans) without you pressing Run. A test runs on the device profile you pick in the dialog; a plan runs on the device recorded in the plan. A scheduled run whose device is busy [queues silently](/docs/running-tests#if-it-cant-start-right-away) and starts when the device is free. Schedules fire only while AskUI Desktop is running, it is not a background service. Close the app, or let the machine sleep or shut down, and the scheduled run silently does not happen: no firing, no report, and no catch-up when the app comes back. For runs that must never be missed, the nightly regression, use the [CLI](/docs/running-tests/cli) on a build server with your CI scheduler. ## Manage all schedules in one place [#manage-all-schedules-in-one-place] The **Runs** page's sidebar has two views, **Runs** and **Schedules**. The Schedules view lists every schedule of the project permanently, each with an on/off toggle, a pencil to edit its cadence, and delete. The **+** button creates a new one: pick any plan or test of the project in **What to run**. The Dashboard shows the next few upcoming schedules at a glance. ## Create a schedule [#create-a-schedule] 1. Open the test on the **Tests** page (or the plan on **Test Plans**). 2. Click the alarm-clock button, the **Scheduled runs** dialog opens, prefilled with this file. 3. Pick the **Device profile** (for a plan this step disappears, the plan's own devices are used). 4. Pick the **Cadence**: **Daily at a time** (with weekdays) or **Every N minutes**. 5. Click **Add schedule**. The Scheduled runs dialog with device profile, cadence, and the project's schedule list The dialog lists every schedule in the project with its last outcome, the run's results, or why it was skipped (e.g. the device could not connect). Schedules live in the project's `schedules.json`. A due schedule never double-fires, even when a run outlasts its interval. ## Pause or delete a schedule [#pause-or-delete-a-schedule] The dialog lists every schedule in the project: 1. Untick the **on** checkbox to pause a schedule, it stays configured but stops firing (the row dims). 2. Click the trash button (**Delete schedule**) to remove it. There is no edit: to change the cadence or device, delete the schedule and add it again. # Get help (/docs/support/get-help) ## Before reaching out [#before-reaching-out] Working through these steps first usually resolves the issue faster than opening a ticket: **Check the run report.** Open the failing run's report and look at the step that failed. The screenshot and status (`FAILED` vs `BROKEN`) usually point directly at the problem. See [Reading a run report](/docs/results/run-report). **Check the troubleshooting guide.** The most common AgentOS and connectivity issues are documented in [Troubleshooting](/docs/troubleshooting). ## Diagnostic report [#diagnostic-report] We are building a diagnostic tool that automatically checks your system configuration, installed versions, network connectivity, AgentOS reachability, environment variables, and more, and writes a structured report. You will be able to send this report directly to support so we can tell you exactly what is wrong, for example why a remote AgentOS cannot be reached. ## What to include in a bug report [#what-to-include-in-a-bug-report] A good bug report gets you a faster answer. Include: * **AskUI Desktop version**: shown in the app's About screen * **Operating system and version**: e.g. Windows 11 22H2, macOS 14.4 * **Steps to reproduce**: the exact sequence of actions that causes the issue * **Expected behavior**: what should happen * **Actual behavior**: what actually happens, including any error messages * **The run report**: the `.md` file or a screenshot of the failing step * **AgentOS logs** (for AgentOS issues), see [Logs](/docs/troubleshooting#logs) ## Contact channels [#contact-channels] | Channel | Best for | Response time | | ----------------------------------------------- | ------------------------------- | -------------------- | | [support@askui.com](mailto:support@askui.com) | Bug reports, technical issues | 24-48 business hours | | [feedback@askui.com](mailto:feedback@askui.com) | Feature requests, docs feedback | - | Mark your email subject **URGENT** for critical production issues. ## Enterprise support [#enterprise-support] Enterprise customers have access to: * A dedicated support channel * Priority response times * Direct access to the engineering team * Custom onboarding and training sessions Contact your account manager to activate enterprise support. ## Status and known issues [#status-and-known-issues] * **Service status:** [status.askui.com](https://status.askui.com) * **Security and compliance:** [trust.askui.com](https://trust.askui.com) * **GitHub issues:** [github.com/askui](https://github.com/askui) ## Community resources [#community-resources] * [YouTube](https://youtube.com/@askui), tutorials and walkthroughs * [Blog](https://blog.askui.com), product updates and deep-dives # Support (/docs/support) Answers to common questions about platform support, pricing, security, and on-premise options. How to report bugs, what to include, and where to reach the team and community. Step-by-step fixes for common AgentOS and connectivity issues. ## Status and trust [#status-and-trust] | Resource | Link | | -------------------------------------- | -------------------------------------------- | | Service status | [status.askui.com](https://status.askui.com) | | Security and compliance (Trust Center) | [trust.askui.com](https://trust.askui.com) | ## Contact [#contact] | Channel | Use for | | ----------------------------------------------- | ------------------------------------------- | | [support@askui.com](mailto:support@askui.com) | Bug reports and technical issues | | [feedback@askui.com](mailto:feedback@askui.com) | Feature requests and documentation feedback | # AgentOS service issues (Windows) (/docs/troubleshooting/agentos-service) The steps on this page apply to AgentOS running as a **Windows system service** . For standalone mode on macOS or Linux, check the terminal output for errors. ### Restart the AgentOS service [#restart-the-agentos-service] Many issues are resolved by restarting the service. To restart it via Task Manager: 1. Open **Task Manager** (`Ctrl+Shift+Esc`). 2. Switch to the **Services** tab (the puzzle-piece icon). 3. Search for **`AskuiCoreService`**. 4. Right-click the entry and choose **Restart**. ### Agent can't press CTRL+ALT+DEL [#agent-cant-press-ctrlaltdel] The login/lock screen cannot be automated unless the local security policy allows services to simulate a Secure Attention Sequence (SAS). To enable it: 1. Open the **Group Policy Editor** (`gpedit.msc`). 2. Navigate to **Computer Configuration → Administrative Templates → Windows Components → Windows Logon Options**. 3. Set **Disable or enable software Secure Attention Sequence** to **Enabled**. Also verify that `SERVICE_ENABLE_SAS` is set to `1` (default) in the [Silent installer parameters](/docs/agentos/installation/silent/#parameters). The service includes a `windows.forceSas` option that overrides group policies. This is **not recommended** as it may trigger system integrity checks. Configure the GPE policy instead. ### Agent can't interact with apps running as Administrator [#agent-cant-interact-with-apps-running-as-administrator] Windows prevents non-elevated processes from sending input to elevated (Run as Administrator) applications. If your agent can't click or type into an app running as Administrator, you need to start the Remote Device Controller in elevated mode. To enable elevated mode: * **Service Installer (GUI)**: Open **Windows Add/Remove Programs**, find AskUI AgentOS, click **Modify**, and enable the elevated execution engine option. Alternatively, reinstall AgentOS with the option enabled. * **Silent Installer**: Set `SERVICE_EXECUTION_ENGINE_ELEVATED` to `1`, see [Silent installer parameters](/docs/agentos/installation/silent/#parameters). Running the execution engine elevated grants it higher privileges. Only enable this when you need to automate applications that run as Administrator. ### `ipv4:127.0.0.1:23000 unavailable` in Standalone mode [#ipv412700123000-unavailable-in-standalone-mode] If the client fails to connect with an error like `ipv4:127.0.0.1:23000 unavailable` while running in **Standalone** runtime mode, autostart of the local AgentOS instance is likely disabled. Check the `ASKUI_CONTROLLER_CLIENT_SERVER_AUTOSTART` environment variable, if it is set to `false`, the client will not start AgentOS automatically and there is nothing listening on port `23000`. Either unset the variable or set it to `true`: ```powershell $env:ASKUI_CONTROLLER_CLIENT_SERVER_AUTOSTART="true" ``` ```bash export ASKUI_CONTROLLER_CLIENT_SERVER_AUTOSTART=true ``` This variable is intentionally set to `false` when connecting to a remote AgentOS instance, see [Remote Windows VM](/docs/agentos/deployment/ci/#remote-windows-vm). ### Need to reinstall or remove [#need-to-reinstall-or-remove] **Do not** stop or remove the service from Windows Services manually. Always **uninstall the full AskUI AgentOS application** via Windows Add/Remove Programs. This ensures proper cleanup so the client falls back to standalone mode. # Connection & sessions (/docs/troubleshooting/connection-sessions) ### Connection error or session mismatch at run start [#connection-error-or-session-mismatch-at-run-start] Connection errors and session mismatches happen when AgentOS and Desktop have lost sync, most often after a machine restart or sleep cycle. **Correct restart order for multi-machine setups:** 1. Restart AgentOS on the target machine(s) first. 2. Then reconnect from AskUI Desktop. If the error persists, use the **Restart** button on the Devices page in the Desktop sidebar to force a clean session reset. If the problem recurs after restarts, check whether the target machine received a new IP address from DHCP, see the entry below. ### Tests won't start after a reboot or power outage [#tests-wont-start-after-a-reboot-or-power-outage] Work through this checklist: 1. **Verify all services are running.** Open the Devices page in AskUI Desktop and confirm every connected machine shows a green status. 2. **Check for IP address changes.** DHCP can reassign addresses after a restart, breaking a stored connection. Use hostnames instead of static IPs wherever possible. 3. **Look for stale configuration.** Old connection settings in your project or workspace config may point to a previous address. Update or remove them and re-add the device. ### Run stops when RDP session is disconnected or screen is locked [#run-stops-when-rdp-session-is-disconnected-or-screen-is-locked] * **Remote Desktop (Windows), session disconnect:** Disconnecting an RDP session suspends the virtual display. AgentOS in Host Mode loses its view of the screen and the run ends. Either keep the RDP session connected and the window visible during the run, or run AgentOS as a **system service** so it operates independently of the interactive session, see [Running as a service](/docs/agentos/installation/service). * **Remote Desktop (Windows), window minimized:** Minimizing the RDP client window (`mstsc`) simulates a display disconnect on the remote machine. The Remote Device Controller loses access to the display and may return empty screenshots or shut down. To prevent this, set a registry value on the machine running the RDP client: Open `regedit`, navigate to `HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Terminal Server Client`, and create a `DWORD` value named `RemoteDesktop_SuppressWhenMinimized` with data `2`. * **Locked screen:** A locked session hides the display on both Windows and macOS. Either keep the machine unlocked during unattended runs, or use a virtual display tool that persists across lock events. For fully unattended CI scenarios, the recommended setup is AgentOS as an OS service, see [CI/CD integration](/docs/agentos/deployment/ci). # Troubleshooting (/docs/troubleshooting) Session mismatches, post-reboot failures, RDP and locked-screen issues. Wrong clicks, screen misinterpretation, and runs stopping mid-test. Unexpected cost increases and slow or crashing long runs. Restarting the service, CTRL+ALT+DEL, elevated apps, and port errors. Configuring the proxy AskUI Desktop uses, and what to check when connections fail. Debugging FAILED and BROKEN statuses, and runs that produce no results. 429, 401, 403, 404, connection refused, and vision-model errors for BYOM. *** ## Logs [#logs] The AskUI Core Service and the Remote Device Controller write to two separate locations. For most issues, collect logs from **both**: **Remote Device Controller** (runs in the interactive user session): ``` %userprofile%\.askui\Logs ``` **AskUI Core Service** (runs as SYSTEM): ``` C:\Windows\System32\config\systemprofile\.askui\logs ``` # Misclicks & stuck runs (/docs/troubleshooting/misclicks-and-stuck-runs) ### Agent clicks the wrong element or misses small buttons [#agent-clicks-the-wrong-element-or-misses-small-buttons] Vague element descriptions are the most common cause. Make descriptions specific: * **Use spatial anchors:** "the button in the bottom-right corner, below the Save dialog" is far more reliable than "the button". * **Include distinguishing features:** label text, color, icon shape, or position relative to a unique landmark on the screen. * **For very small targets:** explicitly instruct the agent to zoom before acting, for example, "zoom in on the toolbar area, then click the small red X icon". See [Prompting best practices](/docs/best-practices/prompting-best-practices) for a full guide on writing reliable element descriptions. ### Agent misinterprets a screen state [#agent-misinterprets-a-screen-state] The agent has no built-in knowledge of your application's UI. Add that knowledge to your project's `tests/ui.md`. Describe screens the agent commonly confuses, loading overlays, login walls, modal dialogs, error banners. Example: ``` A grey semi-transparent overlay with a spinner in the centre means the page is loading. Wait for it to disappear completely before taking any action. ``` See [Agents and prompts](/docs/writing-tests/agents-and-prompts) for the full prompt structure. ### Agent stops in the middle of a long test [#agent-stops-in-the-middle-of-a-long-test] Each run has a step limit that prevents runaway executions. If a test hits that limit, it ends with status `BROKEN`. To avoid this: * **Extract procedures:** move repeated sequences (e.g. "log in") into `procedures/` and call them by name from your tests. * **Split large tests:** break a long end-to-end flow into smaller focused test cases, each with its own clear goal. See [Project structure](/docs/projects) for how procedures and test files are organised. # Model provider errors (/docs/troubleshooting/model-providers) These errors appear when AskUI Desktop tests your API credentials on save, or during a run when the model provider rejects a request. They only apply when you have configured a [custom model provider](/docs/extending/model-providers). ### 429 Too Many Requests [#429-too-many-requests] **What it means:** You've sent too many requests to the AI provider in a short time. Their system is temporarily blocking new requests. Each provider (Anthropic, OpenAI, etc.) limits how many requests you can make per minute. A test suite that runs many tests back-to-back can hit this limit quickly. **What to do:** 1. Wait a few minutes, then try again, the limit resets automatically. 2. Check your quota in your provider's console: * Anthropic: [console.anthropic.com](https://console.anthropic.com) → Usage * OpenAI: [platform.openai.com](https://platform.openai.com) → Usage 3. If this happens regularly, upgrade to a higher usage tier with your provider. 4. Alternatively, switch back to the **AskUI hub** (Settings → Account → Model Provider → Remove key), the hub handles rate limits automatically. ### 401 Unauthorized [#401-unauthorized] **What it means:** The API key you entered is wrong, was typed incorrectly, or has been revoked. **What to do:** 1. Go to **Settings → Account → Model Provider** and check the key you entered. 2. Generate a fresh key in your provider's console and paste it in, don't type it by hand. 3. Make sure you copied the full key. Keys are long strings and it's easy to miss characters at the start or end. ### 403 Forbidden [#403-forbidden] **What it means:** Your API key is valid, but your account doesn't have permission to use this model or feature. Some models (e.g. Claude, GPT-5.4) require a paid plan or explicit access request. **What to do:** 1. Log in to your provider's console and check whether your plan includes API access to the model you selected. 2. Try a different model that's included in your current plan, or switch back to the AskUI hub. ### 404 Not Found / Model not found [#404-not-found--model-not-found] **What it means:** The model ID you entered doesn't exist, or was typed incorrectly. Model IDs are case-sensitive and must match exactly. **What to do:** 1. Go to **Settings → Account → Model Provider** and check the **Model** field. 2. Copy the exact model ID from your provider's documentation: * Anthropic: [docs.anthropic.com/models](https://docs.anthropic.com/en/docs/about-claude/models/overview) * OpenAI: [platform.openai.com/docs/models](https://platform.openai.com/docs/models) ### Connection refused / Could not connect to server [#connection-refused--could-not-connect-to-server] **What it means:** AskUI Desktop tried to reach your model's endpoint but got no response. Either the address is wrong or the server isn't running. Most common with self-hosted models (vLLM, Ollama, llama.cpp). **What to do:** 1. Make sure your local model server is running before starting a run. 2. Check the **Base URL** in **Settings → Account → Model Provider**, it should look like `http://localhost:8000/v1`. Confirm the port matches what your server uses. 3. If connecting to a remote server, check that it's reachable on your network and no firewall is blocking the port. ### The agent can't see the screen (text-only model) [#the-agent-cant-see-the-screen-text-only-model] **What it means:** The model you configured is text-only. It can't process screenshots, so the agent can't see the UI it's supposed to test. **What to do:** Switch to a **vision-capable** model: * Anthropic: any Claude 3 or later model * OpenAI: `gpt-5.4`, `gpt-5.4-mini` * Self-hosted: Qwen-VL, LLaVA, InternVL, or similar vision models # Network proxy (/docs/troubleshooting/network-proxy) The proxy is configured **in the app**: 1. Open **Settings → Network proxy**. (During license setup, the same form is in the wizard under **Behind a proxy? Configure network access**.) 2. Choose the **Proxy** mode: * **Use system proxy (recommended)**: the Windows proxy/PAC configuration applies. * **Manual proxy address**: enter the fields: * **Proxy address**: e.g. `http://proxy.corp.example:8080` * **Bypass for**: hosts reached directly, separated by semicolons (e.g. `*.corp.example; 10.0.0.*`). Localhost is always bypassed. * **No proxy (direct connection)**. 3. Choose **Proxy authentication**: * **Automatic (recommended)**: if the proxy asks for sign-in (HTTP 407), your current OS account answers automatically (NTLM / Kerberos). No password is stored, and nothing is sent unless the proxy actually asks. * **Username and password**: stored encrypted on this machine; it never leaves it. * **Never authenticate**. ### Connections still fail [#connections-still-fail] 1. Check the internet connection first, an interrupted connection produces the same errors as a blocked one. 2. Confirm the domains AskUI needs are reachable through the proxy: [Network requirements](/docs/reference/network-requirements). 3. If they are allowlisted and it still fails, your network is doing something to the traffic that needs your IT team, [get in touch](/docs/support/get-help) and we will work it out with them. # Performance & cost (/docs/troubleshooting/performance-cost) ### Run cost increased unexpectedly [#run-cost-increased-unexpectedly] Common drivers: | Driver | What to check | | ------------------------ | --------------------------------------------------------------------------------------------------------------------------- | | Oversized images or logs | Very large screen captures or log files raise the token count per step. | | Retry loops | A failing step the agent retries many times multiplies cost. Look for high step counts on single actions in the run report. | Open the run report and check the token count per step, the costliest steps are usually the ones to optimize. For a cross-run view, see the [Usage dashboard](/docs/account-billing/usage-dashboard). ### Run got slower or crashed during a very long execution [#run-got-slower-or-crashed-during-a-very-long-execution] Log and trace files grow continuously over a run. Very large files can exhaust memory or significantly slow the host machine. Mitigations: * Keep test cases short and focused, split a large suite into smaller cases, each producing its own report. * Archive or delete old run folders under `agent_workspace/` in your project periodically. * If a run must be long, monitor disk and memory usage on the AgentOS host and set up log rotation if your OS supports it. # Run failures (/docs/troubleshooting/run-failures) ### Debugging a failing run [#debugging-a-failing-run] The fastest way to debug a failing run: 1. Open the run report (the `.md` file in your project's workspace folder, or inline in AskUI Desktop). 2. Find the first step with status `FAILED` or `BROKEN`, that is where to focus. 3. Check the screenshot for that step. `FAILED` means the expected outcome didn't match; `BROKEN` means an infrastructure problem (connection lost, session expired) stopped the run. 4. For AgentOS issues, check the [logs](/docs/troubleshooting#logs) for more detail. If you cannot resolve the issue yourself, see [Get help](/docs/support/get-help) for how to generate a diagnostic report and contact support. ### Run completes with 0 results ("No tests ran") [#run-completes-with-0-results-no-tests-ran] The run started but found no test files to execute. 1. Check that you're running from the correct **Project root**, the folder that contains `tests/`, `plans/`, etc. 2. Check that your test files are inside `tests/` and have a supported extension (`.md`, `.txt`, `.pdf`, `.csv`, `.json`). 3. If you used `--plan`, check that the plan file exists in `plans/` and references valid test paths. # The system prompt (/docs/writing-tests/agents-and-prompts) The system prompt is what you'd tell a new tester on day one, standing instructions the agent gets before every run. Each part lives where it belongs, versioned with your testware: | Part | Lives in | You edit it? | | --------------------------------- | ------------------------------------ | ----------------------------------------- | | Capabilities and error discipline | Built into the app | No, it keeps runs honest | | Device prompt | Each device profile (`devices.json`) | Only when the machine has quirks | | UI information | `tests/ui.md` | Yes, the file you invest the most in | | Report format | `utils/format.md` | When your reporting needs differ | | Rules | `tests/rules.md` (and per suite) | Yes, your rules override everything above | ## Capabilities [#capabilities] The agent's identity and its error discipline are built in and not editable. The defaults are deliberately strict: > You have a maximum of **2 attempts per step**. If a step does not succeed > after 2 attempts, stop immediately. Do not try a third time. Two conventions the agent relies on: **Credentials** never live in a test. A step references a [named secret](/docs/extending/secrets); the agent types a placeholder and the real value is substituted at execution time, hidden from the model. \ **Scratchpad**: the agent can persist notes across phases with the scratchpad tools, but only when a test explicitly instructs it to. When the built-in behaviour doesn't fit your suite, don't look for a file to edit, write a [rule](#rules): rules are appended last and take precedence over the built-in instructions on conflicts. ## Device prompt [#device-prompt] Machine quirks the agent can't see for itself live on the device profile, keep it small. The agent already sees the screen, so OS and display basics rarely need describing. 1. Open **Devices** and click **Edit** on the profile. 2. Fill the **Prompt** field: ```markdown * Always execute on display 1. * The corporate lock screen appears after 5 minutes of inactivity. ``` The text is stored with the profile in `devices.json` and goes into the system prompt of every run on that device. Retargeting a project at a different machine means picking a different profile, its prompt travels with it. ## UI information [#ui-information] `tests/ui.md`, where the agent learns your application, the domain knowledge that lets a [colleague without domain knowledge](/docs/writing-tests/step-constructs) execute your tests. The default ships as placeholders: ```markdown ## Navigation The application has these primary areas: Dashboard, Records, Settings… ## State indicators "Login state is shown top-right: a green dot means signed in, red means the session expired — sign in again." ## Dialogs & quirks "Destructive actions open a centered confirmation dialog that must be confirmed or dismissed before continuing." ``` This is also where you steer **how** the agent operates your UI, "enter numbers via the on-screen numpad, never the keyboard" ([more](/docs/writing-tests/step-constructs#beyond-steps)). A suite that tests a different part of the system can carry its own `ui.md`: like `rules.md`, the files accumulate top-down, the top-level `tests/ui.md` first, then each folder's on the way to the test. `ui.md` is never executed as a test, the Tests page marks it **Context only**. ## Report format [#report-format] `utils/format.md`, the template for every report the agent writes: title, **Test Case ID**, date, status, and the per-step sections. Edit it under **Extending → Report Format**, it applies to all runs of the project. Two parts are load-bearing: * The **`**Status:**` line is parsed by the runner** to set the run's result, remove it and a passing test is recorded as BROKEN. * The status definitions (PASSED / FAILED / SKIPPED / WARN / BROKEN) are the [status vocabulary](/docs/results/run-report#test-report) your reports and Dashboard use. Customize the sections when your organization needs different evidence, keep the `**Status:**` line. ## Rules [#rules] `tests/rules.md` holds your standing corrections, appended at the very end of the system prompt behind an explicit note that **your rules take precedence** where they conflict with anything above. Instructions that apply to one suite only go into that folder's [rules.md](/docs/writing-tests/setup-teardown-rules#rules); the files accumulate top-down at run time. ## Checking what the agent got [#checking-what-the-agent-got] Every run records the exact system prompt per phase: open the run's conversation log and expand the **System prompt** section under an act header. What you read there is what the agent read. ## Upgrading an older project [#upgrading-an-older-project] Projects created before this layout carry a `prompts/` folder. Opening one shows the **Migrate Project** dialog: 1. Click **Migrate**. `ui_information.md` becomes `tests/ui.md`, `report_format.md` becomes `utils/format.md`, and the folder is renamed to `prompts_legacy/`, nothing is deleted, existing files are never overwritten. 2. If you had customized `system_capabilities.md`, the dialog offers to append **your additions** (not the standard text) to `tests/rules.md`, where they keep working, and now take precedence. 3. Text you wrote in `device_information.md` is not migrated automatically: copy it into the device profile's **Prompt** field on the Devices page. The original stays in `prompts_legacy/`. **Not now** dismisses the dialog for this project; the legacy files are simply no longer read. # Test cases (/docs/writing-tests) Test cases live as files under `tests/` and are managed on the **Tests** page: on the left the file tree with all test cases, on the right the editor with the opened test case and its Run controls. The Tests page with the file tree, an open test, and the Run controls ## The concepts [#the-concepts] Six building blocks make up everything you author: All of it lives in one [Project](/docs/projects), plain files, shared via Git. A **suite** frames its test cases with [setup, teardown, and rules](/docs/writing-tests/setup-teardown-rules); how suites nest and scope chains is on [Organisation & Scope](/docs/writing-tests/organisation). Cases and setups call [procedures](/docs/writing-tests/procedures) for repeated sequences, and reference [secrets](#use-secrets-in-a-test) instead of containing credentials. [Test plans](/docs/writing-tests/plans) select which cases run together, and on which device. ## Create a test case [#create-a-test-case] A test case is one file: preconditions, steps with expected results, postconditions. The file name is the test's name in runs and reports. 1. Right-click in the file tree → **New Markdown** (or **New CSV**). 2. Name the file and fill the seeded template. How to phrase steps well: [Writing good tests](/docs/best-practices/writing-good-tests). The file tree's right-click menu with New Markdown, New CSV, New folder, and the quick-create entries for setup, teardown, and rules The same menu holds everything on this page: creating files and folders, the quick-create entries for setup / teardown / rules, **Run on**, and **Duplicate / Rename / Delete**. ### Anatomy & formats [#anatomy--formats] Every test case has the same three parts, preconditions, steps, postconditions, whatever the file format: ```md title="tests/example_login_test.md" # Login Flow · Smoke Test ## Preconditions - No user is currently logged in ## Steps 1. Log in using the `login_to_ui` procedure with the QA secrets 2. Wait until the start screen loads ## Postconditions - Test passes if the signed-in indicator is visible ``` ```csv title="tests/example_test_data.csv" Test case ID,Test case name,Precondition,Step number,Step description,Expected result LOGIN_001,Valid login,App is open on the login screen,1,Enter the QA credentials into the login form,Both fields are filled ,,2,Click the Login button,The start screen is visible and the user is signed in ``` ```json title="tests/login_001.json" { "id": "LOGIN_001", "name": "Valid login", "preconditions": ["App is open on the login screen"], "steps": [ { "action": "Enter the QA credentials into the login form", "expected": "Both fields are filled" }, { "action": "Click the Login button", "expected": "The user is signed in" } ] } ``` **Preconditions**: the state the test *assumes*, not work to perform: which screen is open, which user is logged out, which data exists. The agent checks them before the first step and records whether they were met; a test whose preconditions aren't met is reported `SKIPPED` instead of producing a misleading step failure, because it never ran. Shared preparation work belongs in [setup](/docs/writing-tests/setup-teardown-rules), not here. **Steps**: numbered actions, each paired with what to expect. The agent executes them one at a time: perform the action, compare what it observes against the step's expected result, record both with a screenshot. Each step becomes an expected-vs-actual entry in the [run report](/docs/results/run-report), so a step without an expected result is a step the report can't judge. Everything a step can express, conditions, waits, checks, procedure calls, is on [Step constructs](/docs/writing-tests/step-constructs). **Postconditions**: the overall pass criterion, phrased as a checkable end state: "Test passes if …". The agent judges it after the last step, independent of which path it took to get there. The case's reported status is the worst of its steps ([how it is derived](/docs/results/run-report#test-report)). These templates are starting points, not schemas, the agent reads a test the way a tester would, so you're free to choose your own structure. `.md` holds one case per file, `.csv` one case per **row** (data-driven testing), and `.json`, `.txt`, or `.pdf` exports from a test-management tool run as-is. New to Markdown? The [Markdown Guide](https://www.markdownguide.org/basic-syntax/) covers the syntax in ten minutes. ### Target multiple platforms [#target-multiple-platforms] A first line `platforms: desktop, android` marks a case cross-platform, it then runs only on a [Cross-platform profile](/docs/devices/cross-platform), and single-platform tests never run there. The steps name the surface, like a [multi-computer test](/docs/devices/multi-computer) names machines. Cross-platform profiles connect and report status, but runs against them are not supported yet, the case is ready for when they are. ## Use secrets in a test [#use-secrets-in-a-test] Never write credentials into a case, reference [named secrets](/docs/extending/secrets) by name instead. Add the value once under **Extending → Secrets**; the agent sees only the name, and the real value is substituted at execution time, redacted from logs and reports: ```md Sign in with the QA credentials — the secrets named `QA_USERNAME` and `QA_PASSWORD`. ``` ## Run a test case [#run-a-test-case] 1. Pick a connected device in **Run on**. 2. Press **Run**, or right-click any file or folder → **Run on** → a profile. Details in [Running a test](/docs/running-tests). ## Manage a test case [#manage-a-test-case] All of it is plain file operations via right-click, visible in Git like any other change to your [testware](/docs/projects). ### Duplicate [#duplicate] 1. Right-click the file → **Duplicate**. 2. Rename the copy, it's the starting point for a similar case. ### Rename [#rename] 1. Right-click the file → **Rename**. 2. Enter the new name. The file name is the test's name in runs and reports; reports of old runs keep the old name. ### Delete [#delete] 1. Right-click the file → **Delete**. ### Skip [#skip] There is no skip flag: to leave a case out temporarily, run a [test plan](/docs/writing-tests/plans) that doesn't select it, or move the file out of `tests/`. # Organisation & Scope (/docs/writing-tests/organisation) Two rules build the whole structure: **a file is a test case, a folder is a suite**, and suites nest, so the tree mirrors your test structure plan: | Entry | What it is | | ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `login_test.md` | A single test case, the file name is the test's name in runs and reports | | `user_matrix.csv` | Also test cases, one per row; every [format](/docs/writing-tests#anatomy--formats) sits side by side in the same tree | | `checkout/` | A suite: its cases run together, framed by the suite's own `setup.md` and under its own `rules.md` **in addition to** the outer one. Nest deeper for sub-suites | | `user-management/` | A sibling suite, no steering files of its own, so only the root ones apply. Suites are independent: a failing `checkout/setup.md` never touches it | | `rules.md`, `setup.md`, `teardown.md` | [Steering files](/docs/writing-tests/setup-teardown-rules), allowed at **every** level, each scopes to its folder and everything below | ## Scope [#scope] The steering files reach downward, never sideways. In the tree above, `tests/checkout/pay_with_card.md` runs framed by `tests/setup.md` *and* `tests/checkout/setup.md`, and rules **accumulate**: the root `tests/rules.md` applies to every phase, `tests/checkout/rules.md` adds the suite's own rules on top, but only inside `tests/checkout/`. `tests/user-management/create_user.md` gets only the root files. Setups run top-down, teardowns bottom-up, pressing **Run** on the `checkout` suite: A failing setup blocks exactly the tests below it; sibling suites are unaffected. Any level can be a run target: one file, one suite, or the whole tree, folder structure is also your run granularity. # Test plans (/docs/writing-tests/plans) A test plan is your test selection: which cases run together, and on which device. The classic examples, a fast `smoke` set for every change, the full regression pack for the release, a nightly suite. A plan is a yaml file in `plans/`. You never write it by hand — you check tests and pick a device on the **Test Plans** page and the file is written for you — but it reads (and diffs) like this: ```yaml title="plans/smoke.yaml" version: 1 tests: - tests/login/ - tests/checkout/happy_path.md devices: - id: a1b2c3 ``` * **`tests`**: the selection, in execution order. An entry ending in `/` is a whole folder — it is expanded when the run starts, so a test added to the folder later is included without touching the plan. * **`devices`**: the device the plan runs on, by profile id from `devices.json` (a list in the file, one entry via the app). Only the id is stored — the app shows the device's current name, so renaming a device never touches your plan files. The run contains exactly what the plan lists. Nothing infers the selection, and a plan that selects no tests cannot be run. ## Create a plan [#create-a-plan] 1. Open **Test Plans** and click **New test plan**. A dialog opens. 2. Type a name, for example `smoke`. 3. Check tests in the tree: individual files, a folder to include everything in it, or **All tests** to run the whole project. Files inside a checked folder show as included; uncheck the folder to pick them individually. 4. Pick the device the plan targets. Every profile from the [Devices page](/docs/devices) is offered — the device does not need to be connected while you edit, only when the plan runs. 5. Click **Create plan**. The plan is saved as `plans/smoke.yaml` (the folder is created with the first plan). The page lists each plan with its test count and device; the pencil on a row reopens the dialog. A plan change shows up in review as a small yaml diff, like the rest of your testware. ## Run a plan [#run-a-plan] Press **Run** on the plan. A run starts on the plan's device and executes every selected test — no further input. It appears on the **Runs** page; runs on the same device queue behind each other. The button is disabled while the plan selects no tests or no device, with the reason in the tooltip. If the plan's device is busy (or the two-runs limit is reached), a dialog asks whether to [queue the run](/docs/running-tests#if-it-cant-start-right-away). Two things to know about how a plan run reports: * A selected test the run never reaches is listed as `BROKEN` in the [run report](/docs/results/run-report) — selected means accounted for. * A plan entry whose file was renamed or deleted is skipped with a notice in the conversation log; the run continues with the rest. You can also run a plan headless with [`askui run --plan smoke`](/docs/running-tests/cli) — the CLI runs the selection on the device its flags configure and ignores the plan's device list — or on a [schedule](/docs/running-tests/scheduling), which runs it on the plan's device the same way. ## If a device disappears [#if-a-device-disappears] A plan remembers its device by profile id. When the referenced profile no longer exists, the plan's row says so and the edit dialog shows the orphaned id with a remove button — pick a new device and the plan runs again. ## Older prose plans [#older-prose-plans] Plans used to be free-form Markdown files that an agent interpreted at run time. Those files are no longer runnable and no longer appear on the Test Plans page (they stay on disk until you delete them). Recreate the selection as a test plan — the checkboxes cover what the prose described. # Procedures (/docs/writing-tests/procedures) A procedure is a parameterized, reusable block of steps, the same idea as a keyword in keyword-driven testing. When the login screen changes, you fix the procedure once; every test that calls it picks the fix up. ## Define it [#define-it] The **Procedures** button on the Tests page creates a file in `procedures/` from a template: ```md title="procedures/login_to_ui.md" # Login to the UI # Parameters: [username, password] 1. Enter the value of {username} into the username field 2. Enter the value of {password} into the password field 3. Click the "Login" button 4. The procedure is successful if you are logged in ``` * The **file name** is the name tests call: `login_to_ui`. * The `# Parameters: [...]` line declares the inputs; steps reference them as `{username}`, `{password}`. * The last step states when the procedure counts as successful. ## Use it [#use-it] Call it as a single step from any test, or from a suite's [setup](/docs/writing-tests/setup-teardown-rules), in plain language: name the procedure and say what fills its parameters; a [secret](/docs/extending/secrets) is passed by name: ```md 1. Log in using the `login_to_ui` procedure with the QA username and password secrets. 2. Wait until the start screen loads ``` What belongs in a procedure versus a test step: [What goes where](/docs/best-practices/prompting-best-practices). # Setup, Teardown & Rules (/docs/writing-tests/setup-teardown-rules) Every suite folder can carry three steering files. Their [scope chains per folder level](/docs/writing-tests/organisation#scope); each quick-create seeds a starter template, adjust it to your application, keep the shape. ## Setup [#setup] The suite's entry criteria: open the application, log in, reset data. Runs once, before any case in its folder, a failing setup records the suite's cases as broken instead of executing them against a bad state. **Create it:** right-click the folder → **New setup.md**. ```md title="setup.md" ## Setup Steps 1. Open the application under test and wait until it is fully visible. 2. Log in using the `login_to_ui` procedure with the QA username and password secrets. 3. Verify the start screen has loaded before any test starts. ``` ## Teardown [#teardown] The suite's cleanup: sign out, delete created records. Runs last, after every case in its folder, even after failures. **Create it:** right-click the folder → **New teardown.md**. ```md title="teardown.md" ## Teardown Steps 1. Close the application under test. 2. Clear any temporary files created during testing. ``` ## Rules [#rules] Standing instructions that apply to every phase in the folder, not a test, context: interaction style, error handling, things never to do ("never change the language setting", "treat error dialogs as failures"). **Create it:** right-click the folder → **New rules.md**. ```md title="rules.md" # Execution rules for this folder ## Interaction - Use the desktop computer to execute these tests. ## Error handling - On an infrastructure error (connection lost, session expired): mark the testcase BROKEN, write the report, abort. - On an application error: mark the testcase FAILED and abort. ``` # Step constructs (/docs/writing-tests/step-constructs) Steps are plain language, not syntax. Imagine handing the test to a human colleague **without domain knowledge about your application**: whatever they would need from you to execute it, which element, what to expect, what to do if a dialog appears, what never to touch, is exactly what the agent needs. If that colleague could run the step from your wording alone, so can the agent. These constructs are the vocabulary that works, each example is from a real seeded test. They apply wherever steps live: in [test cases](/docs/writing-tests), in [setup and teardown](/docs/writing-tests/setup-teardown-rules), and inside [procedure](/docs/writing-tests/procedures) bodies. ## Actions [#actions] Describe intent; the agent works out the clicks and keystrokes: ```md 1. Open the Start menu, type `Notepad`, and press Enter. ``` ## Locators [#locators] Describe a UI element the way you'd point it out to a colleague, by any visible feature, combined freely: | Kind | Example | | ------------ | ----------------------------------------------------------------------------------- | | **Text** | Click the button labeled **"Save"** | | **Icon** | Click the **gear icon** in the toolbar | | **Color** | Click the **green** Connect button | | **Location** | The search field **at the top right** | | **Relation** | The Delete button **next to** the second list entry, the field **below** "Username" | The more distinguishing features, the more reliable the step, "click the button" fails on a screen with ten buttons; "the green Connect button on the Windows Desktop card" doesn't. Phrasing guidance: [Writing good tests](/docs/best-practices/writing-good-tests). ## Expectations [#expectations] Pair every action with what must be true afterwards, that pair becomes the step's expected-vs-actual entry in the [report](/docs/results/run-report): ```md 2. Click the Login button — the start screen is visible and the user is signed in. ``` ## Verifications [#verifications] A step can be pure checking: ```md 3. Verify the response status is 200 and the body contains "Example Domain". 4. Check whether `tests/example_test_data.csv` exists (expect yes). ``` ## Conditions [#conditions] Because the agent [reads the screen before every step](/docs/concepts/test-automation-harness#why-execution-differs), steps can branch on what is actually there: ```md 5. If the result says more rows are available, call it again with the suggested offset — otherwise continue. 6. If a cookie banner appears, dismiss it before continuing. ``` Bigger decisions read best as sub-steps, one branch per letter, each with its own expected result: ```md 7. Check whether a window named "AskUI Desktop" is already open: a. If yes: bring it to the front — the app window is focused. b. If no: open the Start menu, search for "AskUI Desktop" and start it — the app window opens within a minute. ``` ## Optional [#optional] A step that only applies in some situations, and whose absence is **not** a failure. Say what to do when the situation doesn't occur, so the report shows SKIPPED instead of FAILED: ```md 8. If the tutorial overlay is shown on first start, dismiss it — otherwise mark this step SKIPPED and continue. 9. Suppress pop-ups throughout: whenever a "Rate this app" pop-up appears, close it and continue — if none appears, that's fine. ``` ## Waits [#waits] Normally you don't need waits, the agent sees the screen and won't act on a half-loaded page. When it gets impatient anyway, tell it **what to look for**, not how long to wait: ```md 10. Wait until the start screen loads. ``` A fixed duration is the last resort, for settling you can't describe: ```md 11. Wait 3 seconds for the page to settle. ``` ## Timeouts [#timeouts] The counterpart of a wait: bound how long the agent keeps trying, and say what happens when time is up, otherwise a hanging application under test turns into an endlessly patient agent: ```md 12. Start the export. If the success message does not appear within about 2 minutes, mark the step FAILED and continue with the next test. ``` Timeouts are approximate, the agent judges elapsed time between screenshots, it doesn't run a stopwatch. For hard behavior on errors and hangs that applies to every test, use [rules.md](/docs/writing-tests/setup-teardown-rules#rules). ## Raising errors [#raising-errors] Tell the agent to fail **actively** when the application doesn't react as expected, an agent that helpfully works around a defect masks exactly what the test exists to find: ```md 13. Open the customer record ACME-42. If an error dialog appears instead, mark the test FAILED and stop — do NOT retry or work around it. ``` Use the [status vocabulary](/docs/results/run-report#test-report): **FAILED** when the application misbehaves, **BROKEN** for infrastructure problems (connection lost, session expired). The seeded [rules.md](/docs/writing-tests/setup-teardown-rules#rules) already sets this policy for every test, a step-level instruction sharpens it for a specific known risk. ## Dynamic values [#dynamic-values] Values that only exist at run time, an ID the application generates, a number shown on screen, can be noted in one step and referenced in a later one; the agent carries what it saw through the whole test: ```md 14. Create a new user — note the user ID shown in the confirmation dialog. 15. Open the user list and click the entry with the user ID noted in step 12. ``` The seeded cross-platform example uses the same pattern across devices: read the most recent order number on the desktop, then search for exactly that number on the phone. ## Iteration [#iteration] A step can repeat over what's on screen, "for every …" across lists, tabs, table rows: ```md 16. For every tab in the Settings dialog: open it and verify it loads without an error message. ``` The loop body can hold several sub-steps, the same lettered pattern as conditions. Keep the set bounded: ```md 17. For the first 3 orders in the list: a. Open the order — the detail view shows its order number. b. Verify the order contains at least one line item. c. Add the comment "checked by QA" and save — the comment appears in the order history. d. Return to the order list — it shows the same rows as before. ``` The agent has to keep count on a screen that changes with every action, long or unbounded iterations drift. Keep the set small and verifiable ("all 4 tabs"), and when the elements are known up front, prefer one [data-driven CSV case per element](/docs/writing-tests#anatomy--formats) instead of a loop. This is a limitation of today's models and improves with every model generation, expect the caution to relax over time. ## Exclusions [#exclusions] Say explicitly what must **not** happen, the agent honors prohibitions like a tester honors a warning in the test spec: ```md 18. Click **Submit** exactly once — do NOT press it again, even if the page seems to hang. 19. Do NOT dismiss the license dialog; the test verifies its content first. ``` For prohibitions that apply to every test in a folder ("never change the language setting", "never sign out"), put them in [rules.md](/docs/writing-tests/setup-teardown-rules#rules) instead of repeating them per step. ## Comments [#comments] HTML comments are notes for maintainers, why a step exists, a ticket reference, a review hint. They are not steps: ```md ``` The agent reads comments as background, not instructions, but it does read them, so keep them truthful: a stale or misleading comment can steer execution the same way a misleading remark steers a colleague. The seeded templates use comments exactly this way. ## Procedure calls [#procedure-calls] One step runs a whole [procedure](/docs/writing-tests/procedures), name it and say what fills its parameters: ```md 20. Log in using the `login_to_ui` procedure with the QA username and password secrets. ``` ## Secrets [#secrets] Reference credentials by name, never by value, [secrets](/docs/extending/secrets): ```md 21. Sign in with the QA credentials — the secrets named `QA_USERNAME` and `QA_PASSWORD`. ``` ## Tool invocations [#tool-invocations] Steps can name anything the [toolbox](/docs/extending/tools) allows, HTTP requests, SQL statements, shell scripts, QR scanning. Describing the action is usually enough; when two tools could match, name the tool explicitly: ```md 22. Perform an HTTP GET request to `https://example.com`. 23. Scan the QR code from the screen — the decoded text contains "wikipedia". 24. Use the `sql_database` tool to run the statement `test_data`. ``` Tool names are listed under **Extending → Tool Store**, each card carries the name the agent knows it by. A [custom tool](/docs/extending/custom-tools)'s name is the `name:` in its C# file. ## Targeting machines and platforms [#targeting-machines-and-platforms] In a [multi-computer](/docs/devices/multi-computer) test, name the machine per step; a `platforms:` first line marks a [cross-platform case](/docs/writing-tests#target-multiple-platforms): ```md 25. On the **server**, start the message service. 26. On the **client**, send a message to the server. ``` ## Beyond steps [#beyond-steps] Some things don't belong in any step, they're the manual tester's tribal knowledge, and they have their own homes. **Real-world disruptions.** Some failures are random and expected: the application hangs, the printer is empty, a product is out of stock. A manual tester doesn't fail the test, they restart the app, ignore the printer, refill the quantity, and carry on. Give the agent the same recoveries in [rules.md](/docs/writing-tests/setup-teardown-rules#rules), at the [scope](/docs/writing-tests/organisation#scope) that needs them: ```md title="tests/rules.md" ## Recoveries - If the application hangs, restart it and repeat the current step once. - If the printer reports empty, ignore the print result and continue. - If a product is out of stock, set its quantity to 10 in inventory first. ``` **The agent operates the UI differently than you wish.** It uses keyboard shortcuts where your users click menus, types numbers instead of using the on-screen numpad, keeps misreading the same part of your UI. That's not a step problem either, teach it the house style in [rules.md](/docs/writing-tests/setup-teardown-rules#rules) or, when it's about how your application works, in the [UI information file](/docs/writing-tests/agents-and-prompts#ui-information): ```md title="tests/ui.md" - Enter numbers via the on-screen numpad with mouse clicks — never type them with the keyboard. - Do not use keyboard shortcuts; this application is tested through its menus, like our users work. ``` What belongs where in detail: [What goes where](/docs/best-practices/prompting-best-practices). # CI pipeline examples (/docs/agentos/deployment/ci-examples) CI execution needs the AskUI CLI, which is not publicly available yet. This page describes the setup you will use once it ships, so you can plan for it. These examples show how to run `askui run` in the most common CI environments. All examples assume: * The AskUI Desktop installer has been run on the CI machine (or a self-hosted runner with AskUI installed), since the CLI ships with the Desktop installer. * `ASKUI_WORKSPACE_ID` and `ASKUI_TOKEN` are stored as CI secrets. * Your test project is checked into the repository. Desktop automation on Windows requires AgentOS running as a service. Install it via the AskUI Desktop installer on your runner before running the pipeline. See [CI/CD integration](/docs/agentos/deployment/ci) for setup details. ## GitHub Actions [#github-actions] ```yaml # .github/workflows/askui.yml name: AskUI Tests on: push: branches: [main] pull_request: jobs: test: runs-on: windows-latest # or macos-latest for macOS desktop / web steps: - name: Checkout uses: actions/checkout@v4 - name: Run AskUI tests env: ASKUI_WORKSPACE_ID: ${{ secrets.ASKUI_WORKSPACE_ID }} ASKUI_TOKEN: ${{ secrets.ASKUI_TOKEN }} run: askui run - name: Upload run reports if: always() uses: actions/upload-artifact@v4 with: name: askui-reports path: agent_workspace/ ``` ## GitLab CI [#gitlab-ci] ```yaml # .gitlab-ci.yml askui-tests: stage: test tags: - windows # use a self-hosted runner with AskUI installed variables: ASKUI_WORKSPACE_ID: $ASKUI_WORKSPACE_ID ASKUI_TOKEN: $ASKUI_TOKEN script: - askui run artifacts: when: always paths: - agent_workspace/ expire_in: 7 days ``` ## Azure DevOps [#azure-devops] ```yaml # azure-pipelines.yml trigger: - main pool: vmImage: windows-latest # or a self-hosted agent with AskUI installed steps: - checkout: self - script: askui run displayName: Run AskUI tests env: ASKUI_WORKSPACE_ID: $(ASKUI_WORKSPACE_ID) ASKUI_TOKEN: $(ASKUI_TOKEN) - task: PublishBuildArtifacts@1 condition: always() inputs: pathToPublish: agent_workspace/ artifactName: askui-reports ``` ## Connecting to a remote AgentOS [#connecting-to-a-remote-agentos] If your CI runner is not the machine being automated (e.g. a Linux runner automating a separate Windows VM), disable AgentOS autostart and point the CLI at the remote instance: ```bash export ASKUI_CONTROLLER_CLIENT_SERVER_AUTOSTART=false export ASKUI_CONTROLLER_CLIENT_SERVER_ADDRESS=:26000 askui run ``` See [Remote Windows VM](/docs/agentos/deployment/ci#remote-windows-vm) for the full setup. ## Storing credentials [#storing-credentials] Never hardcode `ASKUI_WORKSPACE_ID` or `ASKUI_TOKEN` in your pipeline files. Use your CI platform's secret store: | Platform | Where to add secrets | | -------------- | ----------------------------------------------------- | | GitHub Actions | Repository Settings → Secrets and variables → Actions | | GitLab CI | Settings → CI/CD → Variables | | Azure DevOps | Pipeline → Edit → Variables | Create a dedicated access token per pipeline so you can rotate or revoke individual pipelines without affecting others. See [Workspaces](/docs/account-billing/workspaces). # CI/CD Integration (/docs/agentos/deployment/ci) You're running agents unattended in a pipeline or on remote infrastructure. The install method depends on whether you need OS service capabilities (RDP resilience, SYSTEM privileges) or standalone mode is sufficient. ## Windows VM [#windows-vm] Run automation directly on a Windows VM that is part of your CI/CD pipeline. AgentOS runs as an OS service with SYSTEM privileges. **When to use:** Your CI runner *is* the Windows machine you want to automate. **Install:** [Service](/docs/agentos/installation/service) on the VM. AskUI Desktop or the CLI and AgentOS both run on the same VM. The OS service ensures automation continues even if no user is logged in or the RDP session disconnects. ## Remote Windows VM [#remote-windows-vm] Automate a Windows VM from a separate CI runner. AskUI Desktop or the CLI runs on the CI runner and connects to AgentOS on the remote VM over the network. **When to use:** Your CI runner is Linux/macOS but you need to automate a Windows desktop. Or your pipeline orchestrates work across multiple machines. **Install:** [Service](/docs/agentos/installation/service) on the remote VM. During installation, set **Connection Scope** to **Public (0.0.0.0)**. The default Private (127.0.0.1) only accepts local connections and will prevent the client from reaching AgentOS over the network. The client connects to AgentOS over the network via gRPC. The OS service on the remote VM handles desktop control independently, RDP disconnects, logon screens, and headless operation are all supported.

Connecting to a remote AgentOS By default, AskUI Desktop and the CLI start a local AgentOS instance. To connect to a remote VM instead, disable autostart and point the client to the remote address. **Disable local autostart** Set `ASKUI_CONTROLLER_CLIENT_SERVER_AUTOSTART` to `false` so the client doesn't start a local AgentOS instance. ```powershell $env:ASKUI_CONTROLLER_CLIENT_SERVER_AUTOSTART="false" ``` ```bash export ASKUI_CONTROLLER_CLIENT_SERVER_AUTOSTART=false ``` **Set the remote address** Point `ASKUI_CONTROLLER_CLIENT_SERVER_ADDRESS` to the AgentOS service on the remote VM. Replace `192.168.1.100` with your VM's IP address. ```powershell $env:ASKUI_CONTROLLER_CLIENT_SERVER_ADDRESS="192.168.1.100:26000" ``` ```bash export ASKUI_CONTROLLER_CLIENT_SERVER_ADDRESS=192.168.1.100:26000 ``` **Verify the connection** Run your agent. The client should connect to the remote AgentOS instance instead of starting a local one. Check that the remote VM's port `26000` is reachable from your CI runner.
## macOS / Linux CI Runner [#macos--linux-ci-runner] Run automation on a macOS or Linux CI runner. AgentOS runs in standalone mode. **When to use:** Your CI pipeline runs on macOS or Linux and you want to automate the desktop on that same runner. **Install:** [AskUI Desktop installer](/docs/get-started/install-desktop) (includes AgentOS). A standalone installer for CI use is coming soon. Same as local development, AgentOS runs in standalone mode alongside your test code. Ensure the CI runner has a display (real or virtual) available. ## Mobile Device in CI [#mobile-device-in-ci] Automate Android or iOS devices connected to your CI runner via USB. **When to use:** Mobile testing in your pipeline, the device is physically connected to the CI runner. **Install:** [AskUI Desktop installer](/docs/get-started/install-desktop) (includes AgentOS) on the CI runner. A standalone installer is coming soon. AgentOS runs on the CI runner and communicates with the connected device over USB. The CI runner needs physical USB access to the device (or a USB-over-network solution). ### Android: Setting up ADB [#android-setting-up-adb] ADB (Android Debug Bridge) must be available on your PATH. ADB works with both physical devices and emulators. See Google's guide on [running apps on the Android Emulator](https://developer.android.com/studio/run/emulator) to get started with emulators. **Download SDK Platform Tools** Download from [developer.android.com](https://developer.android.com/tools/releases/platform-tools) and unzip to a folder (e.g. `C:\platform-tools` or `~/platform-tools`). **Add to PATH** Add the unzipped folder to your **User** or **System PATH** environment variable. **Verify** Open a new terminal and run: ```bash adb version ``` You should see the ADB version output. ### iOS: Setting up IDB (macOS only, experimental) [#ios-setting-up-idb-macos-only-experimental] iOS automation requires macOS with Xcode and the Facebook IDB companion. IDB currently only works with **iOS Simulators**, not physical devices. This feature is **experimental**. See Apple's guide on [running your app in Simulator](https://developer.apple.com/documentation/xcode/running-your-app-in-simulator-or-on-a-device) to get started. **Install Xcode with iOS Simulators** Install [Xcode](https://developer.apple.com/xcode/) from the App Store and configure iOS Simulators. Verify they are visible: ```bash xcrun xctrace list devices ``` **Install IDB companion** ```bash brew tap facebook/fb brew install idb-companion ``` **Verify** Open a new terminal and run: ```bash idb_companion --list 1 ``` You should see your available simulators or devices listed. # Local Development (/docs/agentos/deployment/local) You're building and testing agents on your own machine. In all local scenarios, AgentOS is installed via the AskUI installer, and AskUI Desktop and the CLI connect to the local AgentOS instance over gRPC. ## Desktop [#desktop] Automate the desktop on your own Windows, macOS, or Linux machine. AgentOS runs in standalone mode alongside your agent code. **When to use:** Day-to-day development, debugging, and interactive testing. **Install:** [AskUI Desktop installer](/docs/get-started/install-desktop) (includes AgentOS) → [Standalone](/docs/agentos/installation/standalone) Your agent code and AgentOS run on the same machine. AskUI Desktop and the CLI send commands via gRPC, and AgentOS translates them into OS-level actions, screenshots, keyboard input, mouse control. ## Mobile Device [#mobile-device] Automate an Android or iOS device connected to your machine via USB. **When to use:** Mobile app testing, device interaction during development. **Install:** [AskUI Desktop installer](/docs/get-started/install-desktop) (includes AgentOS) → [Standalone](/docs/agentos/installation/standalone) AgentOS acts as a bridge: it receives commands via gRPC and forwards them to the connected device using ADB (Android) or IDB (iOS). The device stays connected via USB. You only need one of ADB or IDB depending on your target device, both are shown for completeness. ### Android: Setting up ADB [#android-setting-up-adb] ADB (Android Debug Bridge) must be available on your PATH. ADB works with both physical devices and emulators. See Google's guide on [running apps on the Android Emulator](https://developer.android.com/studio/run/emulator) to get started with emulators. **Download SDK Platform Tools** Download from [developer.android.com](https://developer.android.com/tools/releases/platform-tools) and unzip to a folder (e.g. `C:\platform-tools` or `~/platform-tools`). **Add to PATH** Add the unzipped folder to your **User** or **System PATH** environment variable. **Verify** Open a new terminal and run: ```bash adb version ``` You should see the ADB version output. ### iOS: Setting up IDB (macOS only, experimental) [#ios-setting-up-idb-macos-only-experimental] iOS automation requires macOS with Xcode and the Facebook IDB companion. IDB currently only works with **iOS Simulators**, not physical devices. This feature is **experimental**. See Apple's guide on [running your app in Simulator](https://developer.apple.com/documentation/xcode/running-your-app-in-simulator-or-on-a-device) to get started. **Install Xcode with iOS Simulators** Install [Xcode](https://developer.apple.com/xcode/) from the App Store and configure iOS Simulators. Verify they are visible: ```bash xcrun xctrace list devices ``` **Install IDB companion** ```bash brew tap facebook/fb brew install idb-companion ``` **Verify** Open a new terminal and run: ```bash idb_companion --list 1 ``` You should see your available simulators or devices listed. ## KVM (External Hardware) [#kvm-external-hardware] Control a target device through physical hardware connections, keyboard/mouse via USB or Bluetooth, screen capture via HDMI. **When to use:** The target device can't have software installed on it (locked-down environments, embedded systems, kiosks). **Install:** [AskUI Desktop installer](/docs/get-started/install-desktop) (includes AgentOS) → [Standalone](/docs/agentos/installation/standalone) This is [Companion Mode](/docs/agentos/understanding/control-modes#companion-mode): AgentOS simulates keyboard and mouse input over USB or Bluetooth HID, and captures the target's screen via an HDMI-to-USB capture device. No software installation on the target is required. # Multi-Device Setups (/docs/agentos/deployment/multi-device) You need to automate across multiple targets, desktops, VMs, mobile devices, or hardware. In multi-device setups, AskUI Desktop and the CLI connect to **each AgentOS instance separately** via gRPC. There is no AgentOS-to-AgentOS communication. ## Windows + Mobile Device [#windows--mobile-device] Automate a Windows desktop and a mobile device from the same pipeline. **When to use:** Cross-platform testing, e.g., a web app on Windows and its companion mobile app. The client manages two independent gRPC connections: one to the AgentOS OS Service on the Windows VM, and one to a local AgentOS instance that controls the mobile device. ## Multiple Windows VMs [#multiple-windows-vms] Scale desktop automation across several Windows VMs in parallel. **When to use:** Running the same tests across different Windows configurations, or distributing a large test suite across machines for faster execution. Each VM runs its own AgentOS OS Service. The client connects to all of them independently. Your pipeline code decides which commands go to which VM. ## Multiple Mobile Devices [#multiple-mobile-devices] Automate several Android (or iOS) devices connected to the same machine. **When to use:** Testing across different device models, screen sizes, or OS versions in parallel. Each device gets its own AgentOS instance. The client connects to each one over gRPC and routes commands to the right device. ## Desktop + KVM Device [#desktop--kvm-device] Combine software-based desktop control with hardware-based control of an external device. **When to use:** Testing interactions between a desktop application and a physical device that can't have software installed (e.g., an embedded system, kiosk, or industrial controller). Two AgentOS instances run on the same machine, each in a different [control mode](/docs/agentos/understanding/control-modes): one controls the local desktop (Host Mode), the other controls the external device through hardware (Companion Mode). The client connects to both independently. # Enterprise Features (/docs/agentos/reference/enterprise) AgentOS is designed for enterprise environments that require security controls, audit capabilities, and compliance features. ## Security & Compliance [#security--compliance] | Feature | Status | Description | | ------------------------ | --------- | ---------------------------------------------------------------------------------------- | | Signed binaries | Available | Code-signed installers and binaries, no SmartScreen or Execution Policy bypasses needed. | | Application whitelisting | Planned | Restrict which applications AgentOS can interact with. | | Filesystem whitelisting | Planned | Restrict filesystem paths AgentOS can access. | | Audit logs | Planned | Detailed logs of all actions taken by AgentOS for compliance and forensics. | | Application logs | Planned | Structured application-level logging for monitoring. | | Network scanning | Planned | Visibility into network activity originating from AgentOS. | ## Support [#support] | Feature | Status | Description | | ----------------- | ------- | ------------------------------------------------------- | | Dedicated support | Planned | Priority support channel for enterprise customers. | | Vulnerability SLA | Planned | Guaranteed response times for security vulnerabilities. | ## Connectivity [#connectivity] | Feature | Status | Description | | -------------- | ------- | ---------------------------------------------------------- | | P2P connection | Planned | Direct peer-to-peer connections between AgentOS instances. | | Video stream | Planned | Real-time video streaming of the controlled desktop. | | File stream | Planned | File transfer including log file streaming. | ## Industry Protocols [#industry-protocols] Integration with industrial communication standards for factory automation, IoT, and embedded testing. | Protocol | Status | Description | | ------------------------ | ------- | ----------------------------------------------------- | | CAN bus | Planned | Automotive and industrial controller area network. | | OPC | Planned | Classic OPC for industrial data exchange. | | OPC UA | Planned | Modern OPC Unified Architecture. | | MQTT | Planned | Lightweight messaging for IoT devices. | | Zigbee | Planned | Low-power wireless for smart devices. | | Serial (RS-232 / RS-485) | Planned | Serial communication for legacy and embedded devices. | ## Test Bench (Extended Testing Devices) [#test-bench-extended-testing-devices] Physical hardware integration for automated test setups. | Device | Status | Description | | ------------------------ | ------- | ----------------------------------------------- | | Relay control (Ethernet) | Planned | Switch power or signals via Ethernet relays. | | Relay control (USB) | Planned | Switch power or signals via USB relays. | | SwitchBot / Fingerbot | Planned | Physical button pressing via robotic actuators. | | Bluetooth dongle | Planned | Bluetooth connectivity for test devices. | | Wi-Fi dongle | Planned | Wi-Fi connectivity for test devices. | | Workbench integration | Planned | Full test bench orchestration. | # System Requirements (/docs/agentos/reference/system-requirements) ## Operating System Requirements [#operating-system-requirements] * **Windows**: Windows 10 version 1511+ (64-bit), Windows 11 (64-bit), Windows Server 2019/2022/2025 (64-bit) * **macOS**: macOS 10.15 (Catalina) or newer * **Linux**: Ubuntu 18.04 or newer ### Supported Windows Versions [#supported-windows-versions] #### Windows 10 [#windows-10] | Version | Name | Supported | | ------- | -------------------- | --------- | | 1511 | November Update | x64 | | 1607 | Anniversary Update | x64 | | 1703 | Creators Update | x64 | | 1709 | Fall Creators Update | x64 | | 1803 | April 2018 Update | x64 | | 1809 | October 2018 Update | x64 | | 1903 | May 2019 Update | x64 | | 1909 | November 2019 Update | x64 | | 2004 | May 2020 Update | x64 | | 20H2 | October 2020 Update | x64 | | 21H1 | May 2021 Update | x64 | | 21H2 | November 2021 Update | x64 | | 22H2 | October 2022 Update | x64 | #### Windows 11 [#windows-11] | Version | Name | Supported | | ------- | ---------------- | --------- | | 21H2 | Original Release | x64 | | 22H2 | 2022 Update | x64 | | 23H2 | 2023 Update | x64 | | 24H2 | 2024 Update | x64 | | 25H2 | 2025 Update | x64 | #### Windows Server [#windows-server] | Version | Channel | Supported | | ------- | -------------- | --------- | | 2019 | LTSC | x64 | | 2022 | LTSC | x64 | | 2025 | LTSC | x64 | | 23H2 | Annual Channel | x64 | ## Hardware Requirements [#hardware-requirements] ### Minimum Specifications [#minimum-specifications] * **Memory**: 8 GiB RAM * **CPU**: 4 CPU cores ### Companion Mode (Additional) [#companion-mode-additional] * **USB port** for HID input or device connection (ADB/IDB) * **Bluetooth** adapter for wireless HID input (optional) * **HDMI capture device** (USB) for screen capture (optional) ## Software Requirements [#software-requirements] AgentOS is installed via the AskUI installer and has no separate software prerequisites. # Capabilities (/docs/agentos/understanding/capabilities) AgentOS provides a set of capabilities for controlling machines. What's available depends on the [control mode](/docs/agentos/understanding/control-modes) and [runtime mode](/docs/agentos/understanding/runtime-modes) you use. ## Desktop Control [#desktop-control] | Capability | Host Mode | Companion Mode | Description | | --------------------------- | --------- | ----------------------------------- | ----------------------------------------------- | | Screenshots | Available | Available (via HDMI capture) | Capture the current screen state. | | GPU-accelerated screenshots | Available | , | Take screenshots on GPU for better performance. | | Keyboard input | Available | Available (via USB / Bluetooth HID) | Simulate key presses and combinations. | | Real Unicode typing | Available | , | Native Unicode input (not clipboard-based). | | Mouse input | Available | Available (via USB / Bluetooth HID) | Click, move, drag, and scroll. | | Multi-display support | Available | , | Interact with multiple monitors. | | Window management | Available | , | Select, resize, move, and focus windows. | | Process management | Available | , | Start, stop, and monitor OS processes. | | Automation recovery | Available | , | Recover automatically from display changes. | | CLI | Available | , | Enhanced command-line interface. | ## Windows Service (OS Service Mode Only) [#windows-service-os-service-mode-only] These capabilities require AgentOS to be installed as a [Windows service](/docs/agentos/installation/service). | Capability | Status | Description | | ----------------------------- | --------- | ----------------------------------------------------- | | SYSTEM-level service | Available | Run as a Windows service with SYSTEM privileges. | | RDP disconnect recovery | Available | Keep automation running when RDP sessions disconnect. | | Login screen automation | Available | Interact with the Windows logon screen. | | Secure Attention Sequence | Available | Send CTRL+ALT+DEL programmatically. | | Background session automation | Available | Automate sessions that are not in the foreground. | | Multi-user session control | Planned | Control multiple user sessions on the same machine. | | Virtual display | Planned | Create virtual displays for headless environments. | ## Mobile Devices [#mobile-devices] | Capability | Status | Description | | ------------- | ------------ | ------------------------------------ | | ADB (Android) | Available | Control Android devices via USB. | | IDB (iOS) | Experimental | Control iOS Simulators (macOS only). | ## Hardware (Companion Mode Only) [#hardware-companion-mode-only] | Capability | Status | Description | | --------------------------- | --------- | ------------------------------------------------------- | | HID over USB | Available | Simulate keyboard and mouse via USB connection. | | HID over Bluetooth | Available | Simulate keyboard and mouse via Bluetooth. | | Screenshot via media stream | Available | Capture screen output via HDMI-to-USB dongle or webcam. | | Raspberry Pi support | Planned | Use a Raspberry Pi as the companion device. | ## Platform Support [#platform-support] | Platform | Host Mode | Companion Mode | | -------------------- | --------- | ----------------------------------- | | Windows 10 22H2+ | Available | , | | Windows 11 | Available | , | | Windows Server 2019+ | Available | , | | Windows 10 \< 22H2 | Available | , | | macOS | Available | , | | Linux | Available | , | | Android | , | Available (ADB) | | iOS | , | Experimental (IDB, Simulators only) | ## Future [#future] | Capability | Status | Description | | ---------------------- | ------- | --------------------------------------------------- | | C# API | Planned | Native C# interface for .NET integrations. | | Future automation APIs | Planned | Integration with emerging OS automation frameworks. | # Concepts (/docs/agentos/understanding/concepts) AgentOS has three core concepts that determine what it can do and how it connects to a target machine. While they involve OS-level services, kernel drivers, and hardware interfaces, **you don't need to understand these internals to use AgentOS**, the installer handles the complexity. AgentOS is **platform independent**, Windows, macOS, Linux, Android, and iOS Simulators (experimental), so the same configuration works across operating systems. ## Control modes [#control-modes] Control modes define **how AgentOS connects to the target machine**: * **Host Mode**: AgentOS runs directly on the target as software, using OS-level APIs for screenshots, input, and window management. The most common setup. * **Companion Mode**: AgentOS runs on a separate device and controls the target through hardware (USB, Bluetooth, HDMI capture) or device bridges (ADB, IDB). No software installation on the target is needed. [Learn more about Control Modes →](/docs/agentos/understanding/control-modes) ## Runtime modes [#runtime-modes] Runtime modes define **how AgentOS runs on the machine it's installed on**: * **Standalone**: runs as a regular process in the user's session. Best for local development and testing. * **OS Service**: runs as a system service with elevated privileges. Best for CI/CD, headless VMs, and enterprise deployments. Runtime mode is independent of control mode, both Host and Companion mode can run Standalone or as an OS Service. Higher privileges unlock additional capabilities such as RDP resilience and access to the Windows logon screen. [Learn more about Runtime Modes →](/docs/agentos/understanding/runtime-modes) ## Capabilities [#capabilities] Both control modes expose the same **capabilities** to the agent: screen reading (screenshots, pixel and element access), input simulation (mouse, keyboard, gestures), and window/process management. The agent uses these as building blocks regardless of how AgentOS is connected to the target. [Learn more about Capabilities →](/docs/agentos/understanding/capabilities) AgentOS is the runtime. You drive it through [AskUI Desktop](/docs/get-started/install-desktop) and the [CLI](/docs/running-tests/cli), no separate SDK required. # Control Modes (/docs/agentos/understanding/control-modes) AgentOS operates in two control modes that determine *how* it connects to and controls a target machine. Both modes expose the same core concepts (screenshots, input, automation), but the connection method differs. ## Host Mode [#host-mode] AgentOS runs directly **on the target machine** as software. It controls the desktop via OS-level APIs. * Agent code and AgentOS run on the same machine (or connect over the network). * Full access to OS-level features: window management, process control, multi-display support. * Can run as a [Windows service](/docs/agentos/installation/service) for SYSTEM privileges, RDP resilience, and logon screen control. * Supports Windows, macOS, and Linux. **Best for:** Desktop automation, CI/CD pipelines, enterprise VMs. ## Companion Mode [#companion-mode] AgentOS runs on an **external device** and controls the target through hardware interfaces. No software needs to be installed on the target. * Input is sent via USB or Bluetooth HID (keyboard and mouse emulation). * Screen capture happens via HDMI-to-USB capture devices. * Mobile devices are controlled via ADB (Android) or IDB (iOS, planned). **Best for:** Locked-down environments, embedded systems, kiosks, mobile devices, and any target where you cannot install software. ## Comparison [#comparison] | | Host Mode | Companion Mode | | ------------------------ | --------------------- | -------------------------------------------------------------------- | | **Where AgentOS runs** | On the target machine | On an external device | | **Connection to target** | OS-level APIs | Hardware (USB, Bluetooth, HDMI) or device bridge (ADB/IDB) | | **Software on target** | Required | Not required | | **OS service support** | Yes (Windows) | No | | **Platform support** | Windows, macOS, Linux | Any device with USB/HDMI/Bluetooth; Android (ADB), iOS (IDB planned) | For a detailed breakdown of what each mode can do, see [Capabilities](/docs/agentos/understanding/capabilities). ## What's Next? [#whats-next] # Runtime Modes (/docs/agentos/understanding/runtime-modes) AgentOS can run in two modes. Choose based on your use case. ## Standalone [#standalone] AgentOS runs as a regular process in the current user's session. **Best for:** Local development, interactive desktop use, and manual testing. AgentOS is installed via the AskUI installer. A dedicated standalone installer (without AskUI Desktop) is coming soon. For now, standalone AgentOS is installed as part of the [AskUI Desktop installer](/docs/get-started/install-desktop). A separate standalone installer is in progress. Once installed, AskUI Desktop and the CLI use the local AgentOS instance automatically. ## OS Service [#os-service] AgentOS runs as a Windows system service with SYSTEM privileges. **Best for:** Enterprise deployments, CI/CD pipelines, headless VMs, and scenarios where RDP sessions may disconnect. The OS service requires the [Windows installer](/docs/agentos/installation/service). Once installed, AskUI Desktop and the CLI automatically use the service instead of standalone mode. ## Feature Comparison [#feature-comparison] | Feature | Standalone | OS Service | | ----------------------------- | ---------------------------------------- | ------------------------------- | | **Primary use** | Local dev / desktop | Enterprise / CI/CD | | **CI/CD ready (Windows)** | No (requires OS service) | Yes (unattended/headless) | | **CI/CD ready (macOS/Linux)** | Yes | , | | **RDP resilience** | No (session locks on disconnect) | Yes (session transfer) | | **Logon screen control** | No | Yes | | **Send CTRL+ALT+DEL** | No | Yes (Secure Attention Sequence) | | **Privileges** | Current user | SYSTEM | | **Install method** | AskUI installer (standalone coming soon) | Windows installer | **Not sure which to pick?** Start with **standalone** for development. Move to the **OS service** when you need CI/CD, headless VMs, or RDP resilience. # OS Service (exe) (/docs/agentos/installation/service) AgentOS is proprietary software, **free for non-commercial use**. For commercial deployments, a license is required. See [pricing](https://www.askui.com/enterprise) for details. ## Prerequisites [#prerequisites] * **Windows** (Windows 10, Windows 11, Windows Server 2019+), see [System Requirements](/docs/agentos/reference/system-requirements) for supported versions. * **Administrator rights** To automate the login/lock screen (Secure Attention Sequence), a Group Policy setting must be enabled. See [Troubleshooting](/docs/troubleshooting/agentos-service#agent-cant-press-ctrlaltdel) for details. ## Installation [#installation] **Download the installer** * [AMD64 (x86\_64)](https://files.askui.com/releases/Installer/Latest/AskUI-Agent-OS-Latest-Service-Installer-Win-AMD64.exe) * [ARM64](https://files.askui.com/releases/Installer/Latest/AskUI-Agent-OS-Latest-Service-Installer-Win-ARM64.exe) **Run the installer** Run the EXE and approve the administrator elevation request. **Configure the service (optional)** The installer includes a **Service Configuration** screen: * **Connection Scope:** Use **Public (0.0.0.0)** if AgentOS needs to be reachable from another machine (e.g. a remote CI runner). Keep **Private (127.0.0.1)** for local use only. * **Log Level:** `Info` for production, `Debug` for troubleshooting. * **Allow CTRL+ALT+DEL:** Enable to automate the Windows lock/login screen (requires Group Policy, see [Troubleshooting](/docs/troubleshooting/agentos-service#agent-cant-press-ctrlaltdel)). * **Allow control of administrative applications:** Enable only if you need to automate apps running as administrator. Click **Next**, then **Install**. **Reboot if prompted** If the installer asks to reboot, restart the machine so all changes take effect. AskUI Desktop and the CLI automatically detect the service and use it instead of standalone mode. For silent/unattended installation, see [Silent (exe)](/docs/agentos/installation/silent). ## Uninstalling [#uninstalling] Always uninstall via **Windows Add/Remove Programs**. Do not remove the service from Windows Services manually. # Silent (exe) (/docs/agentos/installation/silent) Install AgentOS as a Windows service unattended, for scripts, CI/CD pipelines, or automated provisioning. ## Download [#download] ## Quick Start [#quick-start] Run from an **elevated** command prompt (Run as administrator): ```bash "AskUI-Agent-OS--Service-Installer-Win-AMD64.exe" /qn ``` Replace `` with the actual version number (e.g. `26.2.1.3` ). With custom options (replace `` with the full path to where you downloaded the installer): ```bash "" /qn APPDIR="C:\ASKUI" /l*vx installer.log ``` Append `/l*vx installer.log` to any command to write detailed installer logs. ## Parameters [#parameters] | Parameter | Default | Description | | ----------------------------------------- | ------------------------------------------- | ------------------------------------------------------------------------ | | `APPDIR` | `C:\Program Files\askui GmbH\AskUI AgentOS` | Install location. Must be accessible to all users. | | `SERVICE_SUBNET` | `127.0.0.1` | Network subnet the service listens on. | | `SERVICE_LISTENING_PORT` | `26000` | Main service port. | | `SERVICE_LOG_LEVEL` | `Debug` | Log verbosity: `Info` or `Debug`. | | `SERVICE_ENABLE_SAS` | `1` | Enable Secure Attention Sequence (CTRL+ALT+DEL). `0` to disable. | | `SERVICE_EXECUTION_ENGINE_ELEVATED` | `0` | Run execution engine with elevated privileges. `1` to enable. | | `SERVICE_EXECUTION_ENGINE_LISTENING_PORT` | `23000` | Execution engine port. | | `SERVICE_EXECUTION_ENGINE_VISIBLE` | `0` | Show execution engine UI/process. `1` to make visible. | | `SERVICE_TRANSFER_SESSION_ON_DISCONNECT` | `1` | Transfer remote sessions on disconnect (RDP resilience). `0` to disable. | **Example with multiple parameters:** ```bash "" /qn SERVICE_LISTENING_PORT=27000 SERVICE_LOG_LEVEL=Info SERVICE_ENABLE_SAS=1 /l*vx installer.log ``` ## Runtime Configuration [#runtime-configuration] After installation, the service can be tuned by editing: ``` C:\Program Files\askui GmbH\AskUI AgentOS\Configs\AskuiCoreService.json ``` After changing this file, **restart the computer** for changes to take effect. # Standalone (/docs/agentos/installation/standalone) Install AgentOS locally in standalone mode, it runs as a regular process in your user session. This is the fastest way to get going on a development machine. AgentOS is proprietary software, **free for non-commercial use**. For commercial deployments a license is required, see [pricing](https://www.askui.com/enterprise) for details. ## Prerequisites [#prerequisites] * **Windows**: **macOS**, or **Linux**, see [System Requirements](/docs/agentos/reference/system-requirements) for supported versions. * **macOS only:** grant **Accessibility** and **Screen Recording** permissions to the app running AgentOS, under **System Settings → Privacy & Security**. ## Install [#install] AgentOS ships with the AskUI Desktop installer, so most users get it automatically when they [install AskUI Desktop](/docs/get-started/install-desktop). A dedicated AgentOS installer for machines without AskUI Desktop is in progress. For now, use the AskUI Desktop installer to get AgentOS on a machine. ## What's next? [#whats-next] * [Runtime Modes](/docs/agentos/understanding/runtime-modes), standalone vs OS service. * [Control Modes](/docs/agentos/understanding/control-modes), Host vs Companion. * [Deploy as a Service](/docs/agentos/installation/service), for CI and headless VMs.