This is the full developer documentation for aqua
# aqua Documentation
> aqua is a QA planning and execution service that works with AI agents via MCP protocol.
aqua is a QA planning and execution service for AI coding agents. Describe what to test in natural language — the AI agent creates structured QA plans, executes them, and captures results on a web dashboard.
## Get Started
[Section titled “Get Started”](#get-started)
Installation
[Set up the server and CLI, and connect your coding agent. →](/docs/getting-started/installation/)
Quickstart
[Walk through your first QA session — from setup to results. →](/docs/getting-started/quickstart/)
## Guides
[Section titled “Guides”](#guides)
QA Plans
[Data model, versioning, and status lifecycle. →](/docs/guides/qa-plans/)
Environments
[Variables, secrets, and proxy settings. →](/docs/guides/environments/)
Execution
[Run plans via coding agent or CLI. →](/docs/guides/execution/)
Common Scenarios
[Reusable scenario templates across QA plans. →](/docs/guides/common-scenarios/)
Project Memory
[Accumulate knowledge across QA sessions. →](/docs/guides/project-memory/)
Organizations
[Teams, members, and roles. →](/docs/guides/organizations/)
Billing & Plans
[Plans, quotas, and subscription management. →](/docs/guides/billing/)
Audit Log
[Track organization and account activity. →](/docs/guides/audit-log/)
## Reference
[Section titled “Reference”](#reference)
CLI
[All aqua-cli commands and options. →](/docs/reference/cli/)
MCP Tools
[All MCP tools exposed by aqua. →](/docs/reference/mcp-tools/)
Step Actions
[HTTP and browser step action schemas. →](/docs/reference/step-actions/)
Assertions
[HTTP and browser assertion types. →](/docs/reference/assertions/)
Configuration
[Config files and environment variables. →](/docs/reference/configuration/)
Template Variables
[Variable syntax, resolution, and TOTP support. →](/docs/reference/template-variables/)
## Architecture
[Section titled “Architecture”](#architecture)
```plaintext
┌───────────────────┐
│ AI Coding Agent │
│ (Claude Code …) │
└────────┬──────────┘
│ MCP
┌────────┴──────────┐ ┌──────────────────────────┐
│ aqua CLI │ API │ aqua Server │
│ • MCP server ├─────►│ • QA plan storage │
│ • Test execution │ │ • Web dashboard │
└───────────────────┘ └──────────────────────────┘
```
The **CLI** runs locally — it acts as an MCP server for AI agents and executes tests. Secrets never leave your machine. The **Server** stores plans and results, providing a web dashboard for your team.
## For AI Agents
[Section titled “For AI Agents”](#for-ai-agents)
This documentation is available in LLM-friendly plain text format:
* [`llms.txt`](/docs/llms.txt) — Documentation index
* [`llms-full.txt`](/docs/llms-full.txt) — Complete documentation in a single file
* [`llms-small.txt`](/docs/llms-small.txt) — Abridged version for smaller context windows
# Installation
> How to set up aqua and connect it to your coding agent.
## Prerequisites
[Section titled “Prerequisites”](#prerequisites)
**Required:**
* **Node.js** >= 20.18.1
* **Git** — used to detect your project root and remote URL during initialization
* **An MCP-compatible coding agent** — such as [Claude Code](https://claude.ai/code), [Gemini CLI](https://github.com/google-gemini/gemini-cli), [OpenCode](https://opencode.ai), [Codex](https://github.com/openai/codex), [Cursor](https://cursor.com), or [Windsurf](https://windsurf.com). See [Coding Agent Setup](#3-coding-agent-setup) below.
**Recommended:**
* **Playwright** — required for QA plans that include browser testing (clicking, form input, screenshot assertions, etc.). Install the Chromium binary with:
```bash
npx playwright install chromium
```
You can skip this if your QA plans only use HTTP requests. aqua will prompt you to install it if a plan requires browser steps.
**Optional — Secret Providers:**
If your test environments require secrets (API keys, passwords, etc.), aqua can resolve them from external secret managers. Install the CLI for the provider you use:
| Provider | CLI | Install guide |
| ------------------- | -------- | -------------------------------------------------------------------------------------------------------- |
| 1Password | `op` | [1password.com/developers/docs/cli](https://developer.1password.com/docs/cli/get-started/) |
| AWS Secrets Manager | `aws` | [docs.aws.amazon.com/cli](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) |
| GCP Secret Manager | `gcloud` | [cloud.google.com/sdk/docs/install](https://cloud.google.com/sdk/docs/install) |
| HashiCorp Vault | `vault` | [developer.hashicorp.com/vault/install](https://developer.hashicorp.com/vault/install) |
You can also use environment variables or literal values for secrets without any external provider. See [Environments](/docs/guides/environments/) for details.
## 1. Account Setup
[Section titled “1. Account Setup”](#1-account-setup)
Create your aqua account:
```bash
npx @aquaqa/cli login
```
This opens your browser for authentication. After completing the login flow, credentials are saved to `~/.aqua/credentials.json`.
## 2. Project Setup
[Section titled “2. Project Setup”](#2-project-setup)
Run the following command inside your project repository:
```bash
npx @aquaqa/cli init
```
This creates a `.aqua/config.json` file in your project root containing:
* `project_key` — A unique identifier for the project, auto-detected from the git remote URL.
Once initialization is complete, subsequent CLI and MCP server commands will use this configuration automatically.
## 3. Coding Agent Setup
[Section titled “3. Coding Agent Setup”](#3-coding-agent-setup)
Connect aqua to the coding agent you use for development. Each agent has its own way of configuring MCP servers.
Use a dedicated session for QA
QA planning requires the agent to read through your codebase extensively — routes, business logic, edge cases, and more — to build meaningful test scenarios. This consumes a significant amount of context. We recommend running QA in a **separate session** from your regular development work.
### Claude Code
[Section titled “Claude Code”](#claude-code)
#### Permanent setup
[Section titled “Permanent setup”](#permanent-setup)
Register the aqua MCP server in your project so it is available in every session:
```bash
claude mcp add --scope project aqua -- npx @aquaqa/cli mcp-server
```
This creates a `.mcp.json` file in your project root that can be shared with your team via version control.
Also add the following to `.claude/settings.json` to allow aqua’s MCP tools without repeated prompts:
```json
{
"permissions": {
"allow": ["mcp__aqua__*"]
}
}
```
#### Ad-hoc session
[Section titled “Ad-hoc session”](#ad-hoc-session)
You can also start a one-off session with the aqua MCP server without modifying any config files:
```bash
claude --mcp-config '{"mcpServers":{"aqua":{"command":"npx","args":["@aquaqa/cli","mcp-server"]}}}' --allowedTools 'mcp__aqua__*'
```
This is useful when you want to keep QA work isolated from your development context. Since QA planning is context-intensive, starting a fresh session for each QA cycle is recommended. Use [project memory](/docs/guides/project-memory/) to carry knowledge across sessions.
### Gemini CLI
[Section titled “Gemini CLI”](#gemini-cli)
Add aqua to your project’s Gemini CLI configuration. Create or edit `.gemini/settings.json` in your project root:
```json
{
"mcpServers": {
"aqua": {
"command": "npx",
"args": ["@aquaqa/cli", "mcp-server"]
}
}
}
```
Gemini CLI will automatically start the aqua MCP server when a session begins in your project directory.
### OpenCode
[Section titled “OpenCode”](#opencode)
Add aqua to your project’s OpenCode configuration. Create or edit `opencode.json` in your project root:
```json
{
"mcp": {
"aqua": {
"type": "local",
"command": ["npx", "@aquaqa/cli", "mcp-server"]
}
}
}
```
OpenCode will automatically discover and start the aqua MCP server.
### Codex
[Section titled “Codex”](#codex)
Register the aqua MCP server with the `codex mcp add` command:
```bash
codex mcp add aqua -- npx @aquaqa/cli mcp-server
```
This writes the configuration to `.codex/config.toml` in your project. Codex will automatically start the aqua MCP server when a session begins.
You can verify the server is registered by typing `/mcp` in a Codex session.
### Cursor
[Section titled “Cursor”](#cursor)
Create `.cursor/mcp.json` in your project root:
```json
{
"mcpServers": {
"aqua": {
"command": "npx",
"args": ["@aquaqa/cli", "mcp-server"]
}
}
}
```
Restart Cursor after adding the configuration. You can verify the server status in **Cursor Settings > MCP**.
### Windsurf
[Section titled “Windsurf”](#windsurf)
Open the MCP configuration file from **Cascade panel > MCP icon > Configure**, or edit `~/.codeium/windsurf/mcp_config.json` directly:
```json
{
"mcpServers": {
"aqua": {
"command": "npx",
"args": ["@aquaqa/cli", "mcp-server"]
}
}
}
```
### Other Agents
[Section titled “Other Agents”](#other-agents)
Any coding agent that supports MCP can use aqua. Start the MCP server with:
```bash
npx @aquaqa/cli mcp-server
```
The server communicates over stdio. Refer to your agent’s documentation for how to configure an MCP server connection.
# Quickstart
> Walk through your first QA session with aqua — from setup to results.
This guide walks you through a typical QA session. It assumes you have already completed the [Installation](/docs/getting-started/installation/) steps and have aqua’s MCP server connected to your coding agent.
## How aqua Works
[Section titled “How aqua Works”](#how-aqua-works)
You use aqua through your coding agent. Rather than writing test scripts by hand, you describe what you want to test in natural language, and the agent builds and runs the QA plan for you.
A typical session looks like this:
| Step | You | Agent |
| --------------------- | --------------------------- | ------------------------------------- |
| 1. Start a session | Open a coding agent session | Verifies project setup |
| 2. Set up environment | Describe the test target | Creates an environment file |
| 3. Create a QA plan | Describe what to test | Reads your codebase and builds a plan |
| 4. Review and refine | Give feedback on the plan | Adjusts the plan |
| 5. Execute | Ask the agent to run it | Executes the plan and reports results |
| 6. Save knowledge | — | Saves insights to project memory |
## 1. Start a QA Session
[Section titled “1. Start a QA Session”](#1-start-a-qa-session)
Open a new session with your coding agent. Since QA planning requires the agent to read through your codebase extensively, we recommend using a **dedicated session** separate from your regular development work. See [Installation](/docs/getting-started/installation/#3-coding-agent-setup) for setup instructions.
The agent will verify that aqua is configured correctly for your project. If anything is missing, it will let you know.
**Example prompt:**
> Check if aqua is set up for this project.
## 2. Set Up the Test Environment
[Section titled “2. Set Up the Test Environment”](#2-set-up-the-test-environment)
Tell the agent about the environment you want to test against — the target URL and any credentials needed.
**Example prompt:**
> The local API server is running at . Set up an environment called “local” for it.
The agent creates an environment file at `.aqua/environments/local.json` containing the target URL and any variables needed for your tests. This file is stored locally in your project and is **reusable across sessions** — you only need to set it up once per environment.
If you already have environments from a previous session, you can skip this step. The agent can list existing environments and use them directly.
For details on environment configuration including secrets and proxy settings, see the [Environments](/docs/guides/environments/) guide.
## 3. Create a QA Plan
[Section titled “3. Create a QA Plan”](#3-create-a-qa-plan)
Describe what you want to test. You can be as broad or specific as you like — the agent will read through your codebase to understand the application structure and build appropriate test scenarios.
**Example prompts:**
> Create a QA plan for the user registration API. Cover the happy path and common error cases like duplicate emails and missing required fields.
> I just added a new checkout flow in this PR. Create a QA plan that tests the full purchase process including cart, payment, and order confirmation.
> Create a browser test plan for the login page. Test with valid credentials, invalid password, and locked account.
The agent will present the QA plan for your review. Each plan contains one or more **scenarios**, and each scenario has a series of **steps** — HTTP requests or browser actions with assertions.
Review the plan and give feedback. For example:
> Add a scenario that tests what happens when the payment gateway times out.
> The login page uses `data-testid="login-button"` instead of a submit button. Update the selector.
The agent will adjust the plan based on your feedback. In practice, you will often discover issues by **executing the plan first** and then refining it based on the results — fixing incorrect selectors, adjusting assertions, or adding missing scenarios. This cycle of execute, review, and refine is a normal part of building a reliable QA plan.
For more on how QA plans are structured, see the [QA Plans](/docs/guides/qa-plans/) guide.
## 4. Execute the Plan
[Section titled “4. Execute the Plan”](#4-execute-the-plan)
Once you are happy with the plan, ask the agent to run it.
**Example prompt:**
> Execute the plan against the local environment.
The agent runs each scenario and step, then reports a summary of the results — which steps passed, which failed, and any error details. You can also view the full results in the aqua Web UI.
You can also execute plans directly from the CLI without going through the coding agent. See the [CLI reference](/docs/reference/cli/) for details.
For more on execution, reviewing results, and re-running plans, see the [Execution](/docs/guides/execution/) guide.
## 5. Save Project Memory
[Section titled “5. Save Project Memory”](#5-save-project-memory)
At the end of a session, the agent saves useful insights to **project memory** — a persistent knowledge base shared across sessions. This might include:
* Reliable CSS selectors for UI elements
* Authentication flow details
* Known quirks or constraints of the application
* Tips for writing tests against this codebase
The next time you (or a teammate) start a QA session, the agent reads project memory to build on previous knowledge rather than starting from scratch.
For more on project memory, see the [Project Memory](/docs/guides/project-memory/) guide.
## What’s Next
[Section titled “What’s Next”](#whats-next)
* **[QA Plans](/docs/guides/qa-plans/)** — Understand the plan data model, versioning, and status lifecycle.
* **[Environments](/docs/guides/environments/)** — Configure target URLs, secrets, and proxy settings.
* **[Execution](/docs/guides/execution/)** — Learn about plan execution, result collection, and the web dashboard.
* **[CLI Reference](/docs/reference/cli/)** — Complete reference for all aqua-cli commands and options.
# Audit Log
> Tracking organization and account activity with audit logs.
Audit logs record write operations performed in aqua, providing a history of who did what and when. There are two ways to view audit logs: at the organization level and at the account level.
## Availability
[Section titled “Availability”](#availability)
| View | Available to | Plan requirement |
| -------------------------- | --------------------------- | -------------------------- |
| **Organization audit log** | Members of the organization | Team or Enterprise (cloud) |
| **Account activity log** | The account owner | All plans |
Self-hosted instances have full access to audit logs regardless of plan.
Logs are always recorded
Audit log entries are written regardless of your organization’s plan. If you upgrade from Free to Team, the full history (up to the retention period) becomes immediately available.
## Organization Audit Log
[Section titled “Organization Audit Log”](#organization-audit-log)
The organization audit log shows all recorded activity within the organization. Access it from the **Audit Log** tab on the organization detail page.
This view is available to members with the `member` role or higher. On the cloud-hosted version, it requires a Team or Enterprise plan. Free plan organizations see a message prompting them to upgrade.
### Filtering
[Section titled “Filtering”](#filtering)
You can filter the audit log by:
* **Category** — Use the segment tabs at the top to show only events in a specific category (e.g., Organization, Project, QA Plan).
* **User** — Filter by a specific organization member to see only their actions.
## Account Activity Log
[Section titled “Account Activity Log”](#account-activity-log)
The account activity log shows all actions performed by your account, across all organizations. Access it from **Settings > Activity Log** in the Web UI.
This view is available to all users regardless of plan. It supports the same category filter as the organization view.
## Tracked Events
[Section titled “Tracked Events”](#tracked-events)
Audit logs track the following events, grouped by category.
### Authentication
[Section titled “Authentication”](#authentication)
| Event | Description |
| ----------------------------- | ----------------------------------------- |
| `user.registered` | A new user account was created. |
| `user.logged_in` | A user signed in. |
| `user.password_changed` | A user changed their password. |
| `user.profile_updated` | A user updated their display name. |
| `user.email_change_requested` | A user requested an email address change. |
| `user.email_changed` | A user’s email address was changed. |
| `user.email_verified` | A user’s email was verified. |
| `user.account_deleted` | A user account was deleted. |
| `api_key.created` | An API key was created. |
| `api_key.deleted` | An API key was deleted. |
| `oauth_connection.deleted` | An OAuth connection was removed. |
| `email_verification.resent` | A verification email was resent. |
### Organization
[Section titled “Organization”](#organization)
| Event | Description |
| ---------------------- | ------------------------------------------- |
| `organization.created` | An organization was created. |
| `organization.updated` | An organization’s name was changed. |
| `organization.deleted` | An organization was deleted. |
| `member.added` | A member was added to the organization. |
| `member.role_changed` | A member’s role was changed. |
| `member.removed` | A member was removed from the organization. |
### Project
[Section titled “Project”](#project)
| Event | Description |
| ------------------------ | -------------------------------------------- |
| `project.created` | A project was created. |
| `project.updated` | A project’s settings were updated. |
| `project.deleted` | A project was deleted. |
| `project.transferred` | A project was moved to another organization. |
| `project.memory_updated` | A project’s memory document was updated. |
### QA Plan
[Section titled “QA Plan”](#qa-plan)
| Event | Description |
| ------------------------- | ---------------------------------------------------------------- |
| `qa_plan.created` | A QA plan was created. |
| `qa_plan.updated` | A QA plan’s content was updated. |
| `qa_plan.status_changed` | A QA plan’s status, pinned state, or archived state was changed. |
| `qa_plan.deleted` | A QA plan was deleted. |
| `qa_plan_version.created` | A new version of a QA plan was created. |
### Execution
[Section titled “Execution”](#execution)
| Event | Description |
| ------------------- | -------------------------------- |
| `execution.created` | A QA plan execution was started. |
### Common Scenario
[Section titled “Common Scenario”](#common-scenario)
| Event | Description |
| ------------------------- | ------------------------------ |
| `common_scenario.created` | A common scenario was created. |
| `common_scenario.updated` | A common scenario was updated. |
| `common_scenario.deleted` | A common scenario was deleted. |
### Billing
[Section titled “Billing”](#billing)
| Event | Description |
| -------------------------- | ------------------------------------------- |
| `billing.checkout_created` | A Stripe checkout session was initiated. |
| `subscription.updated` | An organization’s subscription was changed. |
## Event Details
[Section titled “Event Details”](#event-details)
Each audit log entry includes:
* **Actor** — The user who performed the action, or “System” for automated operations (e.g., webhook-triggered subscription changes).
* **Resource** — The type and ID of the affected resource.
* **Source** — How the action was performed: `web` (Web UI), `api` (CLI / API key), or `system` (automated).
* **Timestamp** — When the action occurred.
* **Additional details** — Context-specific information such as role changes, status transitions, or transfer destinations.
## Data Retention
[Section titled “Data Retention”](#data-retention)
Audit log entries are retained for **3 months**. Entries older than 3 months are automatically deleted.
# Billing & Plans
> Understanding aqua plans, quotas, and subscription management.
aqua offers three plans with different resource limits. Your plan is set at the organization level — each team organization can have its own subscription.
## Plans
[Section titled “Plans”](#plans)
| | Free | Team | Enterprise |
| ---------------------------------------------- | ---------- | --------- | ---------- |
| **Storage** | 512 MB | 50 GB | Unlimited |
| **Members** | Unlimited | Unlimited | Unlimited |
| **Team organizations** | 1 per user | Unlimited | Unlimited |
| **Audit log** | — | ✓ | ✓ |
| **[Self-hosting](/docs/guides/self-hosting/)** | — | — | ✓ |
Personal organizations always use the Free plan and cannot be upgraded. To access paid features, create a [team organization](/docs/guides/organizations/).
## Quotas
[Section titled “Quotas”](#quotas)
Each plan enforces limits on the following resources:
* **Storage** — Total size of artifacts (HTTP responses, screenshots, DOM snapshots) stored by executions.
When a quota is exceeded, the server returns HTTP 402 and the operation is blocked until you free up resources or upgrade your plan.
### Soft Quota (CLI)
[Section titled “Soft Quota (CLI)”](#soft-quota-cli)
The CLI checks quota status before starting an execution. If storage quota is exceeded:
* The QA plan **still executes normally** — tests are never blocked.
* Execution results are **not recorded** on the server (artifacts and step results are skipped).
* A warning is displayed in the CLI output.
This means your testing workflow is never interrupted by quota limits. You can upgrade at any time to resume recording results.
## Managing Your Subscription
[Section titled “Managing Your Subscription”](#managing-your-subscription)
Billing is managed from the **Usage** tab on the organization detail page. This tab is visible to admins and owners.
### Viewing Usage
[Section titled “Viewing Usage”](#viewing-usage)
The Usage tab shows current resource consumption for each quota:
* A progress bar showing usage relative to the plan limit.
* The exact count or size used vs. the allowed maximum.
### Upgrading
[Section titled “Upgrading”](#upgrading)
To upgrade your organization’s plan:
1. Go to the organization’s **Usage** tab.
2. Click **Upgrade Plan**.
3. Select your desired plan in the Stripe checkout page.
4. Complete the payment.
The new plan takes effect immediately after payment.
### Managing Your Subscription
[Section titled “Managing Your Subscription”](#managing-your-subscription-1)
If you already have an active subscription, click **Manage Subscription** on the Usage tab to open the Stripe Customer Portal. From there you can:
* Change your plan.
* Update your payment method.
* View invoices and billing history.
* Cancel your subscription.
# Common Scenarios
> Creating and reusing scenario templates across QA plans.
Common scenarios are reusable scenario templates that exist at the project level. They allow you to define frequently used test flows once and include them in any QA plan.
## Use Cases
[Section titled “Use Cases”](#use-cases)
Common scenarios are useful for test flows that appear in many plans:
* **Login flows** — Authenticate a user before running feature tests.
* **Test data setup** — Create prerequisite data (users, resources, configurations).
* **Cleanup routines** — Remove test data after execution.
## Creating a Common Scenario
[Section titled “Creating a Common Scenario”](#creating-a-common-scenario)
Tell the AI agent what reusable flow you need. The agent will create a common scenario using the appropriate MCP tool.
**Example prompt:**
> “Create a common scenario for logging into the app. It should navigate to the login page, enter email and password, and wait for the dashboard. Use variables for the credentials.”
The agent will create a scenario like this:
```json
{
"name": "Standard Login",
"description": "Logs in with test_email and test_password variables.",
"requires": ["test_email", "test_password", "web_base_url"],
"steps": [
{
"step_key": "login_navigate",
"action": "browser",
"config": {
"steps": [
{ "action": "goto", "url": "{{web_base_url}}/login" },
{ "action": "type", "selector": "#email", "text": "{{test_email}}" },
{ "action": "type", "selector": "#password", "text": "{{test_password}}" },
{ "action": "click", "selector": "button[type='submit']" },
{ "action": "wait_for_url", "url": "/dashboard" }
]
}
}
]
}
```
### Parameters
[Section titled “Parameters”](#parameters)
| Parameter | Description |
| ------------- | --------------------------------------------------------------------------------- |
| `name` | A descriptive name for the scenario. |
| `description` | Explanation of what the scenario does and when to use it. |
| `requires` | *(optional)* List of variable names that must be present for the scenario to run. |
| `steps` | The ordered list of steps that make up the scenario. |
## Using Common Scenarios in QA Plans
[Section titled “Using Common Scenarios in QA Plans”](#using-common-scenarios-in-qa-plans)
When the AI agent creates a QA plan, it can reference existing common scenarios by their ID. You can also ask the agent to include them:
> “Create a QA plan for the user profile page. Use the Standard Login scenario for authentication.”
The steps from the common scenario are **snapshot-copied** into the plan version at that point in time. This means:
* The plan version gets its own independent copy of the steps.
* Future changes to the common scenario do not affect existing plan versions.
* The plan version is self-contained and reproducible.
## Managing Common Scenarios
[Section titled “Managing Common Scenarios”](#managing-common-scenarios)
You can ask the AI agent to list, update, or delete common scenarios:
* **List** — “What common scenarios do we have?” — The agent retrieves all common scenarios in the project.
* **Update** — “Update the login scenario to use a CSS class selector instead of an ID.” — The agent modifies the scenario’s steps.
* **Delete** — “Delete the old cleanup scenario.” — The agent removes it from the project.
### Deletion Behavior
[Section titled “Deletion Behavior”](#deletion-behavior)
Deleting a common scenario does **not** affect QA plans that have already copied its steps. Since steps are snapshot-copied at the time the plan version is created, the plan versions remain complete and executable even after the source common scenario is removed.
# Environments
> Configuring local environment files for variables, secrets, and proxy settings.
Environments define the target URLs, credentials, and other configuration needed to execute a QA plan. Environment files are stored locally and never sent to the server, ensuring sensitive data stays on your machine.
## File Location
[Section titled “File Location”](#file-location)
Environment files are stored at:
```plaintext
.aqua/environments/.json
```
Each file represents a named environment (e.g., `local.json`, `staging.json`, `production.json`). We recommend committing the `.aqua/` directory to your repository so that environment configurations are shared across your team. Sensitive values are safe to commit when using secret types that reference external sources (`env`, `op`, `aws_sm`, etc.) — only the reference is stored in the file, not the actual secret.
## File Schema
[Section titled “File Schema”](#file-schema)
A complete environment file has the following structure:
```json
{
"notes": "Markdown notes about the environment",
"variables": {
"api_base_url": "http://localhost:8000",
"web_base_url": "http://localhost:3000",
...
},
"secrets": {
"api_key": { "type": "literal", "value": "dev-key-123" },
"auth_token": { "type": "env", "value": "STAGING_AUTH_TOKEN" },
"db_password": { "type": "op", "value": "op://Development/staging-db/password" },
...
},
"secret_providers": {
"aws_sm": { "region": "ap-northeast-1", "profile": "staging" },
"gcp_sm": { "project": "my-project-123" },
"hcv": { "address": "https://vault.example.com:8200" }
},
"proxy": {
"server": "http://proxy.corp.com:3128",
"bypass": "localhost,.internal.com",
"username": { "type": "literal", "value": "user" },
"password": { "type": "env", "value": "PROXY_PASSWORD" },
"ca_cert_path": "/path/to/ca.pem",
"reject_unauthorized": false
}
}
```
All sections except `variables` are optional.
## Variables
[Section titled “Variables”](#variables)
The `variables` object contains plain key-value pairs. You define variable names to match what your QA plan references — any key name can be used. Variables are substituted into plan templates using `{{variable_name}}` syntax.
For example, if your QA plan has a step with the URL `{{api_base_url}}/users`, define `api_base_url` in your environment file to provide the value.
Two variable names are used by convention:
| Variable | Purpose |
| -------------- | --------------------------------- |
| `api_base_url` | Base URL for HTTP API requests. |
| `web_base_url` | Base URL for browser-based tests. |
### Variable Priority
[Section titled “Variable Priority”](#variable-priority)
When the same variable is defined in multiple places, the following priority order applies (highest wins):
1. **Execution overrides** — Values passed at execution time.
2. **Environment file** — Values from `.aqua/environments/.json`.
3. **Plan defaults** — Default values defined in the QAPlanVersion.
## Secrets
[Section titled “Secrets”](#secrets)
Secrets work like variables but hold sensitive values such as API keys, auth tokens, and passwords. You define secret names to match what your QA plan references — just like variables, any key name can be used. The difference is that each secret specifies a `type` that determines how the value is resolved, and resolved values are always masked before being sent to the server.
Once resolved, secrets are merged into the same variable namespace as plain variables and can be referenced in plan templates with the same `{{secret_name}}` syntax.
### Secret Types
[Section titled “Secret Types”](#secret-types)
| Type | Description | Example |
| --------- | ----------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| `literal` | The value is used directly as written. | `{ "type": "literal", "value": "dev-key-123" }` |
| `env` | The value is read from an OS environment variable. | `{ "type": "env", "value": "STAGING_AUTH_TOKEN" }` |
| `op` | The value is fetched from [1Password CLI](https://developer.1password.com/docs/cli/). | `{ "type": "op", "value": "op://vault/item/field" }` |
| `aws_sm` | The value is fetched from [AWS Secrets Manager](https://aws.amazon.com/secrets-manager/). | `{ "type": "aws_sm", "value": "staging/db-creds" }` |
| `gcp_sm` | The value is fetched from [GCP Secret Manager](https://cloud.google.com/secret-manager). | `{ "type": "gcp_sm", "value": "api-key" }` |
| `hcv` | The value is fetched from [HashiCorp Vault](https://www.vaultproject.io/). | `{ "type": "hcv", "value": "myapp/keys" }` |
### Cloud Secret Manager Options
[Section titled “Cloud Secret Manager Options”](#cloud-secret-manager-options)
The `aws_sm`, `gcp_sm`, and `hcv` types support additional fields for fine-grained control:
**AWS Secrets Manager (`aws_sm`)**
| Field | Description |
| ---------- | ----------------------------------------------------------------- |
| `value` | Secret name or ARN. |
| `region` | *(optional)* AWS region. Overrides the provider-level setting. |
| `json_key` | *(optional)* Extract a specific key from a JSON-formatted secret. |
**GCP Secret Manager (`gcp_sm`)**
| Field | Description |
| ---------- | ------------------------------------------------------------------ |
| `value` | Secret name. |
| `project` | *(optional)* GCP project ID. Overrides the provider-level setting. |
| `version` | *(optional)* Secret version. Defaults to `latest`. |
| `json_key` | *(optional)* Extract a specific key from a JSON-formatted secret. |
**HashiCorp Vault (`hcv`)**
| Field | Description |
| ------- | ------------------------------------------------------ |
| `value` | Secret path. |
| `field` | *(optional)* Extract a specific field from the secret. |
| `mount` | *(optional)* KV mount point. Defaults to `secret`. |
### Secret Providers
[Section titled “Secret Providers”](#secret-providers)
The `secret_providers` section sets default configuration for each external secret type. Entry-level fields override provider-level fields.
```json
{
"secret_providers": {
"aws_sm": {
"region": "ap-northeast-1",
"profile": "staging"
},
"gcp_sm": {
"project": "my-project-123"
},
"hcv": {
"address": "https://vault.example.com:8200",
"namespace": "staging"
}
}
}
```
This avoids repeating the same region or project in every secret entry. For example, if all your AWS secrets are in `ap-northeast-1`, set the region once in `secret_providers.aws_sm` and omit it from individual entries.
### Lazy Resolution
[Section titled “Lazy Resolution”](#lazy-resolution)
Only secrets that are actually referenced in the current plan are resolved. If your environment file defines ten secrets but the plan only uses two, only those two are looked up. This avoids unnecessary calls to external secret managers and prevents errors from unused secrets that may not be configured.
### Secret Masking
[Section titled “Secret Masking”](#secret-masking)
Before any data is sent to the aqua server, all resolved secret values are replaced with `***`. This ensures that sensitive information never leaves your machine, even when execution results are recorded on the server. Masking is applied across multiple layers — environment values, HTTP request/response headers, and DOM snapshots.
Secrets are never exposed to the AI agent
When you execute a QA plan through a coding agent, secrets are resolved **locally on your machine** by the aqua MCP server process — not by the AI agent itself. The agent only receives masked execution results and never sees raw secret values. You can safely use API keys, passwords, and tokens in your environments without concern about them being sent to the AI model.
## Proxy
[Section titled “Proxy”](#proxy)
The optional `proxy` section configures an HTTP proxy for outbound requests during test execution.
| Field | Description |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `server` | Proxy server URL (e.g., `http://proxy.corp.com:3128`). |
| `bypass` | Comma-separated list of hosts that should bypass the proxy. |
| `username` | *(optional)* Proxy authentication username. Uses the same secret type format. |
| `password` | *(optional)* Proxy authentication password. Uses the same secret type format. |
| `ca_cert_path` | *(optional)* Path to a CA certificate file for target server TLS verification (e.g., self-signed certs or SSL-intercepting proxies). |
| `proxy_ca_cert_path` | *(optional)* Path to a CA certificate file for the proxy server itself (when the proxy uses HTTPS with a custom CA). |
| `reject_unauthorized` | *(optional)* Set to `false` to skip TLS certificate verification for both proxy and target connections. |
## Notes
[Section titled “Notes”](#notes)
The `notes` field accepts Markdown text and is intended for recording environment-specific information such as:
* Preconditions that must be met before running tests.
* Known constraints or limitations of the environment.
* Test account credentials or setup instructions.
* Links to environment-specific documentation.
Notes are stored locally with the environment file and are available to the AI agent during QA sessions to provide context about the target environment.
# Execution
> How to execute QA plans — through a coding agent or directly from the CLI.
Once you have a QA plan ready, you can execute it in two ways: ask your coding agent to run it, or execute it directly from the CLI. Both methods resolve secrets locally and never send raw credentials to the aqua server.
## Through Your Coding Agent
[Section titled “Through Your Coding Agent”](#through-your-coding-agent)
The most common way to execute a plan is through your coding agent. Simply ask it to run the plan against a specific environment.
**Example prompt:**
> Execute the QA plan against the local environment.
The agent calls the `execute_qa_plan` MCP tool, which:
1. Loads the environment file and resolves variables and secrets locally.
2. Runs each scenario and its steps in order, respecting dependencies.
3. Records the results on the aqua server.
4. Returns a markdown summary with pass/fail status for each step.
After execution, the agent can help you interpret the results, identify failures, and adjust the plan accordingly.
### Async Execution
[Section titled “Async Execution”](#async-execution)
For long-running plans, you can use async execution to start the plan in the background and check progress later:
> Execute the QA plan against the staging environment asynchronously.
The agent calls `execute_qa_plan` with the `async` parameter set to `true`. Instead of waiting for all scenarios to complete, it returns immediately with an execution ID and URL.
To check progress:
> Check the progress of that execution.
The agent calls `get_execution_progress` with the execution ID, which returns:
* Current status (pending, running, completed, failed)
* Progress count (completed steps / total steps)
* Currently running step (if any)
* Per-step results as they complete
This is useful when a plan has many scenarios or steps that take a long time to execute, as it frees the agent to work on other tasks while the execution runs.
Secrets are never exposed to the agent
When the agent triggers an execution, secrets are resolved **locally on your machine** by the aqua MCP server process — not by the AI agent itself. The agent never sees raw secret values. It only receives the execution summary after secret values have been masked with `***`.
You can safely use secrets such as API keys, passwords, and tokens in your QA plans without concern about them being sent to the AI model.
## From the CLI
[Section titled “From the CLI”](#from-the-cli)
You can also execute plans directly from the command line using the `aqua-cli execute` command:
```bash
npx @aquaqa/cli execute --env
```
### Options
[Section titled “Options”](#options)
| Option | Description |
| -------------------- | ----------------------------------------------------------------- |
| `` | **(required)** The ID of the QA plan to execute. |
| `--env ` | Load environment variables from `.aqua/environments/.json`. |
| `--plan-version ` | Execute a specific plan version. Defaults to the latest version. |
| `--var key=value` | Override a variable value. Can be specified multiple times. |
### Use in CI/CD
[Section titled “Use in CI/CD”](#use-in-cicd)
CLI execution does not require a coding agent or an MCP server, making it suitable for automated pipelines. You can integrate aqua into your CI/CD workflow to run QA plans on every deploy or pull request.
**Example: GitHub Actions**
```yaml
- name: Run QA plan
run: npx @aquaqa/cli execute ${{ vars.QA_PLAN_ID }} --env ci
```
Set up a `ci` environment file (`.aqua/environments/ci.json`) with the appropriate target URLs and credentials for your CI environment. Use the `env` secret type to read sensitive values from CI environment variables.
## Execution Flow
[Section titled “Execution Flow”](#execution-flow)
When a plan is executed, aqua processes it as follows:
1. **Variable resolution** — Variables are merged from three sources in priority order: execution overrides (highest), environment file, and plan defaults (lowest). See [Template Variables](/docs/reference/template-variables/) for details.
2. **Secret resolution** — Only secrets that are actually referenced in the plan are resolved. Secret values are masked with `***` before any data is sent to the server.
3. **Scenario execution** — Scenarios are executed in order. If a scenario declares a `requires` field and the required variables are not present, the scenario is skipped.
4. **Step execution** — Steps within each scenario are executed in order, respecting `depends_on` constraints. If a dependency step has failed or was skipped, the dependent step is also skipped.
5. **Condition evaluation** — If a step has a `condition` field, the condition is checked after dependency resolution. If the condition is not met (e.g., a variable does not equal the expected value), the step is skipped. See [Conditional Step Execution](/docs/guides/qa-plans/#conditional-step-execution) for details.
6. **Assertions** — After each step completes, its assertions are evaluated. A step passes if all assertions succeed.
7. **Extraction** — Values extracted from step responses become available as template variables for subsequent steps.
### Cross-Scenario State
[Section titled “Cross-Scenario State”](#cross-scenario-state)
State is shared across scenarios in two ways:
* **Extracted variables** are global — a value extracted in one scenario can be referenced in any subsequent scenario.
* **Browser state** (cookies and localStorage) is preserved across scenarios, so a login performed in one scenario carries over to the next.
## Reviewing Results
[Section titled “Reviewing Results”](#reviewing-results)
### In the Agent Session
[Section titled “In the Agent Session”](#in-the-agent-session)
After execution, the agent presents a summary showing:
* Overall pass/fail status
* Per-scenario and per-step results
* Error details for failed steps
* A link to the full results in the aqua Web UI
You can ask the agent to dig deeper into specific failures:
> What went wrong with the “checkout with expired card” scenario?
### In the Web UI
[Section titled “In the Web UI”](#in-the-web-ui)
The aqua Web UI provides a detailed view of each execution, including:
* Full request and response data for HTTP steps
* Screenshots and browser logs for browser steps
* Assertion results with expected vs. actual values
* Execution timeline
Open the Web UI with:
```bash
npx @aquaqa/cli web
```
### Via MCP Tools
[Section titled “Via MCP Tools”](#via-mcp-tools)
The agent can also use the `get_execution` and `list_executions` MCP tools to retrieve past execution results programmatically. This is useful for comparing results across runs or tracking down regressions.
## Sharing Results
[Section titled “Sharing Results”](#sharing-results)
You can share execution results with team members, stakeholders, or anyone else — even people who don’t have an aqua account. Shared links provide a read-only view of the full execution results including scenarios, steps, assertions, and artifacts.
### Creating a Share Link
[Section titled “Creating a Share Link”](#creating-a-share-link)
1. Open the execution detail page in the Web UI.
2. Click the **Share** button in the top-right corner.
3. Choose an expiration period (3 days or 30 days).
4. Click **Create share link**.
5. Copy the link and share it with anyone.
The share link provides full access to the execution results without requiring login. Each execution can have one active share link at a time.
### Revoking a Share Link
[Section titled “Revoking a Share Link”](#revoking-a-share-link)
If you need to revoke access to a shared execution:
1. Open the execution detail page and click **Share**.
2. Click **Revoke share link** at the bottom of the dialog.
The link creator or any organization admin can revoke a share link. Once revoked, the link immediately stops working.
### What’s Included
[Section titled “What’s Included”](#whats-included)
The shared view includes:
* Execution status and timing information
* All scenarios with their step results
* Assertion results (pass/fail with expected vs. actual values)
* Artifacts (HTTP request/response data, screenshots)
* Environment variables (secrets are already masked with `***` before recording)
## Re-Running Plans
[Section titled “Re-Running Plans”](#re-running-plans)
After fixing issues in your plan or application, you can re-run the plan immediately:
> Run the plan again against the local environment.
You can also run a specific version of the plan:
```bash
npx @aquaqa/cli execute --env local --plan-version 3
```
Or override specific variables for a one-off run:
```bash
npx @aquaqa/cli execute --env local --var api_base_url=http://localhost:4000
```
## Automatic Status Transitions
[Section titled “Automatic Status Transitions”](#automatic-status-transitions)
When an execution completes with all steps passing, the plan’s status is automatically promoted from `draft` to `active`. This ensures that only validated, fully passing plans carry the `active` status.
Conversely, when a new version is added to an `active` plan, the status is automatically demoted back to `draft` for re-validation.
See [QA Plans](/docs/guides/qa-plans/#status-lifecycle) for more on the status lifecycle.
# Interactive Exploration
> How the AI agent autonomously explores your application to build reliable QA plans.
When you ask the agent to create a QA plan, it often needs to discover page structure, find reliable selectors, and understand how the application behaves. The agent uses **exploration sessions** to do this autonomously — opening a browser, navigating through the application one action at a time, and inspecting the results before moving on.
## How It Works
[Section titled “How It Works”](#how-it-works)
When the agent determines that it needs to investigate the application before building a plan, it automatically starts an exploration session. Within a session, the agent executes actions one at a time and receives immediate feedback (DOM HTML, screenshots, URLs) after each action. This lets the agent identify selectors, verify navigation flows, and adapt to unexpected UI states — all without any manual intervention.
**Exploration vs. `run_scenario`:**
| | Exploration | `run_scenario` |
| ---------------- | ----------------------------- | --------------------------------- |
| Browser lifetime | Kept alive across actions | Created and destroyed per run |
| Feedback | After each individual action | After the full scenario completes |
| Results recorded | No (local logs only) | No |
| Use case | Investigating before planning | Testing a complete scenario |
## What the Agent Does
[Section titled “What the Agent Does”](#what-the-agent-does)
### Starting a session
[Section titled “Starting a session”](#starting-a-session)
The agent calls `start_exploration` to create a session. The browser is not launched until the first browser action, so session creation is instant.
| Parameter | Description |
| ------------- | ---------------------------------------------------------------- |
| `env_name` | Environment name to load from `.aqua/environments/.json`. |
| `environment` | Variable overrides (highest priority). |
| `qa_plan_id` | QA Plan ID to pull default variables from. |
| `viewport` | Viewport preset: `pc` (1280×720, default) or `mobile` (375×667). |
Sessions automatically expire after **15 minutes** of inactivity. The timer resets on each action.
### Executing actions
[Section titled “Executing actions”](#executing-actions)
The agent calls `explore_action` to execute actions within the session. Each call accepts exactly one of the following action types:
* **`browser_step`** — Execute a single browser action (navigate, click, type, etc.) and receive the resulting page DOM, screenshot, URL, and title.
* **`browser_steps`** — Execute multiple browser actions in sequence. Only the final page state is returned. Useful for replaying a known sequence quickly.
* **`http_request`** — Send an HTTP request and receive the status code, headers, body, and duration.
* **`browser_assertion`** — Evaluate an assertion against the current page state without modifying it.
The agent can also **extract values** from HTTP responses using JSONPath and store them as session variables for use in subsequent actions.
After each action, the agent analyzes the feedback to decide what to do next — for example, identifying which selector to use for a button, or confirming that a navigation succeeded before proceeding.
### Ending a session
[Section titled “Ending a session”](#ending-a-session)
Once the agent has gathered enough information, it calls `end_exploration` to clean up resources (browser process, memory). If the agent forgets or the session is interrupted, it automatically expires after 15 minutes of inactivity.
## Example
[Section titled “Example”](#example)
When you ask the agent to create a QA plan, the agent autonomously explores the application to gather the information it needs.
**Your prompt:**
> Create a QA plan for the login flow and the profile editing page against the local environment.
**What the agent does behind the scenes:**
1. Starts an exploration session against the local environment.
2. Navigates to the login page and examines the DOM to find the email and password input selectors.
3. Fills in test credentials and clicks the login button.
4. Observes the resulting page to confirm the login succeeded (checks the URL, looks for dashboard elements).
5. Navigates to the profile settings page and inspects the available form fields.
6. Ends the exploration session.
7. Creates a QA plan using the discovered selectors, URLs, and verified action sequences.
At each step, the agent receives a screenshot and the page DOM, so it can identify the right elements and adapt if something unexpected happens (e.g., a modal dialog appears, a selector doesn’t match).
## Exploration Logs
[Section titled “Exploration Logs”](#exploration-logs)
Exploration sessions are logged locally so the agent can reference past discoveries.
* **`list_exploration_logs`** — Lists recent sessions with timestamps, action counts, and last visited URLs.
* **`get_exploration_log`** — Retrieves the full action log from a specific session. Successful browser steps are formatted as a JSON array that can be directly used in a QA plan’s `browser_steps`.
Logs are stored at `~/.aqua/explorations/` and automatically cleaned up after 24 hours (up to 30 sessions per project are retained).
# Organizations
> Managing teams, members, and roles in aqua.
Organizations are the top-level unit for managing team access in aqua. Every project belongs to an organization, and organization membership determines who can view and interact with the projects inside it.
## Personal vs Team Organizations
[Section titled “Personal vs Team Organizations”](#personal-vs-team-organizations)
aqua has two types of organizations:
| | Personal | Team |
| ---------------- | ------------------------------- | ------------------------- |
| **Created by** | Automatically when you register | Manually from the Web UI |
| **Limit** | One per user | Multiple allowed |
| **Members** | Owner only | Owner + invited members |
| **Billing plan** | Always Free | Free, Team, or Enterprise |
| **Deletable** | No | Yes (owner only) |
Your **personal organization** is created during registration and cannot be deleted. It provides a private workspace for individual projects.
**Team organizations** let you share projects with other users and collaborate on QA plans. Each member is assigned a role that controls what they can do.
## Creating a Team Organization
[Section titled “Creating a Team Organization”](#creating-a-team-organization)
You can create a team organization from the **Organizations** page in the Web UI:
1. Click **New Organization**.
2. Enter a name for the organization.
3. Click **Create**.
You become the **owner** of the new organization automatically.
## Members and Roles
[Section titled “Members and Roles”](#members-and-roles)
Organization members are assigned one of four roles, listed from most to least privileged:
| Role | Description |
| -------- | ---------------------------------------------------------------------------------- |
| `owner` | Full control. Can manage billing, delete the organization, and transfer ownership. |
| `admin` | Can invite and remove members, change roles, and manage billing. |
| `member` | Can create and execute QA plans, manage projects, and update project memory. |
| `viewer` | Read-only access to projects, QA plans, and execution results. |
### Permissions
[Section titled “Permissions”](#permissions)
| Action | Owner | Admin | Member | Viewer |
| --------------------------- | ----- | ----- | ------ | ------ |
| View projects and plans | ✓ | ✓ | ✓ | ✓ |
| Create and execute QA plans | ✓ | ✓ | ✓ | |
| Invite members | ✓ | ✓ | | |
| Change member roles | ✓ | ✓ | | |
| Promote to owner | ✓ | | | |
| Remove members | ✓ | ✓ | | |
| Rename organization | ✓ | | | |
| Manage billing | ✓ | ✓ | | |
| Delete organization | ✓ | | | |
### Inviting Members
[Section titled “Inviting Members”](#inviting-members)
To invite a member, go to the **Members** tab on the organization page:
1. Click **Add Member**.
2. Enter the email address of the user you want to invite. The user must already have an aqua account.
3. Select a role (Admin, Member, or Viewer).
4. Click **Add**.
Note
You cannot directly assign the owner role when inviting. To transfer ownership, first add the user with another role, then promote them.
### Changing Roles
[Section titled “Changing Roles”](#changing-roles)
Admins and owners can change a member’s role from the Members tab by selecting a new role from the dropdown next to their name. Only the owner can promote someone to owner or change the owner’s role.
### Removing Members
[Section titled “Removing Members”](#removing-members)
Admins and owners can remove members by clicking the remove button next to their name on the Members tab. The owner cannot be removed from the organization.
## Projects in Organizations
[Section titled “Projects in Organizations”](#projects-in-organizations)
Projects are created through the CLI (`aqua-cli init`), not from the Web UI. When the CLI sends requests, the server uses the `X-Project-Key` header to automatically resolve which organization the project belongs to:
* If you are a member of a **team organization** that already has a project with the same key, it is used.
* Otherwise, the project is created in your **personal organization**.
### Transferring Projects
[Section titled “Transferring Projects”](#transferring-projects)
You can move a project from one organization to another through **Project Settings**:
1. Open the project’s settings page.
2. In the transfer section, select the destination organization.
3. Confirm the transfer.
You must be a member of the destination organization. All QA plans and execution history move with the project.
Transferring is immediate
Once transferred, the project and all its data belong to the new organization. Access is governed by the destination organization’s membership.
## Deleting an Organization
[Section titled “Deleting an Organization”](#deleting-an-organization)
Only the **owner** can delete a team organization. Personal organizations cannot be deleted.
Deletion is permanent
Deleting an organization removes all its projects, QA plans, execution history, and other data. This action cannot be undone.
To delete an organization:
1. Go to the **Settings** tab on the organization page.
2. Scroll to the **Danger Zone** section.
3. Click **Delete Organization** and confirm.
# Project Memory
> Accumulating and sharing project knowledge across QA sessions.
Project memory is a Markdown document stored per project on the aqua server. It serves as a persistent knowledge base that accumulates insights from QA sessions, making them available to the AI agent and team members in future sessions.
## Purpose
[Section titled “Purpose”](#purpose)
As you run QA sessions, you learn things about the application under test — how authentication works, which selectors are reliable, what constraints exist, and so on. Project memory provides a place to record this knowledge so it is not lost between sessions.
## How It Works
[Section titled “How It Works”](#how-it-works)
### What the AI agent does
[Section titled “What the AI agent does”](#what-the-ai-agent-does)
* **Reads memory at session start.** The agent automatically retrieves the project memory to understand the project context — known selectors, authentication flows, constraints, and past learnings.
* **Applies knowledge during planning.** The agent uses the information in project memory when building QA plans, choosing selectors, and configuring steps.
* **Saves new findings at session end.** After a QA session, you can ask the agent to update the project memory with what it learned:
> “Save what you learned in this session to the project memory.”
The agent will merge new insights (discovered selectors, working API patterns, timing considerations, etc.) into the existing memory.
### What you can do
[Section titled “What you can do”](#what-you-can-do)
* **Edit via the Web UI.** Project memory is viewable and editable through the aqua Web UI. This is useful for manual corrections, adding information the agent doesn’t know, or pre-populating memory before starting a session.
* **Ask the agent to show it.** You can ask the agent to retrieve the current project memory at any time:
> “Show me the project memory.”
* **Ask the agent to update specific sections.** You can direct the agent to add, change, or remove specific content:
> “Add a note to the project memory that the /api/v2 endpoints require a Bearer token.”
> “Remove the old staging URL from the project memory.”
Note
`save_project_memory` performs a **full overwrite** — the entire document is replaced. The AI agent handles this by reading the current content, merging changes, and writing the complete document back.
## Recommended Content
[Section titled “Recommended Content”](#recommended-content)
A well-maintained project memory typically includes the following sections:
### Application Architecture
[Section titled “Application Architecture”](#application-architecture)
Document the high-level structure of the application — frontend framework, backend services, API patterns, and how components relate to each other.
### Source Code Pointers
[Section titled “Source Code Pointers”](#source-code-pointers)
Note the locations of key files and directories that are relevant to testing — route definitions, API handlers, database schemas, and configuration files.
### Authentication Flows
[Section titled “Authentication Flows”](#authentication-flows)
Record how authentication works in the application — login endpoints, token formats, session management, and any test accounts available for different environments.
### Common Selectors
[Section titled “Common Selectors”](#common-selectors)
List reliable CSS selectors for frequently tested UI elements. Note any selectors that are unstable or environment-dependent.
### Constraints
[Section titled “Constraints”](#constraints)
Document known limitations, quirks, or edge cases — rate limits, required feature flags, environment-specific behaviors, or timing sensitivities.
### Test Creation Notes
[Section titled “Test Creation Notes”](#test-creation-notes)
Capture practical tips for writing tests against this application — common patterns that work well, pitfalls to avoid, and lessons learned from previous QA sessions.
## Best Practices
[Section titled “Best Practices”](#best-practices)
* **Ask the agent to update after each session.** At the end of a session, ask the agent to save what it learned. This keeps the memory current and useful.
* **Keep it concise.** Focus on information that helps create and maintain tests. Avoid duplicating documentation that exists elsewhere.
* **Structure with headings.** Use Markdown headings to organize content so the AI agent and team members can quickly find relevant information.
* **Remove stale information.** As the application evolves, review and update project memory to remove outdated details — either through the Web UI or by asking the agent.
# QA Plans
> Understanding the QA plan data model, versioning, and status lifecycle.
A QA plan is the central object in aqua. It organizes your test scenarios and steps into a structured, versioned document that can be executed against any environment.
## Data Model Hierarchy
[Section titled “Data Model Hierarchy”](#data-model-hierarchy)
The QA plan data model follows a four-level hierarchy:
```plaintext
QAPlan
└─ QAPlanVersion
└─ Scenario
└─ Step
```
Each level has a distinct role:
* **QAPlan** — The top-level container that represents an entire test plan.
* **QAPlanVersion** — An immutable snapshot of the plan at a point in time.
* **Scenario** — A named group of related test steps.
* **Step** — An individual test action (HTTP request or browser interaction).
## QAPlan
[Section titled “QAPlan”](#qaplan)
A QAPlan holds metadata about the overall test plan.
| Field | Description |
| ------------------ | ----------------------------------------------------------- |
| `name` | Human-readable name for the plan. |
| `description` | Explanation of what the plan tests. |
| `git_branch` | *(optional)* The Git branch this plan is associated with. |
| `pull_request_url` | *(optional)* A link to the related pull request. |
| `status` | Current lifecycle status: `draft`, `active`, or `archived`. |
## QAPlanVersion
[Section titled “QAPlanVersion”](#qaplanversion)
Every time you update a plan’s content, a new **QAPlanVersion** is created. Versions are immutable snapshots, meaning once created they cannot be modified. Each version receives an auto-incremented version number.
A version contains:
* **variables** — Default variable values used across scenarios and steps.
* **scenarios** — The ordered list of scenarios and their steps.
Immutability ensures that execution results always reference the exact plan content that was tested.
## Scenario
[Section titled “Scenario”](#scenario)
A scenario is a named group of steps that together verify a particular behavior or workflow.
| Field | Description |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `name` | Descriptive name for the scenario. |
| `requires` | *(optional)* A list of variable names that must be present. If any required variable is missing from the environment, the scenario is skipped. |
| `steps` | Ordered list of steps to execute. |
The `requires` field enables conditional execution. For example, a scenario that tests admin features can declare `requires: ["admin_token"]`, and it will be automatically skipped when running against an environment that does not provide that variable.
## Step
[Section titled “Step”](#step)
A step is the smallest unit of testing — a single action with optional assertions and value extraction.
| Field | Description |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `step_key` | A user-defined unique identifier for the step. Used for dependency references. |
| `action` | The type of action: `"http_request"` or `"browser"`. |
| `depends_on` | *(optional)* A list of `step_key` references that must complete before this step runs. Dependencies can cross scenario boundaries. |
| `assertions` | *(optional)* Validation checks to run against the step’s result. |
| `extract` | *(optional)* Extract values from the result for use as template variables (`{{variable}}`) in subsequent steps. |
| `condition` | *(optional)* A condition that must be met for the step to execute. If not met, the step is skipped. See [Conditional Step Execution](#conditional-step-execution) below. |
### Step Dependencies
[Section titled “Step Dependencies”](#step-dependencies)
The `depends_on` field allows you to express ordering constraints between steps. Dependencies can reference step keys in the same scenario or in different scenarios, giving you flexibility to model complex test flows.
If a dependency step has failed or was skipped, the dependent step will also be skipped.
### Extracting Values
[Section titled “Extracting Values”](#extracting-values)
The `extract` field lets you capture values from a step’s response and make them available as template variables. Extracted variables are global — they can be referenced by any subsequent step in any scenario.
For example, after creating a resource via an API call, you can extract the returned `id` and use it as `{{resource_id}}` in later steps.
### Conditional Step Execution
[Section titled “Conditional Step Execution”](#conditional-step-execution)
The `condition` field allows you to control whether a step executes based on the value of a variable. This is evaluated after `depends_on` checks. Two condition types are supported:
* **`variable_equals`** — Execute the step only if a variable equals a specific value.
* **`variable_not_equals`** — Execute the step only if a variable does NOT equal a specific value.
When a variable is undefined, `variable_equals` conditions are not met (step is skipped), while `variable_not_equals` conditions are met (step runs).
Conditional steps are typically independent preparation steps that are not connected via `depends_on` to subsequent steps. The variables used in conditions come from `extract` in previous steps.
**Example** — Run different setup steps based on a user’s role:
```json
{
"step_key": "check_role",
"action": "http_request",
"config": {
"method": "GET",
"url": "{{api_base_url}}/users/me",
"headers": { "Authorization": "Bearer {{auth_token}}" }
},
"extract": {
"user_role": "$.data.role"
}
}
```
```json
{
"step_key": "admin_setup",
"action": "http_request",
"condition": {
"type": "variable_equals",
"variable": "user_role",
"value": "admin"
},
"config": {
"method": "POST",
"url": "{{api_base_url}}/admin/prepare-test-data",
"headers": { "Authorization": "Bearer {{auth_token}}" }
}
}
```
In this example, the `admin_setup` step only runs if the extracted `user_role` variable equals `"admin"`. Otherwise, the step is skipped.
## Status Lifecycle
[Section titled “Status Lifecycle”](#status-lifecycle)
A QA plan moves through three statuses:
```plaintext
draft ◀──▶ active ──▶ archived
```
| Status | Meaning |
| ---------- | --------------------------------------------------------------------------------------------- |
| `draft` | The plan is being developed or has been updated. It can be edited and executed. |
| `active` | The plan is promoted automatically when all tests pass. Represents a validated, passing plan. |
| `archived` | The plan is no longer in use. |
**Auto-promotion:** The transition from `draft` to `active` happens automatically when an execution completes with all steps passing. This ensures that only validated plans carry the `active` status.
**Auto-demotion:** When a new version is added to an `active` plan, the status is automatically reverted to `draft`. Since the test content has changed, the plan must be re-validated by running the new version successfully.
## Cross-Scenario State Sharing
[Section titled “Cross-Scenario State Sharing”](#cross-scenario-state-sharing)
aqua provides two mechanisms for sharing state between scenarios:
1. **Extract variables** — Values extracted in any step are available globally. A variable extracted in Scenario A can be referenced in Scenario B using `{{variable}}` templates.
2. **Browser storageState** — When using the browser driver, cookies and localStorage are preserved across scenarios via the browser’s `storageState`. This means a login performed in one scenario carries over to subsequent scenarios without repeating the authentication steps.
# Self-Hosting
> Deploy aqua on your own infrastructure for full control over your data.
aqua’s cloud-hosted service is designed with security in mind, but some organizations require complete control over where their data resides. For those cases, aqua offers a self-hosted deployment option.
## Getting Started
[Section titled “Getting Started”](#getting-started)
Self-hosting is available by request. Contact us at to get access to the Docker image and setup instructions.
## Hosting Requirements
[Section titled “Hosting Requirements”](#hosting-requirements)
aqua is distributed as a **Docker image**. You will need the following infrastructure:
* **PostgreSQL** — Used as the primary database.
* **S3-compatible object storage or local disk** — Used for storing artifacts such as screenshots. You can use AWS S3, MinIO, Google Cloud Storage (with S3-compatible API), or the server’s local filesystem.
# Assertions Reference
> Complete reference for all HTTP and browser assertion types available in aqua steps.
Assertions validate the outcome of a step. The AI agent includes assertions in QA plan steps when building plans via MCP tools. Each step can contain an `assertions` array with one or more assertion objects. All assertions in a step must pass for the step to be considered successful.
## HTTP Assertions
[Section titled “HTTP Assertions”](#http-assertions)
These assertions apply to steps with the `http_request` action type.
### status\_code
[Section titled “status\_code”](#status_code)
Check that the response status code matches an exact value.
```json
{ "type": "status_code", "expected": 200 }
```
| Field | Type | Description |
| ---------- | --------------- | ------------------------------ |
| `type` | `"status_code"` | Assertion type identifier. |
| `expected` | `number` | The expected HTTP status code. |
### status\_code\_in
[Section titled “status\_code\_in”](#status_code_in)
Check that the response status code is one of the allowed values.
```json
{ "type": "status_code_in", "expected": [200, 201] }
```
| Field | Type | Description |
| ---------- | ------------------ | ----------------------------------------- |
| `type` | `"status_code_in"` | Assertion type identifier. |
| `expected` | `number[]` | An array of acceptable HTTP status codes. |
### json\_path
[Section titled “json\_path”](#json_path)
Validate a value at a specific JSON path in the response body.
```json
{ "type": "json_path", "path": "$.user.email", "expected": "alice@example.com" }
```
| Field | Type | Description |
| ----------- | ---------------------------------------- | ----------------------------------------------------------------- |
| `type` | `"json_path"` | Assertion type identifier. |
| `path` | `string` | A JSONPath expression pointing to the value to check. |
| `condition` | `"exists" \| "not_exists" \| "contains"` | *(optional)* The comparison mode. Omit for exact match. |
| `expected` | `any` | *(optional when using `exists`/`not_exists`)* The expected value. |
**Condition behavior:**
* **Omitted** — Performs an exact equality check between the value at `path` and `expected`.
* `"exists"` — Passes if a value exists at the given path. The `expected` field is ignored.
* `"not_exists"` — Passes if no value exists at the given path. The `expected` field is ignored.
* `"contains"` — Passes if the string value at `path` contains `expected` as a substring.
## Browser Assertions
[Section titled “Browser Assertions”](#browser-assertions)
These assertions apply to steps with the `browser` action type.
### element\_text
[Section titled “element\_text”](#element_text)
Check the text content of an element.
```json
{ "type": "element_text", "selector": ".welcome-message" }
```
```json
{ "type": "element_text", "selector": ".welcome-message", "contains": "Hello" }
```
| Field | Type | Description |
| ---------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `type` | `"element_text"` | Assertion type identifier. |
| `selector` | `string` | CSS selector for the target element. |
| `contains` | `string` | *(optional)* Substring that the element’s text must contain. If omitted, asserts that the element has any text content. |
### element\_visible
[Section titled “element\_visible”](#element_visible)
Assert that an element is visible on the page.
```json
{ "type": "element_visible", "selector": "#main-content" }
```
| Field | Type | Description |
| ---------- | ------------------- | ------------------------------------ |
| `type` | `"element_visible"` | Assertion type identifier. |
| `selector` | `string` | CSS selector for the target element. |
### element\_not\_visible
[Section titled “element\_not\_visible”](#element_not_visible)
Assert that an element is not visible on the page.
```json
{ "type": "element_not_visible", "selector": ".error-banner" }
```
| Field | Type | Description |
| ---------- | ----------------------- | ------------------------------------ |
| `type` | `"element_not_visible"` | Assertion type identifier. |
| `selector` | `string` | CSS selector for the target element. |
### url\_contains
[Section titled “url\_contains”](#url_contains)
Assert that the current page URL contains a substring.
```json
{ "type": "url_contains", "expected": "/dashboard" }
```
| Field | Type | Description |
| ---------- | ---------------- | ------------------------------------ |
| `type` | `"url_contains"` | Assertion type identifier. |
| `expected` | `string` | Substring that the URL must contain. |
### title
[Section titled “title”](#title)
Assert that the page title matches an exact value.
```json
{ "type": "title", "expected": "Dashboard - My App" }
```
| Field | Type | Description |
| ---------- | --------- | -------------------------- |
| `type` | `"title"` | Assertion type identifier. |
| `expected` | `string` | The expected page title. |
### screenshot
[Section titled “screenshot”](#screenshot)
Capture a screenshot. This assertion always passes and is used for visual documentation.
```json
{ "type": "screenshot", "name": "checkout-page", "description": "Final state of the checkout form" }
```
| Field | Type | Description |
| ------------- | -------------- | ----------------------------------------------------------- |
| `type` | `"screenshot"` | Assertion type identifier. |
| `name` | `string` | *(optional)* A name for the screenshot file. |
| `description` | `string` | *(optional)* A description of what the screenshot captures. |
### element\_count
[Section titled “element\_count”](#element_count)
Assert the number of elements matching a selector.
```json
{ "type": "element_count", "selector": ".cart-item", "expected": 3 }
```
| Field | Type | Description |
| ---------- | ----------------- | ----------------------------------------- |
| `type` | `"element_count"` | Assertion type identifier. |
| `selector` | `string` | CSS selector for the target elements. |
| `expected` | `number` | The expected number of matching elements. |
### element\_attribute
[Section titled “element\_attribute”](#element_attribute)
Assert the value of an element’s attribute.
```json
{ "type": "element_attribute", "selector": "#submit-btn", "attribute": "disabled", "expected": "true" }
```
| Field | Type | Description |
| ----------- | --------------------- | ------------------------------------ |
| `type` | `"element_attribute"` | Assertion type identifier. |
| `selector` | `string` | CSS selector for the target element. |
| `attribute` | `string` | The attribute name to check. |
| `expected` | `string` | The expected attribute value. |
### cookie\_exists
[Section titled “cookie\_exists”](#cookie_exists)
Assert that a cookie with the given name exists.
```json
{ "type": "cookie_exists", "name": "session_id" }
```
| Field | Type | Description |
| ------ | ----------------- | ----------------------------- |
| `type` | `"cookie_exists"` | Assertion type identifier. |
| `name` | `string` | The cookie name to check for. |
### cookie\_value
[Section titled “cookie\_value”](#cookie_value)
Assert the value of a cookie.
```json
{ "type": "cookie_value", "name": "theme", "expected": "dark", "match": "exact" }
```
| Field | Type | Description |
| ---------- | ----------------------- | ----------------------------------------------- |
| `type` | `"cookie_value"` | Assertion type identifier. |
| `name` | `string` | The cookie name. |
| `expected` | `string` | The expected cookie value. |
| `match` | `"exact" \| "contains"` | *(optional)* Match mode. Defaults to `"exact"`. |
### localstorage\_exists
[Section titled “localstorage\_exists”](#localstorage_exists)
Assert that a key exists in localStorage.
```json
{ "type": "localstorage_exists", "key": "auth_token" }
```
| Field | Type | Description |
| ------ | ----------------------- | ---------------------------------- |
| `type` | `"localstorage_exists"` | Assertion type identifier. |
| `key` | `string` | The localStorage key to check for. |
### localstorage\_value
[Section titled “localstorage\_value”](#localstorage_value)
Assert the value of a localStorage entry.
```json
{ "type": "localstorage_value", "key": "locale", "expected": "en-US", "match": "exact" }
```
| Field | Type | Description |
| ---------- | ----------------------- | ----------------------------------------------- |
| `type` | `"localstorage_value"` | Assertion type identifier. |
| `key` | `string` | The localStorage key. |
| `expected` | `string` | The expected value. |
| `match` | `"exact" \| "contains"` | *(optional)* Match mode. Defaults to `"exact"`. |
# CLI Reference
> Complete reference for all aqua-cli commands and their options.
The aqua CLI (`aqua-cli`) provides commands for authentication, project setup, test execution, and browser recording. Run any command with `npx @aquaqa/cli`.
## aqua-cli login
[Section titled “aqua-cli login”](#aqua-cli-login)
```bash
aqua-cli login [--server-url ] [--force]
```
Authenticate with the aqua server. Opens your default browser to complete the authentication flow. On success, credentials are saved to `~/.aqua/credentials.json`.
| Option | Description |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `--server-url ` | The aqua server URL to authenticate against. Required for self-hosted environments. Defaults to `https://app.aquaqa.com`. |
| `--force` | Re-authenticate even if valid credentials already exist. |
CI/CD environments
For CI/CD environments where browser-based login is not available, set the `AQUA_API_KEY` environment variable instead. See [Configuration: Environment Variables](/docs/reference/configuration/#environment-variables).
## aqua-cli logout
[Section titled “aqua-cli logout”](#aqua-cli-logout)
```bash
aqua-cli logout
```
Remove saved credentials for the server.
## aqua-cli init
[Section titled “aqua-cli init”](#aqua-cli-init)
```bash
aqua-cli init [--server-url ]
```
Initialize project configuration. Detects the git remote URL to derive a `project_key`, lets you select the organization and project, and creates a `.aqua/config.json` file in the current directory.
| Option | Description |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `--server-url ` | The aqua server URL to associate with this project. Required for self-hosted environments. Defaults to `https://app.aquaqa.com`. |
## aqua-cli whoami
[Section titled “aqua-cli whoami”](#aqua-cli-whoami)
```bash
aqua-cli whoami
```
Display information about the currently authenticated user, including user ID, email address, and display name.
## aqua-cli execute
[Section titled “aqua-cli execute”](#aqua-cli-execute)
```bash
aqua-cli execute [--env ] [--plan-version ] [--var key=value]
```
Execute a QA plan directly from the command line without going through the MCP server.
| Option | Description |
| -------------------- | ----------------------------------------------------------------- |
| `` | **(required)** The ID of the QA plan to execute. |
| `--env ` | Load environment variables from `.aqua/environments/.json`. |
| `--plan-version ` | Execute a specific plan version. Defaults to the latest version. |
| `--var key=value` | Override a variable value. Can be specified multiple times. |
## aqua-cli record
[Section titled “aqua-cli record”](#aqua-cli-record)
```bash
aqua-cli record [url]
```
Record browser actions using Playwright codegen. Opens an interactive browser window where your interactions are captured. When the browser is closed, the recorded actions are output as a `BrowserStep[]` JSON array.
| Option | Description |
| ------- | ----------------------------------------------------------- |
| `[url]` | *(optional)* The URL to navigate to when the browser opens. |
## aqua-cli web
[Section titled “aqua-cli web”](#aqua-cli-web)
```bash
aqua-cli web
```
Open the aqua web UI in your default browser.
## aqua-cli mcp-server
[Section titled “aqua-cli mcp-server”](#aqua-cli-mcp-server)
```bash
aqua-cli mcp-server
```
Start the MCP (Model Context Protocol) server. This enables AI agents such as Claude Code, Gemini CLI, OpenCode, and Cursor to interact with aqua programmatically.
Authentication is resolved in the following order of precedence:
1. `AQUA_API_KEY` environment variable
2. `~/.aqua/credentials.json` (managed by `aqua-cli login`)
The server URL is resolved in the following order of precedence:
1. `AQUA_SERVER_URL` environment variable
2. `.aqua/config.json` in the current project
3. `https://app.aquaqa.com` (default)
# Configuration Reference
> Reference for all aqua configuration files and environment variables.
aqua uses a combination of local configuration files and environment variables. This page documents each configuration source and its schema.
## \~/.aqua/credentials.json
[Section titled “\~/.aqua/credentials.json”](#aquacredentialsjson)
Stores authentication credentials for one or more aqua servers. This file is managed automatically by the `aqua-cli login` and `aqua-cli logout` commands.
The file contains a map of server URLs to their authentication tokens. You should not edit this file manually.
If the `AQUA_API_KEY` environment variable is set, it takes precedence over the credentials file. See [Environment Variables](#environment-variables) below.
**Location:** `~/.aqua/credentials.json` (user home directory)
## .aqua/config.json
[Section titled “.aqua/config.json”](#aquaconfigjson)
Project-level configuration created by `aqua-cli init`. This file lives in your project root and is typically committed to version control.
```json
{
"server_url": "https://app.aquaqa.com",
"project_key": "github.com/owner/repo"
}
```
| Field | Type | Description |
| ------------- | -------- | --------------------------------------------------------------------- |
| `server_url` | `string` | The URL of the aqua backend server. |
| `project_key` | `string` | A unique identifier for the project, derived from the git remote URL. |
## .aqua/environments/\.json
[Section titled “.aqua/environments/\.json”](#aquaenvironmentsnamejson)
Environment files define variables, secrets, and proxy settings for test execution. Each file represents a named environment (e.g., `staging.json`, `production.json`).
```json
{
"variables": {
"base_url": "https://staging.example.com",
"api_version": "v2"
},
"secrets": {
"api_key": {
"type": "env",
"key": "STAGING_API_KEY"
},
"db_password": {
"type": "gcp_secret",
"project": "my-project",
"secret": "db-password",
"version": "latest"
}
},
"proxy": {
"server": "http://proxy.internal:8080",
"ca_cert_path": "/path/to/ca.pem",
"reject_unauthorized": false
},
"notes": "Staging environment for integration tests"
}
```
| Field | Type | Description |
| ----------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `variables` | `Record` | Key-value pairs of plain-text variables available during execution. |
| `secrets` | `Record` | Named secrets resolved at execution time. See secret types below. |
| `proxy` | `object` | *(optional)* HTTP proxy configuration. See [Environments: Proxy](/guides/environments/#proxy) for all fields including TLS options (`ca_cert_path`, `proxy_ca_cert_path`, `reject_unauthorized`). |
| `notes` | `string` | *(optional)* A human-readable description of the environment. |
### Secret Types
[Section titled “Secret Types”](#secret-types)
Secrets are resolved at execution time and never stored in plain text in the environment file.
**Environment variable:**
```json
{ "type": "env", "key": "ENV_VAR_NAME" }
```
Reads the value from the specified OS environment variable.
**GCP Secret Manager:**
```json
{ "type": "gcp_secret", "project": "gcp-project-id", "secret": "secret-name", "version": "latest" }
```
Fetches the secret from Google Cloud Secret Manager.
## Environment Variables
[Section titled “Environment Variables”](#environment-variables)
| Variable | Description |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `AQUA_API_KEY` | API key for authentication. Takes precedence over `~/.aqua/credentials.json`. Useful for CI/CD environments where browser-based login is not available. |
| `AQUA_SERVER_URL` | Override the aqua server URL. Takes precedence over `.aqua/config.json` but is overridden by the `--server-url` CLI flag. |
# MCP Tools Reference
> Complete reference for all MCP tools exposed by the aqua MCP server.
The aqua MCP server exposes the following tools. These tools allow AI agents to create, manage, and execute QA plans programmatically.
## Plan Management
[Section titled “Plan Management”](#plan-management)
Tools for creating and managing QA plans and their versions.
| Tool | Description |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `create_qa_plan` | Create a new QA plan. Auto-detects the current git branch and pull request URL. |
| `get_qa_plan` | Retrieve a plan by ID, including its latest version information. |
| `list_qa_plans` | List plans with optional status filter and cursor-based pagination. |
| `update_qa_plan` | Create a new immutable version with the full scenario and step structure. Steps support an optional `condition` field for conditional execution based on variable values. |
| `update_qa_plan_step` | Partial update of a single step. Creates a new plan version. Supports setting a `condition` for conditional execution. |
| `add_qa_plan_step` | Add a step to a scenario. Creates a new plan version. Supports setting a `condition` for conditional execution. |
| `remove_qa_plan_step` | Remove a step by its key. Creates a new plan version. Fails if other steps depend on it. |
| `set_qa_plan_status` | Change the plan status: `draft`, `active`, or `archived`. |
## Execution
[Section titled “Execution”](#execution)
Tools for running QA plans and inspecting results.
| Tool | Description |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `execute_qa_plan` | Execute a full plan and record results on the server. Returns a markdown summary and an execution URL. Supports an `async` parameter for background execution. |
| `run_scenario` | Execute a single inline scenario without recording results on the server. Returns detailed debug output. |
| `get_execution` | Fetch execution results including per-step details. |
| `list_executions` | List executions filtered by plan ID, version, or status. |
| `get_execution_progress` | Get the current progress of a running execution. Use this to monitor async executions started with `execute_qa_plan(async=true)`. |
## Environment
[Section titled “Environment”](#environment)
Tools for managing environment configurations used during execution.
| Tool | Description |
| ---------------------- | ----------------------------------------------------------------------------- |
| `create_environment` | Create or overwrite an environment file at `.aqua/environments/.json`. |
| `list_environments` | List all environment configurations with their notes. |
| `validate_environment` | Validate an environment file’s schema and check that secrets can be resolved. |
## Common Scenario
[Section titled “Common Scenario”](#common-scenario)
Tools for managing reusable scenario templates that can be copied into QA plans.
| Tool | Description |
| ------------------------ | ---------------------------------------------------------------------------- |
| `create_common_scenario` | Create a reusable scenario template. |
| `get_common_scenario` | Retrieve a common scenario by ID. |
| `list_common_scenarios` | List all common scenarios in the project. |
| `update_common_scenario` | Update an existing common scenario. |
| `delete_common_scenario` | Delete a common scenario. Does not affect plans that have already copied it. |
## Recording
[Section titled “Recording”](#recording)
Tools for capturing browser interactions.
| Tool | Description |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------- |
| `record_browser_actions` | Open an interactive browser window to record user actions. Returns the recorded actions as a `BrowserStep[]` array. |
## Exploration
[Section titled “Exploration”](#exploration)
Tools for interactively investigating your application one action at a time. Unlike `run_scenario`, exploration sessions keep the browser alive between calls, allowing you to try selectors, inspect responses, and build up state incrementally. See the [Interactive Exploration](/docs/guides/exploration/) guide for details.
| Tool | Description |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `start_exploration` | Start an interactive exploration session. The browser is maintained between actions so you can build up state incrementally. |
| `explore_action` | Execute an action within a session (browser step, HTTP request, or browser assertion) and get immediate feedback. |
| `end_exploration` | End an exploration session and clean up resources (browser process, memory). |
| `list_exploration_logs` | List recent exploration session logs for the current project. |
| `get_exploration_log` | Get the full action log from a specific exploration session. Can be used to replay successful actions. |
## Memory
[Section titled “Memory”](#memory)
Tools for managing persistent project-level knowledge.
| Tool | Description |
| --------------------- | ---------------------------------------------------------------------------------------- |
| `get_project_memory` | Retrieve the project memory. Returns a starter template if no memory has been saved yet. |
| `save_project_memory` | Save project memory. Performs a full overwrite of the existing content. |
## Setup
[Section titled “Setup”](#setup)
Tools for checking project readiness.
| Tool | Description |
| --------------------- | ------------------------------------------------------------------------------------------------------- |
| `check_project_setup` | One-shot status check that reports on local config, project memory, environments, and common scenarios. |
# Step Actions Reference
> Detailed schema reference for http_request and browser step actions.
Each step in a QA plan performs one of two action types: `http_request` or `browser`. The AI agent selects and configures these actions when building QA plans via MCP tools. This page documents the full configuration schema for both.
## http\_request
[Section titled “http\_request”](#http_request)
The `http_request` action sends an HTTP request and validates the response.
### HttpRequestConfig
[Section titled “HttpRequestConfig”](#httprequestconfig)
| Field | Type | Required | Description |
| --------- | ------------------------ | -------- | ----------------------------------------------------------------------------------------------- |
| `method` | `string` | Yes | HTTP method: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, etc. |
| `url` | `string` | Yes | The request URL. Supports template variables (e.g., `{{base_url}}/api/users`). |
| `headers` | `Record` | No | Request headers as key-value pairs. Values support template variables. |
| `body` | `any` | No | The request body. Objects are serialized as JSON. Supports template variables in string values. |
| `timeout` | `number` | No | Request timeout in milliseconds. |
| `poll` | `PollConfig` | No | Poll the endpoint until a condition is met. |
### PollConfig
[Section titled “PollConfig”](#pollconfig)
Some API endpoints require polling — repeating a request until a condition is met. When `poll` is specified, the request is repeated at a fixed interval until the `until` condition is satisfied or the timeout is reached.
| Field | Type | Required | Description |
| ------------------- | -------- | -------- | --------------------------------------------------------------------------------------------------- |
| `until` | `object` | Yes | The condition to check. Must specify one of the sub-fields below. |
| `until.status_code` | `number` | No | Poll until the response status code matches this value. |
| `until.json_path` | `object` | No | Poll until a JSON path in the response body matches. Contains `path` (string) and `expected` (any). |
| `interval_ms` | `number` | Yes | Milliseconds to wait between each poll request. |
| `timeout_ms` | `number` | Yes | Maximum total time in milliseconds before the poll is considered failed. |
**Polling example** — wait for an async job to complete:
```json
{
"action": "http_request",
"config": {
"method": "GET",
"url": "{{api_base_url}}/jobs/{{job_id}}"
},
"poll": {
"until": {
"json_path": "$.status",
"equals": "completed"
},
"interval_ms": 2000,
"timeout_ms": 60000
}
}
```
### Extract
[Section titled “Extract”](#extract)
The `extract` field captures values from the HTTP response for use in subsequent steps. Each extraction uses a JSONPath expression to locate the value in the response body. Extracted values become template variables accessible via `{{variable_name}}`.
```json
{
"extract": {
"user_id": "$.data.id",
"user_name": "$.data.name"
}
}
```
After this step executes, `{{user_id}}` and `{{user_name}}` are available in all subsequent steps.
### Example
[Section titled “Example”](#example)
The following example creates a user, extracts the returned ID, and then retrieves the user to verify it was created correctly.
**Step 1 — Create user:**
```json
{
"step_key": "create_user",
"action": "http_request",
"config": {
"method": "POST",
"url": "{{api_base_url}}/users",
"headers": {
"Content-Type": "application/json",
"Authorization": "Bearer {{auth_token}}"
},
"body": "{\"name\": \"Test User\", \"email\": \"test@example.com\"}"
},
"assertions": [
{ "type": "status_code", "expected": 201 },
{ "type": "json_path", "expression": "$.data.name", "equals": "Test User" }
],
"extract": {
"created_user_id": "$.data.id"
}
}
```
**Step 2 — Retrieve user:**
```json
{
"step_key": "get_user",
"action": "http_request",
"depends_on": ["create_user"],
"config": {
"method": "GET",
"url": "{{api_base_url}}/users/{{created_user_id}}",
"headers": {
"Authorization": "Bearer {{auth_token}}"
}
},
"assertions": [
{ "type": "status_code", "expected": 200 },
{ "type": "json_path", "expression": "$.data.email", "equals": "test@example.com" }
]
}
```
## Step Condition
[Section titled “Step Condition”](#step-condition)
The `condition` field on a step controls whether the step executes based on a variable’s value. If the condition is not met, the step is skipped (same behavior as `depends_on` or `requires` skips).
Condition checks are evaluated after `depends_on` checks. The variables referenced in conditions typically come from `extract` in earlier steps.
### ConditionConfig
[Section titled “ConditionConfig”](#conditionconfig)
| Field | Type | Required | Description |
| ---------- | -------- | -------- | ------------------------------------------------------------------- |
| `type` | `string` | Yes | The condition type: `"variable_equals"` or `"variable_not_equals"`. |
| `variable` | `string` | Yes | The name of the variable to check. |
| `value` | `string` | Yes | The value to compare against. |
### variable\_equals
[Section titled “variable\_equals”](#variable_equals)
Execute the step only if the variable equals the specified value. If the variable is undefined, the condition is **not met** and the step is skipped.
```json
{
"condition": {
"type": "variable_equals",
"variable": "user_role",
"value": "admin"
}
}
```
### variable\_not\_equals
[Section titled “variable\_not\_equals”](#variable_not_equals)
Execute the step only if the variable does NOT equal the specified value. If the variable is undefined, the condition **is met** and the step runs.
```json
{
"condition": {
"type": "variable_not_equals",
"variable": "payment_method",
"value": "free"
}
}
```
## browser
[Section titled “browser”](#browser)
The `browser` action drives a headless browser using [Playwright](https://playwright.dev/).
### BrowserConfig
[Section titled “BrowserConfig”](#browserconfig)
| Field | Type | Required | Description |
| ------------ | --------------- | -------- | -------------------------------------------------------------------- |
| `steps` | `BrowserStep[]` | Yes | An ordered array of browser actions to execute. |
| `timeout_ms` | `number` | No | Maximum time in milliseconds for the entire browser action sequence. |
### Browser Step Types
[Section titled “Browser Step Types”](#browser-step-types)
Each entry in the `steps` array is an object with a `type` field and type-specific parameters.
#### Navigation
[Section titled “Navigation”](#navigation)
| Type | Parameter | Description |
| ------ | -------------- | ----------------------------------------------- |
| `goto` | `string` (URL) | Navigate to a URL. Supports template variables. |
Note
If a `goto` action fails (e.g., the page returns an error), all remaining actions in the current scenario are aborted.
#### Mouse Actions
[Section titled “Mouse Actions”](#mouse-actions)
| Type | Parameter | Description |
| -------------- | ----------------------- | ------------------------ |
| `click` | `string` (CSS selector) | Click an element. |
| `double_click` | `string` (CSS selector) | Double-click an element. |
| `hover` | `string` (CSS selector) | Hover over an element. |
#### Form Input
[Section titled “Form Input”](#form-input)
| Type | Parameter | Description |
| --------------- | ------------------------------------- | ------------------------------------------------------------------------ |
| `type` | `{ selector: string, text: string }` | Type text into an input field. Both fields support template variables. |
| `select_option` | `{ selector: string, value: string }` | Select an option in a `