CLI Commands Reference

Complete reference for Meticulous CLI commands, flags, and usage patterns.


Installation

Install the CLI globally or use npx:

# Using npx (recommended)
npx @alwaysmeticulous/cli [command]

# Or install globally
npm install -g @alwaysmeticulous/cli
meticulous [command]

Commands Overview

CommandPurposeUse Case
ci run-with-tunnelRun tests in cloud via tunnelCI testing with local app
ci upload-assetsUpload and test static assetsCI testing for static sites
ci upload-asset-chunkUpload one named, versioned asset chunkMulti-bundle deployments
ci run-with-uploaded-asset-chunksTrigger a test run against uploaded chunksMulti-bundle deployments
ci upload-containerUpload Docker container and testCI testing with containers
ci run-localRun all replay test cases locallyLocal test execution
ci prepareEnsure base run existsCI setup
ci start-tunnelStart secure tunnelManual testing/debugging
simulate (alias: replay)Replay session locallyLocal debugging
record sessionRecord a user sessionSession recording
record loginRecord a login flowLogin flow recording
auth loginForce a fresh browser login and select a projectAuthentication
auth whoamiShow current userAuthentication check
auth logoutClear stored tokensAuthentication
auth set-projectSelect the project to use with OAuthAuthentication
auth unset-projectClear the selected projectAuthentication
auth list-projectsList the projects you can accessAuthentication
project showShow linked projectProject info
project upload-sourceUpload a source-code archive for a given commitSource coverage / CI
download sessionDownload a recorded sessionDebugging
download replayDownload a replayDebugging
download test-runDownload a test runDebugging
local relevant-sessionsFind sessions covering the current branch's code changesLocal development
debug replaySet up a debug workspace for a single replayInvestigating a replay
debug replay-diffSet up a debug workspace for a specific replay diffInvestigating a diff
debug cleanClean up debug workspacesDebug workspace maintenance
agent upload-buildUpload a build (static assets or container) and capture a deployment IDAgent/programmatic use
agent trigger-test-runTrigger a test run against an uploaded buildAgent/programmatic use
agent test-run-diffsList replay diffs for a test run with summaryAgent/programmatic use
agent dom-diffGet the DOM diff for a replay-diff screenshotAgent/programmatic use
agent image-urlsGet screenshot image URLs for a replay-diff screenshotAgent/programmatic use
agent image-filesDownload screenshot images to ~/.meticulous/agent-imagesAgent/programmatic use
agent timeline-diffGet the timeline diff for a replay diffAgent/programmatic use
agent test-run-for-commitLook up the latest test run for a commit (defaults to git HEAD)Agent/programmatic use
agent js-coverageGet JS coverage for a replay or a whole test runAgent/programmatic use
agent js-coverage-diffGet the JS coverage diff (base vs head) for a replay diffAgent/programmatic use
schemaPrint the CLI command schema as JSONAgent/programmatic use

For a closer look at the agent and auth commands — including their flags and how they compose into agent workflows — see CLI commands for agents.


ci run-with-tunnel

Run Meticulous tests in the cloud against a locally-running application.

Synopsis

npx @alwaysmeticulous/cli ci run-with-tunnel \
  --apiToken="<token>" \
  --appUrl="<url>" \
  [options]

Required Flags

--apiToken

Type: String Description: Your Meticulous API token How to get: From Meticulous dashboard project settings

Example:

--apiToken="met_live_abc123..."

Note: Can also be set via METICULOUS_API_TOKEN environment variable.


--appUrl

Type: String Description: URL where your app is running Format: Full URL including protocol and port

Examples:

--appUrl="http://localhost:3000"
--appUrl="http://localhost:8080"
--appUrl="https://localhost:3000"

Optional Flags

--commitSha

Type: String Description: Commit SHA being tested Default: Auto-detected from git

Example:

--commitSha="$GITHUB_SHA"
--commitSha="abc123def456..."

--companionAssetsFolder

Type: String (path) Description: Path to local folder with static assets to upload Default: None Requires: Must also provide --companionAssetsRegex

Example:

--companionAssetsFolder="companion-assets"

--companionAssetsRegex

Type: String (regex) Description: Regex pattern for requests to serve from companion assets Default: None Requires: Must also provide --companionAssetsFolder

Example:

--companionAssetsRegex="^/_next/static/"

--proxyAllUrls

Type: Boolean Description: Proxy all URLs through tunnel (not just app URL) Default: false

Example:

--proxyAllUrls

Use case: Multi-server applications (frontend + API on different ports)


--rewriteHostnameToAppUrl

Type: Boolean Description: Rewrite request hostname to match app URL Default: false

Example:

--rewriteHostnameToAppUrl

Use case: When HTML contains absolute URLs


--secureTunnelHost

Type: String Description: Custom tunnel server host Default: Meticulous production tunnel Note: For Meticulous team use only


--hadPreparedForTests

Type: Boolean Description: Indicate that meticulous ci prepare was already run Default: false


Complete Example

# Basic usage
npx @alwaysmeticulous/cli ci run-with-tunnel \
  --apiToken="$METICULOUS_API_TOKEN" \
  --appUrl="http://localhost:3000"

# With companion assets (Next.js)
npx @alwaysmeticulous/cli ci run-with-tunnel \
  --apiToken="$METICULOUS_API_TOKEN" \
  --appUrl="http://localhost:3000" \
  --companionAssetsFolder="companion-assets" \
  --companionAssetsRegex="^/_next/static/"

# Multi-server app
npx @alwaysmeticulous/cli ci run-with-tunnel \
  --apiToken="$METICULOUS_API_TOKEN" \
  --appUrl="http://localhost:3000" \
  --proxyAllUrls

Exit Codes

CodeMeaning
0Success - all tests passed or diffs approved
1Failure - tests failed or unapproved diffs
2Error - configuration or connection error

ci upload-assets

Upload static assets and run tests in the cloud.

Synopsis

npx @alwaysmeticulous/cli ci upload-assets \
  --apiToken="<token>" \
  --appDirectory="<path>" \
  [options]

Required Flags

--apiToken

Type: String Description: Your Meticulous API token


--appDirectory

Type: String (path) Description: Path to directory containing built static assets Common values: dist, build, out

Examples:

--appDirectory="dist"        # Vite
--appDirectory="build"       # Create React App
--appDirectory="out"         # Next.js static export

Optional Flags

--commitSha

Type: String Description: Commit SHA being tested Default: Auto-detected from git


--rewrites

Type: String (JSON) Description: URL rewrite rules in Vercel format Use case: SPA routing, redirects

Example:

--rewrites='[{"source":"/(.*)", "destination":"/index.html"}]'

Common patterns:

SPA routing:

[{"source": "/(.*)", "destination": "/index.html"}]

API proxy:

[{"source": "/api/(.*)", "destination": "https://api.example.com/$1"}]

--waitForBase

Type: Boolean Description: Wait for base test run Default: false


--waitForTestRunToComplete

Type: Boolean Description: After the upload succeeds and Meticulous has started a test run, keep polling until that run reaches a terminal status, then exit non-zero if the run failed.

Default: false (omit the flag)

Standard CI setups should leave this flag off. For GitHub, GitLab, Buildkite, CircleCI, and similar pipelines, the usual pattern is: build, run ci upload-assets (or ci upload-container) to upload and trigger a run, then let the job exit. Meticulous reports progress and outcomes on the pull request or through your VCS integration. Holding the whole CI job open until every replay finishes makes pipelines slower, rarely adds value, and tooling (including some AI code reviewers) often suggests this flag because the name sounds helpful.

Why avoid it by default: the run can still have background work in some configurations (for example lazy session execution), so a naive "wait until complete" loop may exit too early or fail with errors that are hard to interpret if you were only trying to "wait for Meticulous."

When it may be appropriate: automation that deliberately must block until the run is fully finished (for example internal regression checks where the process relies on the CLI exit code). If you are onboarding a new project or wiring PR checks, you almost never need this flag.


Complete Example

# Basic usage
npx @alwaysmeticulous/cli ci upload-assets \
  --apiToken="$METICULOUS_API_TOKEN" \
  --appDirectory="dist"

# With SPA routing
npx @alwaysmeticulous/cli ci upload-assets \
  --apiToken="$METICULOUS_API_TOKEN" \
  --appDirectory="dist" \
  --rewrites='[{"source":"/(.*)", "destination":"/index.html"}]'

# With commit SHA
npx @alwaysmeticulous/cli ci upload-assets \
  --apiToken="$METICULOUS_API_TOKEN" \
  --appDirectory="build" \
  --commitSha="$CI_COMMIT_SHA"

Exit Codes

CodeMeaning
0Success
1Failure
2Error

ci upload-asset-chunk

Upload a named, versioned chunk of static assets to Meticulous for incremental deployments.

Synopsis

npx @alwaysmeticulous/cli ci upload-asset-chunk \
  --apiToken="<token>" \
  --chunkName="<name>" \
  --chunkVersionId="<version>" \
  --chunkAssetsDirectory="<path>" \
  [options]

Required Flags

--apiToken

Type: String Description: Your Meticulous API token

Note: Can also be set via METICULOUS_API_TOKEN environment variable.


--chunkName

Type: String Description: Logical name of the asset chunk (e.g. app, vendor).

Example:

--chunkName="app"

--chunkVersionId

Type: String Description: Version identifier for this chunk (e.g. content hash or build id). Chunks are deduped by (chunkName, chunkVersionId).

Example:

--chunkVersionId="$CI_COMMIT_SHA"

--chunkAssetsDirectory

Type: String (path) Description: Directory whose contents should be packaged into this chunk.

Example:

--chunkAssetsDirectory="dist"

Optional Flags

--chunkAssetsDirectoryPrefix

Type: String Description: Path prefix prepended to every entry in the chunk (e.g. static/assets). Files in chunkAssetsDirectory will be served under this prefix at replay time.

Example:

--chunkAssetsDirectoryPrefix="static/assets"

--commitSha

Type: String Description: Commit SHA being tested Default: Auto-detected from git


--force

Type: Boolean Description: Re-upload even if a chunk with the same --chunkName and --chunkVersionId is already marked as uploaded on the server. Use only for recovery (e.g., a corrupted S3 object). The server will overwrite the existing chunk; downstream test runs that already referenced the old bytes will resolve to the new ones. Default: false

Example:

--force

Complete Example

npx @alwaysmeticulous/cli ci upload-asset-chunk \
  --apiToken="$METICULOUS_API_TOKEN" \
  --chunkName="app" \
  --chunkVersionId="$CI_COMMIT_SHA" \
  --chunkAssetsDirectory="dist"

Exit Codes

CodeMeaning
0Success
1Failure
2Error

ci run-with-uploaded-asset-chunks

Trigger a test run against already-uploaded asset chunks. Pair with ci upload-asset-chunk.

Synopsis

npx @alwaysmeticulous/cli ci run-with-uploaded-asset-chunks \
  --apiToken="<token>" \
  --commitSha="<sha>" \
  --assetReferencesManifest="<path>" \
  [options]

Required Flags

--apiToken

Type: String Description: Your Meticulous API token


--assetReferencesManifest

Type: String (path) Description: Path to a JSON file containing a list of { name, versionId } references to previously uploaded asset chunks (see ci upload-asset-chunk). Chunked analog of --appDirectory / --appZip on ci upload-assets.

File format:

[
  { "name": "app", "versionId": "ad8a8da9aaaweaad9" },
  { "name": "plugin-1", "versionId": "dd8ffdaa9dfedebb3" }
]

Example:

--assetReferencesManifest="./manifest.json"

Optional Flags

--commitSha

Type: String Description: Commit SHA being tested Default: Auto-detected from git


--baseSha

Type: String Description: The base commit SHA to compare against. Intended for custom test run triggers. Cannot be combined with --repoDirectory.


--gitDiffOutput

Type: String Description: Raw git diff output between the base and head commits. Requires --baseSha. Cannot be combined with --repoDirectory.


--repoDirectory

Type: String (path) Description: The path to a git repository. Intended for custom test run triggers. Automatically infers --commitSha, --baseSha, and --gitDiffOutput from the repo. Cannot be combined with --commitSha, --baseSha, or --gitDiffOutput.


--rewrites

Type: String (JSON) Description: URL rewrite rules in Vercel serve-handler format. Default: '[]' (falls back to { source: "**", destination: "/index.html" })

Example:

--rewrites='[{"source":"/(.*)", "destination":"/index.html"}]'

--sessionFilter

Type: String (path) Description: Path to a JSON file restricting which sessions the test run replays. A session is replayed if its start URL matches at least one of the regexes (RE2 syntax). If omitted, all selected sessions are replayed. See Filter Sessions by Start URL.

File format:

{
  "session-start-url-matches-any-regex": ["/checkout/", "/settings/"]
}

Example:

--sessionFilter="./session-filter.json"

--waitForBase

Type: Boolean Description: If true, wait for a base test run to be created before triggering a test run. Default: true


--waitForTestRunToComplete

Type: Boolean Description: Block until the triggered test run finishes. Only for runs tied to a local branch: requires --repoDirectory, or both --baseSha and --gitDiffOutput. Implies --waitForBase. Default: false


--dryRun

Type: Boolean Description: Print what would be triggered without making the API call. Default: false


Complete Example

# manifest.json
# [
#   { "name": "app", "versionId": "ad8a8da9aaaweaad9" },
#   { "name": "plugin-1", "versionId": "dd8ffdaa9dfedebb3" }
# ]

npx @alwaysmeticulous/cli ci run-with-uploaded-asset-chunks \
  --apiToken="$METICULOUS_API_TOKEN" \
  --commitSha="$CI_COMMIT_SHA" \
  --assetReferencesManifest="./manifest.json"

Exit Codes

CodeMeaning
0Success
1Failure
2Error

simulate

Replay a session locally for debugging.

Synopsis

npx @alwaysmeticulous/cli simulate \
  --sessionId="<id>" \
  --appUrl="<url>" \
  [options]

Required Flags

--sessionId

Type: String Description: ID of session to replay How to get: From Meticulous dashboard or test run

Example:

--sessionId="ses_abc123..."

--appUrl

Type: String Description: URL where your app is running locally

Example:

--appUrl="http://localhost:3000"

Optional Flags

--apiToken

Type: String Description: Your Meticulous API token Note: Required if session is private


--headless

Type: Boolean Description: Run browser in headless mode Default: false

Example:

--headless

--devtools

Type: Boolean Description: Open browser DevTools automatically Default: false

Example:

--devtools

Complete Example

# Basic replay
npx @alwaysmeticulous/cli simulate \
  --sessionId="ses_abc123..." \
  --appUrl="http://localhost:3000"

# With DevTools for debugging
npx @alwaysmeticulous/cli simulate \
  --sessionId="ses_abc123..." \
  --appUrl="http://localhost:3000" \
  --devtools

# Headless mode for CI
npx @alwaysmeticulous/cli simulate \
  --sessionId="ses_abc123..." \
  --appUrl="http://localhost:3000" \
  --headless

Exit Codes

CodeMeaning
0Replay completed successfully
1Replay failed

ci start-tunnel

Start a secure tunnel for manual testing and debugging.

Synopsis

npx @alwaysmeticulous/cli ci start-tunnel \
  --port=<port> \
  [options]

Required Flags

--port / -p

Type: Number Description: Port your local server is running on

Example:

--port=3000
-p 3000

Optional Flags

--apiToken

Type: String Description: Your Meticulous API token Note: Required for authentication


--localHost / -l

Type: String Description: Host to tunnel to Default: localhost

Example:

--localHost=127.0.0.1

--localHttps

Type: Boolean Description: Connect to local HTTPS server Default: false

Example:

--localHttps

--localCert

Type: String (path) Description: Path to SSL certificate file

Example:

--localCert="./certs/server.crt"

--localKey

Type: String (path) Description: Path to SSL key file

Example:

--localKey="./certs/server.key"

--localCa

Type: String (path) Description: Path to CA file for self-signed certificates

Example:

--localCa="./certs/ca.crt"

--allowInvalidCert

Type: Boolean Description: Ignore SSL certificate errors Default: false

Example:

--allowInvalidCert

--proxyAllUrls

Type: Boolean Description: Proxy all URLs through tunnel Default: false


--rewriteHostnameToAppUrl

Type: Boolean Description: Rewrite request hostnames Default: false


--enableDnsCache

Type: Boolean Description: Enable DNS caching Default: false


--printRequests

Type: Boolean Description: Log all requests through tunnel Default: false

Example:

--printRequests

--http2Connections

Type: Number Description: Number of HTTP/2 connections for multiplexing Default: Number of CPU cores

Example:

--http2Connections=8

Complete Example

# Basic tunnel
npx @alwaysmeticulous/cli ci start-tunnel \
  --port=3000

# With request logging
npx @alwaysmeticulous/cli ci start-tunnel \
  --port=3000 \
  --printRequests

# HTTPS tunnel with self-signed cert
npx @alwaysmeticulous/cli ci start-tunnel \
  --port=3000 \
  --localHttps \
  --allowInvalidCert

# Multi-server setup
npx @alwaysmeticulous/cli ci start-tunnel \
  --port=3000 \
  --proxyAllUrls

Output

When tunnel starts successfully:

Your url is: https://abc123.meticulous.ai
user: meticulous, password: ******

Use these credentials to access your app through the tunnel.


ci prepare

Ensure a base test run exists before running tests.

Synopsis

npx @alwaysmeticulous/cli ci prepare \
  --apiToken="<token>" \
  [options]

Required Flags

--apiToken

Type: String Description: Your Meticulous API token


Required Flags

--triggerScript

Type: String Description: Path to script that triggers a test run on a specific commit


Optional Flags

--headCommit

Type: String Description: Commit SHA to check/prepare Default: Auto-detected


Complete Example

npx @alwaysmeticulous/cli ci prepare \
  --apiToken="$METICULOUS_API_TOKEN" \
  --triggerScript="./scripts/trigger-test-run.sh"

Common Patterns

Environment Variables

Set API token via environment variable:

export METICULOUS_API_TOKEN="met_live_abc123..."

# Now can omit --apiToken flag
npx @alwaysmeticulous/cli ci run-with-tunnel \
  --appUrl="http://localhost:3000"

CI Integration

GitHub Actions

- name: Run Meticulous tests
  run: |
    npx @alwaysmeticulous/cli ci run-with-tunnel \
      --apiToken="${{ secrets.METICULOUS_API_TOKEN }}" \
      --appUrl="http://localhost:3000"

GitLab CI

script:
  - >
    npx @alwaysmeticulous/cli ci upload-assets
    --apiToken="$METICULOUS_API_TOKEN"
    --appDirectory="dist"
    --commitSha="$CI_COMMIT_SHA"

Debug Mode

Enable verbose logging:

DEBUG=meticulous:* npx @alwaysmeticulous/cli ci run-with-tunnel \
  --apiToken="$METICULOUS_API_TOKEN" \
  --appUrl="http://localhost:3000"

Scripting

Use in shell scripts:

#!/bin/bash
set -e

# Start app
npm start &
APP_PID=$!

# Wait for app
npx wait-on http://localhost:3000

# Run tests
npx @alwaysmeticulous/cli ci run-with-tunnel \
  --apiToken="$METICULOUS_API_TOKEN" \
  --appUrl="http://localhost:3000"

# Cleanup
kill $APP_PID

Troubleshooting

"API token required"

Cause: No API token provided

Solution: Pass --apiToken or set METICULOUS_API_TOKEN env var


"Failed to connect"

Cause: App not running or wrong URL

Solutions:

  1. Verify app is running: curl http://localhost:3000
  2. Check port in --appUrl matches actual port
  3. Increase wait time before running command

"No sessions found"

Cause: No recorded sessions for project

Solution: Record sessions first (add recorder snippet to app)


"Tunnel connection failed"

Cause: Network/firewall issue

Solutions:

  1. Check outbound HTTPS (443) is allowed
  2. Try --printRequests to debug
  3. Contact support if persists

See Also