TESTPILOT / FLIGHT MANUAL 01

From plain English
to a proven browser run.

Install TestPilot, write the workflow like a person, and follow every browser action, check, and screenshot from one clear manual.

Start the first run
QUICK ROUTEREADY
1TEXT FILE
0SELECTORS IN TESTS
100%VISIBLE EVIDENCE
01 / START

Your first green run.

Five checkpoints take you from an empty machine to a real browser test with a report you can open and share.

CHECKPOINT 01 / 05

Add the TestPilot command

Install the public launcher globally so the testpilot command is available from any project.

Requires Node.js 22 or newer and the system tar command.
install.sh
npm install --global @macevoorhees/testpilot
01Node.js 22+

The public launcher runs on the current Node LTS generation.

02Supported computer

macOS Apple silicon/Intel, Windows x64, or glibc Linux arm64/x64.

03No extra runtime setup

TestPilot brings .NET, Playwright, and its console. Alpine/musl is not supported.

WHY GLOBAL?

Use --global during installation. A local npm install may succeed but leave a bare testpilot command unavailable in your shell.

02 / WRITE

A test that explains itself.

Click any line to see what TestPilot understands, how it carries context forward, and what evidence the line must produce.

record-random-sales.pilot
NATURAL LANGUAGE8 LINES / 6 EXECUTABLE STEPS
new test named "…"Starts a test

The header is unindented. One file can contain multiple tests.

two leading spacesCreates a step

Every indented line is timed, executed, and reported independently.

@tags recipe, serialAdds metadata

Tags apply to one test. Only serial changes built-in scheduling.

@viewport 1920x1200Changes one viewport

Optional test metadata from 640×480 through 7680×4320.

# a helpful commentDocuments intent

Comments and blank lines are ignored by execution.

.pilot or .testpilotNames the file

Ordinary unmatched steps use Computer Use automatically.

Reliable unique data

Reuse the same value without model memory.

Use a named saved value for generated numbers, strings, and booleans—or a visible run-ID placeholder when the identifier should remain obvious in the file.

  • Isolated to one test
  • Generated and owned by the framework
  • Sensitive values are rejected
unique-recipe.pilot
new test named "Create a unique recipe"
  create a recipe named "AUTO_RECIPE_<final 8 characters of the run id>"
  search for "AUTO_RECIPE_<final 8 characters of the run id>"
  verify that exact recipe is visible
WRITE MUTATIONS PRECISELY

Say which visible dialog or section owns the field, ask to replace its entire value and verify the exact whole value, then name the exact Save control to click once. Every test may change data when its authored steps require it.

03 / REUSE

Teach the common routes once.

Action aliases keep specs natural while stable guidance or protected browser recipes handle workflows the team repeats.

DEFAULTComputer action

Add product-specific guidance while Computer Use still reads and controls the visible browser. The executor line is optional because computer is the default.

analytics.action
new action named "open analytics"
  aliases "go to analytics", "open the analytics module"
  use executor "computer"
  guidance:
    Open Analytics from the visible application navigation.
    Confirm the page heading before marking the step complete.
PROTECTEDBrowser action

Use a deterministic recipe for credential-bearing flows. Required values resolve locally and are not included in the model prompt.

login.action
new action named "login"
  aliases "login using the application credentials"
  use executor "browser"
  requires "APP_EMAIL"
  requires "APP_PASSWORD"
  browser:
    go to the environment start page
    fill "input[name='email']" with credential "APP_EMAIL"
    fill "input[name='password']" with credential "APP_PASSWORD"
    click "button[type='submit']"
    wait until the page URL does not contain "login"
SUPPORTED BROWSER RECIPE LINES
go to the environment start pagefill "selector" with credential "VARIABLE"fill "selector" with text "value"click text "Exact label"click "selector"wait 1000 millisecondswait until the page URL does not contain "login"verify "selector" is visible
inspect-actions.sh
testpilot actions list
testpilot actions validate
local-credentials.sh
testpilot credentials list
testpilot credentials set APP_EMAIL
04 / CONFIGURE

One suite. Clear boundaries.

Each project owns its model key, reusable actions, test files, output, and strict list of environments.

CREATED BY TESTPILOT INIT
my-suite/
├── actions/
├── specs/
│   └── example.pilot
├── .env.local
├── .env.example
├── .gitignore
├── README.md
└── testpilot.config.json
PRIVATE.env.local

Project API key and local variables. Ignored by source control.

READABLEspecs/

Natural-language tests that teammates can review.

REUSABLEactions/

Aliases, guidance, and protected browser recipes.

STRICTtestpilot.config.json

Model, deadline, directories, and HTTPS environments.

testpilot.config.json
{
  "name": "My TestPilot suite",
  "specsDirectory": "specs",
  "actionsDirectory": "actions",
  "outputDirectory": "output",
  "openAi": {
    "apiKeyVariable": "TEST_PILOT_AI_API_KEY",
    "model": "gpt-5.6-luna",
    "maxTurnsPerStep": 30
  },
  "execution": {
    "stepTimeoutSeconds": 120
  },
  "safety": {
    "allowModelCode": false
  },
  "environments": {
    "example": {
      "baseUrl": "https://example.com/",
      "allowedHosts": ["example.com"]
    }
  }
}
TUNE THE TURN LIMIT

openAi.maxTurnsPerStep defaults to 30. Change it to any whole number from 1 through 200. The limit resets for every authored step, so it is not a cap on the whole test.

ENVIRONMENTSNo arbitrary URL override

The selected base host must be allowlisted, and top-level navigation outside it is blocked.

MODELgpt-5.6-luna by default

Override with TESTPILOT_MODEL only when the chosen model supports the built-in computer tool.

OPTIONALBounded JavaScript semantics

allowModelCode stays off in new projects. Enable it only on disposable, least-privilege runners; screenshot Computer Use remains the fallback.

The four clocks

Every limit resets for the next authored step.

120sStep deadline

execution.stepTimeoutSeconds limits one natural-language line—not the whole test.

30Computer turns

openAi.maxTurnsPerStep is configurable from 1 through 200 and stops a fast no-progress loop.

150sAPI request

openAi.requestTimeoutSeconds limits one OpenAI request.

300sBrowser operation

browser.operationTimeoutSeconds limits one Playwright operation.

05 / RUN

Run exactly what you mean.

Target one file, a folder, or the entire configured suite. Build the command visually, then paste it into your project terminal.

COMMAND BUILDER

Choose the run. Copy the command.

LIVE
YOUR COMMAND
testpilot run specs --env example

Nothing runs from this page. Paste the command into a terminal inside your test project.

MODEBEHAVIORBEST FOR
auto

Parallelizes normal tests, then runs serial tests one at a time.

Most local runs
parallel

Uses the local worker pool for normal tests, then preserves serial tests.

Explicit concurrency
serial

Runs every selected test in stable order with one active browser test.

Debugging and tight memory
LIVE CONSOLEOne stable block per test

Tests and individual steps show running, passed, failed, or skipped. Horizontal dividers keep runs readable.

DETAILSPress Ctrl+O locally

Toggle model and browser activity while the run continues. --details starts it visible.

RETRIESFailures stay honest

Failed steps and tests are not automatically rerun. Only transient API requests retry—initial request plus two attempts by default.

FAILUREOther tests keep moving

A failed or timed-out step skips the rest of that test while unrelated parallel tests continue.

06 / SCALE

Parallelism at the right layer.

Workers share one machine. Shards split the suite across CI containers. Combine both deliberately instead of making every container fight for memory.

20TEST FILES
CONTAINER 015 files1 browser at a time
CONTAINER 025 files1 browser at a time
CONTAINER 035 files1 browser at a time
CONTAINER 045 files1 browser at a time
LOCAL WORKERS--workers 4

Up to four isolated browser contexts inside the current machine or container.

CI SHARDS--shard 2/4

One deterministic slice. CircleCI node index and total are detected automatically.

MEMORY-FIRST PATTERNOne browser per container

Give each container multiple files but run them serially with --workers 1.

CI activation

One license pair across every shard.

Pre-provision an activation token and matching stable installation ID. Do not activate parallel containers independently with the raw license key.

CircleCI project variables
TESTPILOT_ACTIVATION_TOKEN=tpa_...
TESTPILOT_INSTALLATION_ID=circleci-my-project
TEST_PILOT_AI_API_KEY=your-project-key
merge-results.sh
testpilot merge shard-a/run.json shard-b/run.json \
  --out aggregate-report \
  --expect-tests 20
SERIAL TESTS + BUILT-IN SHARDS

Built-in multi-shard selection rejects a set that contains a serial test. For mixed suites, distribute whole spec files in the CI workflow and run each assigned file set locally with one worker.

07 / EVIDENCE

Every result brings receipts.

Each run writes one portable bundle for people, CI systems, and fast visual diagnosis.

01
report.html

Expandable tests, per-step status, timings, details, and screenshots.

HUMAN
02
run.json

The structured source used to merge evidence from multiple shards.

MERGE
03
junit.xml

Machine-readable test results for CircleCI and other CI interfaces.

CI
04
step-XX-passed.png

A screenshot after each step by default, with failure evidence always attempted.

VISUAL
TestPilot reportRun A72F
RECORD RANDOM SALES

6 of 6 steps passed

✓ Evidence captured

✓ passed verify final sales equals the saved "sales amount" 4.2s

08 / REFERENCE

The complete command deck.

Search every TestPilot command by its name, outcome, or the problem you are trying to solve.

01Setup

Install TestPilot

Install the public launcher globally and make the testpilot command available in your shell.

npm install --global @macevoorhees/testpilot
02Setup

Activate this installation

Enter a license key through a hidden prompt and download the verified private runtime.

testpilot activate
03Setup

Remove local activation

Remove the saved activation state from this computer.

testpilot deactivate
04Setup

Create a test project

Scaffold a standalone suite. Omit the directory to initialize the current folder.

testpilot init [directory]
05Inspect

Check readiness

Inspect configuration, browser availability, and declared credential presence without changing them.

testpilot doctor [--project|-p directory]
06Setup

Install the compatible browser

Explicitly install TestPilot's pinned Chromium build when automatic readiness needs recovery.

testpilot install-browser
07Inspect

Validate the suite

Check config, reusable actions, and selected .pilot files without running the browser.

testpilot validate [paths...] [--project|-p directory]
08Inspect

List environments

Show the project's strict environment and host allowlist.

testpilot environments|envs [--project|-p directory]
09Inspect

List reusable actions

Show action names, aliases, executors, and required variables in the selected suite.

testpilot actions list [--project|-p directory]
10Inspect

Validate reusable actions

Check every .action file and its browser recipe without executing it.

testpilot actions validate [--project|-p directory]
11Inspect

Check credential presence

Report whether declared variables are available without printing their values.

testpilot credentials list [--project|-p directory]
12Setup

Save a local credential

Prompt privately and save one suite-scoped credential in macOS Keychain.

testpilot credentials set VARIABLE [--project|-p directory]
13Author

Convert a text file

Turn pasted natural-language lines into a .pilot test and reuse any matching action aliases.

testpilot convert scenario.txt --name "My test"
14Author

Convert piped text

Read plain text from standard input and choose the destination file explicitly.

testpilot convert - --name "My test" --out specs/my-test.pilot
15Run

Run a folder

Discover and run every selected test under a directory using automatic scheduling.

testpilot run specs --env example
16Run

Watch one file run

Open a visible browser and run only the selected .pilot file.

testpilot run specs/checkout.pilot --env example --headed
17Run

Run locally in parallel

Use up to four isolated browser contexts on this machine.

testpilot run specs --env example --mode parallel --workers 4
18Run

Run everything serially

Execute each selected test in stable order with one active test at a time.

testpilot run specs --env example --mode serial
19Run

Run one CI shard

Select a deterministic one-based slice of the suite. CircleCI node variables are detected automatically.

testpilot run specs --env example --shard 2/4
20Run

Filter by tags

Include or exclude organizational tags. Repeat either option to add more filters.

testpilot run specs --env example --include-tag checkout --exclude-tag slow
21Run

Preview the selection

Validate discovery and emit reports without opening a browser or calling OpenAI.

testpilot run specs --env example --dry-run
22Run

Print detailed activity

Keep model and browser activity visible continuously. Locally, Ctrl+O toggles the same panel.

testpilot run specs --env example --details
23Report

Merge CI results

Combine shard JSON into one portable HTML, JSON, and JUnit bundle and reject partial aggregation.

testpilot merge shard-a/run.json shard-b/run.json --out aggregate-report --expect-tests 20
24Help

Open terminal help

Show the general command list or focused usage for one command.

testpilot help [command]
25Help

Show the installed version

Print the active TestPilot runtime version.

testpilot version
RUNTIME ENVIRONMENT VARIABLES
TEST_PILOT_AI_API_KEY

OpenAI project key owned by the consumer suite

TESTPILOT_MODEL

Optional computer-capable model override

TESTPILOT_ENV

Default selected environment

TESTPILOT_EXECUTION_MODE

Default auto, serial, or parallel mode

TESTPILOT_OUTPUT_DIRECTORY

Alternate report root, useful per CI shard

TESTPILOT_LOG_LEVEL=debug

Short diagnostic details for unexpected failures

CI=true

Conservative worker defaults and noninteractive output

CIRCLE_NODE_INDEX / TOTAL

Automatic deterministic CircleCI shard selection

EXIT CODES
0Success
1Failed test or readiness
2Usage, config, or parser error
3License validation error
130Cancelled with Ctrl+C
09 / RECOVERY

When the runway is not clear.

Start with the symptom. Each answer points to the smallest safe check or command.

01testpilot: command not found+

Install the launcher globally: npm install --global @macevoorhees/testpilot. A local npm install does not normally add a bare command to your shell path.

02The browser is not ready+

Run testpilot doctor first. A normal init or run checks Chrome automatically; testpilot install-browser explicitly installs the pinned Chromium build when recovery is needed.

03The project or environment cannot be found+

Run inside the suite, or add --project path/to/suite. Use testpilot environments to see the exact names accepted by --env.

04The OpenAI key is missing+

Add the suite's key to its own ignored .env.local as TEST_PILOT_AI_API_KEY. TestPilot never borrows a key from another project.

05A step seems stuck+

The default hard deadline is 120 seconds for each authored step, not the whole test. Adjust execution.stepTimeoutSeconds from 1–3600 only when the workflow genuinely needs more time.

06A failed test did not retry+

That is intentional. TestPilot retries transient API requests, not a failed step or entire test. Read the HTML report and screenshot, fix the product or test intent, then run it again deliberately.

07CircleCI containers cannot activate+

Give every parallel job the same pre-provisioned TESTPILOT_ACTIVATION_TOKEN and matching stable TESTPILOT_INSTALLATION_ID. Do not rotate one raw license key independently in each job.

Still planning the test?

Describe the workflow. We will help map the flight path.

Talk to us