Skip to main content
Skip to Content

Some browser and device services need more than a URL: a session has to be created before each test and deleted afterwards, the connection signed, your app uploaded or a tunnel opened. A plugin does that work for one service, and agent-qa does the rest: connecting, masking credentials, recording evidence and cleaning up.

Each plugin is one npm package. You enable it once in plugins with your account's options, and each remote that runs tests on the service names it.

Browsers and devices

PluginWeb testsMobile testsBrowsersSession linkMarks the session
BrowserStackOver PlaywrightAndroid and iOS, over AppiumChrome, Edge, Chromium, Firefox, WebKitYesPassed or failed
HyperbrowserOver CDPNoChromiumYesNo
KernelOver CDPNoChromiumNoNo
SteelOver CDPNoChromiumYes, except self-hostedNo

BrowserStack runs web tests only on the Playwright versions it lists, and agent-qa 0.3.2's Playwright 1.64 is not on that list yet. Device tests are not affected. See BrowserStack.

A Playwright server, a CDP endpoint or an Appium server that only needs a URL and credentials needs no plugin. List it under registry.remotes with its url. See Remote browsers and devices.

Model sign-in

The subscription plugin runs inside agent-qa and needs no remote. Only vostride's own @vostride/agent-qa-* packages may run inside agent-qa; every browser and device plugin runs as a separate process.

Add a plugin

  1. Install the package

    Install a first-party plugin at exactly the version of agent-qa your project runs. Plugins are released with agent-qa and share its version:

    npm install --save-dev --save-exact @vostride/agent-qa-plugin-kernel@$(npx agent-qa --version)

    npx agent-qa plugins list prints this line, with the version filled in, when the package is missing or its version differs from agent-qa's.

  2. Declare it

    Add an entry to plugins with the account's options. Write each credential as a {{secret:NAME}} reference, and put the value in the file workspace.secretsFile names, .env.secrets.local by default:

    plugins:
      - name: kernel
        package: "@vostride/agent-qa-plugin-kernel"
        options:
          apiKey: "{{secret:KERNEL_API_KEY}}"
    # .env.secrets.local
    KERNEL_API_KEY=sk_your_kernel_key
  3. Add a remote that names it

    A remote is one place tests run. It names the entry with plugin and holds that place's settings:

    registry:
      remotes:
        - name: kernel
          plugin: kernel
          settings:
            headless: true
  4. Pick the remote

    A web test runs there when use.browser.remote names it, in the config, a suite or the test. A mobile test runs there when its device's remote names it:

    use:
      browser:
        name: chromium
        headless: true
        remote: kernel
  5. Check it

    npx agent-qa plugins list
    npx agent-qa doctor

    plugins list reads each package's manifest. doctor runs each plugin's account check, which opens no paid session.

Entries and remotes

A plugins entry is the account. A remote is one place on that account. One entry can serve several remotes, such as a BrowserStack remote for Chrome on Windows, another for WebKit on macOS and a third for devices.

plugins entry keyMeaning
nameThe entry's name, a lowercase slug unique in the list. Remotes name it.
packageThe plugin's npm package name, exactly as installed. agent-qa never adds a prefix or guesses a name.
pathA plugin folder inside the project, instead of package. For plugins you are developing.
optionsThe account's values: keys, endpoints, tunnels. Checked against the plugin's own schema.
Plugin remote keyDefaultMeaning
nameThe remote's name, a lowercase slug. local is reserved for this machine.
pluginThe plugins entry that serves it.
settingsThis place's values: operating system, region, pool, profile and so on. Checked against the plugin's own schema.
connectTimeout5mHow long the plugin may take to hand over a session, including a queue.
uploadTimeout10mHow long an app upload may take, for device remotes.
contextnewnew opens agent-qa's own browser context. reuse uses the browser's first context, which signed-in profiles need.
capabilitiesAppium capabilities for device sessions on this remote.

A plugin remote has no url, query, headers or basicAuth, because the plugin supplies the connection. An entry's values go under options, and a remote's under settings. validate refuses each mix-up with a sentence that says where the key belongs.

agent-qa plugins describe <entry> prints every option and setting a plugin takes, read from the schemas the package ships. Read it before you write options or settings:

$ npx agent-qa plugins describe kernel
kernel  @vostride/agent-qa-plugin-kernel  first-party  0.3.2  protocol 1
serves: cdp
methods: check
receives: session facts only
skill: ./skill

Options
  field   type    required  default                     credential  description
  apiKey  string  required  -                           credential  The Kernel API key
  apiUrl  string  optional  "https://api.onkernel.com"  -           Kernel's API, https:// unless it points at this machine
Settings
  field                 type             required  default  credential  description
  headless              boolean          optional  true     -           Run a headless browser; Kernel offers a live view only for a headful one
  timeoutSeconds        integer          optional  60       -           Seconds with no connection before Kernel deletes the browser
  stealth               boolean          optional  -        -           Kernel's stealth mode
  region                string           optional  -        -           The Kernel region, for example eu-west
  proxy                 object           optional  -        -           Kernel's proxy, sent as given
  viewport              object           optional  -        -           The browser window size
  viewport.width        integer          required  -        -
  viewport.height       integer          required  -        -
  viewport.refreshRate  integer          optional  -        -
  pool                  string           optional  -        -           A Kernel browser pool, by id or name, to acquire from instead of creating a browser
  profile               string | object  optional  -        -           A Kernel profile loaded read-only, by name or as { id }; needs context: reuse
  extra                 object           optional  -        -           Fields merged last into the create or pool acquire request, overriding the rest

--json prints the same as JSON.

Check your plugins

agent-qa plugins list shows each entry with its origin, version, protocol, the remotes that name it and its state. It reads manifests only and runs no plugin code:

$ npx agent-qa plugins list
subscription  @vostride/agent-qa-subscription-auth  first-party  0.3.2  protocol -  remotes: none  ok
kernel  @vostride/agent-qa-plugin-kernel  first-party  0.3.2  protocol 1  remotes: kernel  ok
steel  @vostride/agent-qa-plugin-steel  first-party  -  protocol -  remotes: steel  not_installed
  Plugin entry steel names @vostride/agent-qa-plugin-steel, which is not installed. Run npm install --save-dev --save-exact @vostride/agent-qa-plugin-steel@0.3.2.
StateMeaning
okInstalled, with a valid manifest that this agent-qa can run.
not_installedThe package is missing, or path has no package.json inside the project. The line says what to run.
version_mismatchA first-party plugin at another version than agent-qa. Install the version the line names.
protocol_mismatchA third-party plugin that speaks a protocol this agent-qa does not. Update agent-qa or rebuild the plugin.
bad_manifestThe package has no valid plugin manifest, or is an alias of another package.
unusedNo remote names the entry. Name it from a remote, or remove it.

agent-qa doctor adds a row for each plugin and each remote: its origin, version and protocol, the result of its account check, any {{secret:NAME}} it uses that your secrets file does not declare, and the install line when it is missing. The checks read the account, such as free sessions or a pool, and never open a paid session. doctor --remote <name> shows only that remote.

agent-qa validate checks entries and plugin remotes without running plugin code: each entry's options and each remote's settings against the schemas the plugin ships, for the remotes your tests and suites would use.

During a run

  1. agent-qa starts the plugin as its own Node process, once per entry, the first time a test needs it.
  2. Before a test connects, agent-qa asks the plugin for a session. The plugin creates one, takes one from a pool or waits in a queue, and tells agent-qa what to connect to. Its progress, such as waiting for pool shop or uploading app (84 MB), prints in the run and on the dashboard's live run page. Progress never extends connectTimeout.
  3. agent-qa connects with Playwright or WebdriverIO and runs the test. A plugin that returns a link to the session, such as a BrowserStack dashboard page, has it printed as Remote <name>: <link> when the test starts, and recorded with the run.
  4. When the test ends, the plugin is told the outcome if it wants it, which is how BrowserStack marks sessions, and then releases the session. That happens whether the test passed, failed, timed out or was cancelled.
  5. When the run ends, agent-qa stops each plugin process.

A suite holds one session for all of its tests.

Sessions are released even when a run is stopped. On Ctrl+C, plugin sessions get up to five seconds to release before agent-qa exits with code 130. If agent-qa is killed outright, the plugin notices its parent is gone and releases what it holds before it exits.

When a remote cannot serve a test, the test is refused before it starts, with one sentence that says why. Only the tests placed on that remote fail; the rest of the run goes on, and the run exits 2. The sentence names one of these failure kinds:

KindMeaning
authThe service refused the credentials.
capacityNo free session, a full pool, or a rate limit.
unreachableThe service could not be reached, or a tunnel did not start.
versionThe service does not support this agent-qa's Playwright version.
refusedThe service refused the request, or an option or setting is wrong. A path such as settings.profile points at the line to fix.
timeoutThe session did not arrive within connectTimeout.
ended, lostThe session ended, or the connection dropped, while the test ran.

The run's analysis counts a refused test as an environment problem, not a flaky one.

Security

  • A plugin is a separate process. Its code never runs inside agent-qa. It talks to agent-qa over its standard input and output, and anything else it writes there stops it.
  • Credentials reach it only in messages. A plugin's environment holds only the path, home, temp, locale, time zone, proxy and certificate variables. Your shell's other variables never reach it.
  • What it sends back is masked. Connection URLs, tokens and live-view links a plugin marks are masked in logs, records and output, in their encoded forms too. A plugin's own log is masked and shown only at the debug log level.
  • Connection secrets stay connection secrets. A secret used in options, settings or capabilities is used only to connect to the service. Steps, expected values, target URLs and hooks cannot use it.
  • Only you add plugins. The dashboard and MCP show a plugins entry without its options, and neither can add, change or remove an entry or a plugin remote; you edit those in the config file. The one exception is the subscription entry, which config.auth.set can add.
  • Vendors keep their own records. Some services record sessions and keep the replay on their dashboard, behind their login. agent-qa's masking does not reach those replays. Use test credentials.

Third-party and your own plugins

Any npm package with an agent-qa plugin manifest can be an entry. Name it exactly with package, install it with your package manager, and agent-qa checks that it speaks a plugin protocol it supports. While you build one, point path at its folder. See Write a plugin.

Skills for coding agents

Each first-party plugin ships a skill with its service's settings and refusals, in the package's skill/ folder. plugins describe names the folder. Copy it next to agent-qa's own skills, such as .claude/skills/agent-qa-plugin-kernel/ for Claude Code or .agents/skills/agent-qa-plugin-kernel/ for Codex. See Skills.