Reference

On this page

Subcommands #

CommandDoes
atago runrun specs and report results
atago recordrun a command once and write a spec from what it observed (--pty for interactive sessions)
atago initscaffold a spec (--template for browser, cli, db, grpc, http, mock, services, ssh; cli is the default)
atago snapshot updaterecord or refresh golden files
atago explaindescribe what a spec does without running it
atago docgenerate Markdown from specs, with fixtures and golden files inlined
atago manifestemit a stable JSON summary of specs for tooling
atago listshow scenarios, tags, and artifacts
atago completionprint a shell completion script

explain, doc, manifest, and list all load and validate the spec first — exit code 2 on a schema error — so any of them doubles as a lint step in CI.

Selecting scenarios #

Selection flags compose with any spec: --filter NAME (repeatable, and comma-separated for OR — --filter a,b or --filter a --filter b runs scenarios whose name contains a or b), --tag T and --skip-tag T (tags match exactly, not by substring — atago list shows the available tags), --parallel N, --fail-fast, and --rerun-failed. atago run --rerun-failed re-runs only the scenarios the previous run recorded as failed in .atago/last-failed.json, so the fix-and-recheck loop replays just the failures instead of the whole suite. While authoring, --verbose traces every command, capture, and assertion verdict — for passing scenarios too. Under --ci, a selection that matches no scenario fails the run (exit 3) rather than passing an empty suite.

Snapshot testing #

snapshot matchers compare output against committed golden files; ANSI colors, temp paths, UUIDs, timestamps, ports, and CRLF are normalized so snapshots stay stable across machines. Record or refresh them with:

atago snapshot update spec.atago.yaml

For volatile patterns the built-ins do not cover — auto-increment IDs, request identifiers, epoch times — declare spec-wide scrub: rules that rewrite each regex match to a placeholder before the compare (applied after secrets: masking):

scrub:
  - {pattern: 'id=\d+', placeholder: 'id=<ID>'}

See the scrub example.

Spec file keys #

Every key a spec file accepts, generated from the committed JSON Schema — the same document that powers editor completion, so this reference cannot drift from what the loader accepts. Indentation shows nesting; a type that links (like step) is documented in its own section rather than repeated inline.

All keys belong to spec format version 1 — the only format version so far; version: "1" is the first line of every spec. Since is the atago release that introduced the key (unreleased = merged to main, not yet in a tagged release).

Top level #

The keys of a spec file document.

KeyTypeDescriptionSince
defaultsdefaultsSpec-wide default fragments merged into every matching element at load time — authoring sugar to cut repetition. An explicitly authored value always wins; maps merge per key; a defaulted boolean cannot be turned off per element.v0.1.0
permissionsobjectThe spec’s security policy.v0.1.0
networkobjectNetwork egress policy for the spec.v0.1.0
allowarray of stringHosts that scenarios may contact; egress to any other host is a policy violation (exit 6).v0.1.0
runnersmap of runnerNamed runner configurations. cmd is the implicit default for run steps; http supplies a base_url for http steps; db a dsn for query steps; ssh, grpc, and browser configure their step types.v0.1.0
scenariosarray of scenarioRequired. The named behaviors under test. Each scenario runs in its own isolated temporary workdir.v0.1.0
scrubarray of objectsDeclarative output-normalization rules (#137): each replaces every regex match in captured output with a literal placeholder before a snapshot is compared or written. Where secrets masks known values, scrub normalizes volatile patterns the built-in normalizers do not cover (auto-increment IDs, request identifiers, custom timestamps). Rules apply in order, after secret masking and before the built-in ANSI/UUID/timestamp/port/path normalization.v0.5.0
patternstringRequired. A Go (RE2) regular expression; every match is replaced. Required.v0.5.0
placeholderstringLiteral replacement text (no $1 expansion), e.g. “<ID>”. Defaults to empty, which deletes matches.v0.5.0
secretsarray of stringEnvironment variable names whose VALUES are masked as *** in output, reports, and snapshots.v0.1.0
suiteobjectRequired. Groups the file’s scenarios under a name, with optional suite-wide env, default step timeout, and one-time setup/teardown steps.v0.1.0
envmap of stringEnvironment exported to every scenario, setup, and teardown step (a scenario’s own env wins per key).v0.2.0
namestringRequired. The suite name shown in reports and generated docs.v0.1.0
setuparray of stepSteps run ONCE before any scenario, in order, inside the ${suitedir} scratch dir. Allowed kinds: fixture, run, store, assert, and service (a suite-wide background process started at that point in the sequence). A failing setup step errors every scenario.v0.2.0
teardownarray of stepSteps that always run after the last scenario, while suite services are still up (services stop last, LIFO). Failures are reported but never change the suite verdict.v0.2.0
timeoutstringSuite-level default step timeout (#17): every run/http/query/grpc step without a more specific timeout (step > runner > defaults.run > suite) is bounded by this Go duration. “0” disables. When no level configures one, a built-in 60s default applies.v0.3.0
version1 | 1Required. Spec format version. Write “1” (quoted); a bare 1 is accepted for convenience — the loader coerces it to “1”.v0.1.0

scenarios[*] #

KeyTypeDescriptionSince
envmap of stringEnvironment variables for every step in the scenario (a step’s own env wins per key).v0.1.0
matrixarray of objectMakes the scenario a template: one concrete instance per row, with each row’s key/value pairs seeded as ${name} variables.v0.1.0
mock_serversarray of mockServerDeclarative stub HTTP servers (#24): canned routes on an ephemeral loopback port, every request recorded for the mock: assertion target; ${<name>.url} / ${<name>.port} are seeded before steps run.v0.3.0
namestringRequired. The scenario name shown in reports; with matrix:, ${var} placeholders make each instance’s name unique.v0.1.0
onlyconditionRuns the scenario only when the condition holds.v0.1.0
servicesarray of serviceBackground processes started before the steps and terminated (with their process group) when the scenario ends — peers the CLI under test talks to.v0.1.0
skipconditionSkips the scenario when the condition holds (os match, env var set, or probe command succeeding).v0.1.0
stepsarray of stepRequired. The ordered actions: fixtures, commands, requests, assertions, captures.v0.1.0
tagsarray of stringLabels for run-time selection with --tag / --skip-tag.v0.1.0
teardownarray of stepSteps that always run after steps — pass, fail, error, or interrupt — sharing the scenario’s variable store. For external side effects the isolated workdir cannot undo. A teardown failure is reported but does not change the scenario’s verdict.v0.1.0

steps[*] #

KeyTypeDescriptionSince
assertassertChecks externally observable behavior of the preceding step. Exactly one target family per assert block.v0.1.0
cdpcdpDrives a headless Chrome through a browser runner with a declarative action list.v0.1.0
fixturefixtureMaterializes an input file in the scenario workdir before the command runs.v0.1.0
grpcgrpcCalls a unary gRPC method through a grpc runner via server reflection.v0.1.0
httphttpIssues an HTTP request through an http runner — as a peer of the CLI under test.v0.1.0
mock_servermockServerStarts a suite-wide stub HTTP server at this point in the sequence (#24). Valid only inside suite.setup.v0.3.0
ptyptyRuns a command inside a real pseudo-terminal and drives it with a declarative expect/send session — for prompts, REPLs, and TUIs. Works on Linux, macOS, and Windows (ConPTY).v0.2.0
queryqueryRuns a SQL statement through a db runner; SELECT rows feed the rows: assert.v0.1.0
runrunExecutes a command and captures its exit code, stdout, and stderr.v0.1.0
serviceserviceStarts a suite-wide background process at this point in the sequence. Valid only inside suite.setup; the loader rejects it anywhere else.v0.2.0
signalsignalSends a named POSIX signal to a managed service — the race-free alternative to kill hacks for graceful-shutdown tests. POSIX-only.v0.3.0
storestoreCaptures a value into the variable store; later steps reference it as ${name}.v0.1.0

fixture #

KeyTypeDescriptionSince
base64stringInline binary content, base64-encoded — carries exact bytes YAML text cannot.v0.1.0
contentstringInline text content for the file. Exactly one source (content/base64/from/symlink) is set.v0.1.0
filestringRequired. The workdir-relative path to create.v0.1.0
fromstringCopies an existing file (e.g. committed testdata), resolved relative to the spec file’s directory.v0.1.0
modestringOctal file mode (e.g. “0755”) applied after writing.v0.1.0
mtimestringRFC3339 modification time applied after writing — pins timestamps for freshness/change-detection tests.v0.1.0
symlinkstringMakes file a symbolic link to this target instead of a regular file. The target is written verbatim.v0.1.0

run #

KeyTypeDescriptionSince
clear_envbooleanStart the child from an empty environment instead of inheriting the host environment (#16). On Windows a small system-critical set (SystemRoot, SystemDrive, TEMP, TMP, PATHEXT) is always retained.v0.3.0
commandstringRequired. The program to run. Tokenized and exec’d directly unless shell: true.v0.1.0
cwdstringWorking directory relative to the scenario workdir (default: the workdir itself).v0.1.0
envmap of stringEnvironment variables for the child process, layered over the scenario env; values get ${name} expansion.v0.1.0
pass_envarray of stringHost variables copied into the cleared environment (#16). Requires clear_env: true; unset host variables are skipped.v0.3.0
retryretryRe-runs the command until the until assertion passes — declarative polling for async behavior. The last attempt’s result is what later steps observe.v0.1.0
runnerstringNames a declared runner to execute through (e.g. an ssh runner runs the command remotely). Default: local execution.v0.1.0
sandbox_homebooleanPoint the child’s home and per-OS config/cache/data/state dirs at ${workdir}/.atago-home so a CLI touching ~/.config, ~/.cache, or %APPDATA% runs hermetically (#71). Precedence: step env > sandbox > pass_env > host; composes with clear_env.v0.3.0
shellbooleanRuns the command through the shell (/bin/sh on POSIX, cmd.exe on Windows) — for pipes, redirects, and builtins.v0.1.0
stderr_tostringWrite the command’s captured stderr to this workdir-relative file (create/truncate), without needing shell redirection.v0.1.0
stdinstring | objectStandard input for the command (#18): a plain string (inline text), {file: path} (workdir-relative, path-confined), or {base64: data} for binary bytes.v0.1.0
filestringRequired. Feeds the command’s stdin from a workdir-relative file.v0.3.0
base64stringRequired. Feeds the command’s stdin with exact binary bytes, base64-encoded.v0.3.0
stdout_tostringWrite the command’s captured stdout to this workdir-relative file (create/truncate), without needing shell redirection.v0.1.0
timeoutstringBounds this command as a Go duration. Precedence: step > runner > defaults.run > suite > built-in 60s.v0.1.0

pty #

Runs one command inside a real pseudo-terminal and drives it with a declarative expect/send session (#8) — for CLIs that branch on TTY-ness or present interactive prompts. POSIX-only at runtime; Windows reports a clear execution error.

KeyTypeDescriptionSince
clear_envbooleanStart the child from an empty environment instead of inheriting the host environment (#16). On Windows a small system-critical set (SystemRoot, SystemDrive, TEMP, TMP, PATHEXT) is always retained.v0.3.0
colsintegerTerminal width in columns (default 80).v0.2.0
commandstringRequired. The program to run inside a real pseudo-terminal (a ConPTY on Windows). The captured transcript becomes the step’s stdout.v0.2.0
cwdstringWorking directory relative to the scenario workdir.v0.2.0
envmap of stringEnvironment variables for the pty child. The child gets TERM=xterm-256color by default; override here if needed.v0.2.0
pass_envarray of stringHost variables copied into the cleared environment (#16). Requires clear_env: true; unset host variables are skipped.v0.3.0
rowsintegerTerminal height in rows (default 24). Also sizes the screen: assertion’s emulator.v0.2.0
sandbox_homebooleanPoint the pty child’s home and per-OS config/cache/data/state dirs at ${workdir}/.atago-home so a CLI touching ~/.config, ~/.cache, or %APPDATA% runs hermetically (#71).v0.3.0
sessionarray of objectsOrdered expect/send script. Each entry waits for the transcript to match (expect) or types into the terminal (send). Deliberately no branching.v0.2.0
expectstringWaits until the transcript (scanned after the previous match) matches this Go regular expression; a never-matching expect fails when the session timeout elapses.v0.2.0
sendstring | objectWrites to the terminal: a string verbatim ("" sends EOF/^D; ${name} expansion applies) or {key: <name>} for a named key — enter, tab, esc, arrows, f1-f12, ctrl-a..ctrl-z.v0.2.0
keystringRequired. Named key: enter, tab, esc, space, backspace, delete, arrows, home/end, pageup/pagedown, f1-f12, ctrl-a..ctrl-z.v0.3.0
shellbooleanRuns the command through the shell, like run.shell.v0.2.0
timeoutstringGo duration bounding the WHOLE session (default 30s).v0.2.0

http #

KeyTypeDescriptionSince
bodystringRaw string payload sent verbatim (default Content-Type text/plain). The payload fields (json/body/body_file/form+files) are mutually exclusive.v0.1.0
body_filestringWorkdir-relative file streamed as the raw request body (binary-safe) — for upload endpoints that take file content directly.v0.1.0
body_tostringWrite the response body to this workdir-relative file, so file/image/pdf assertions can inspect a download (the http analog of run’s stdout_to).v0.1.0
filesarray of objectsFiles attached as multipart/form-data parts (the browser-style upload most web apps expect).v0.1.0
content_typestringOverrides the part’s Content-Type (default: detected from content, falling back to application/octet-stream).v0.1.0
fieldstringRequired. The multipart form field name the server reads the file from.v0.1.0
pathstringRequired. The workdir-relative file whose content becomes the part body.v0.1.0
follow_redirectsbooleanFollow 3xx responses (default true). Set false to assert on the redirect itself: its status code and Location header.v0.1.0
formmap of stringForm fields: application/x-www-form-urlencoded alone, multipart/form-data when files is also set.v0.1.0
headermap of stringRequest headers.v0.1.0
jsonanyv0.1.0
methodstringRequired. The HTTP method (GET, POST, …).v0.1.0
pathstringRequest path appended to the runner’s base_url; ${name} expansion applies.v0.1.0
retryretryRe-issues the request until the until assertion passes — declarative polling for eventually-consistent endpoints.v0.1.0
runnerstringNames the http runner declaring the base_url. With exactly one http runner declared it may be omitted.v0.1.0

query #

KeyTypeDescriptionSince
runnerstringRequired. Names the db runner declaring the dsn.v0.1.0
sqlstringRequired. The SQL statement. SELECT rows are captured as JSON for rows: asserts and store from.rows; other statements record their affected-row count.v0.1.0

grpc #

KeyTypeDescriptionSince
headermap of stringRequest metadata headers.v0.1.0
jsonanyv0.1.0
methodstringRequired. The unary method to call as “package.Service/Method”; the schema is resolved via server reflection (no compiled stubs).v0.1.0
runnerstringRequired. Names the grpc runner declaring the target server.v0.1.0

cdp #

KeyTypeDescriptionSince
actionsarray of objectsRequired. Browser actions run in order against one session; the value captured by the last text/eval/attribute/title action feeds the value: assert and store from.value.v0.1.0
attributeobjectCaptures an element attribute value.v0.1.0
namestringRequired. The attribute name to capture.v0.1.0
selectorstringRequired. The element to read.v0.1.0
checkstringTicks the checkbox matched by the selector.v0.1.0
clickstringClicks the element matched by the selector.v0.1.0
downloadobjectClicks to trigger a download and captures the file using the server-suggested filename; the captured value is the final filename.v0.1.0
clickstringRequired. The element to click to start the download.v0.1.0
dirstringWorkdir-relative directory to save into (default: the workdir root).v0.1.0
evalstringEvaluates a JavaScript expression and captures the result as JSON.v0.1.0
navigatestringLoads a URL.v0.1.0
pressobjectPresses a single key on an element.v0.1.0
keystringRequired. The key to press (e.g. “Enter”, “Tab”, or a printable character).v0.1.0
selectorstringRequired. The element to receive the key press.v0.1.0
screenshotobjectWrites a PNG of the page (or one element) into the workdir for file/image assertions.v0.1.0
pathstringRequired. The workdir-relative PNG path to write.v0.1.0
selectorstringLimits the screenshot to this element (default: the whole page).v0.1.0
selectobjectChooses an <option> in a <select>.v0.1.0
selectorstringRequired. The <select> element.v0.1.0
valuestringRequired. The option value to choose.v0.1.0
send_keysobjectTypes text into an element.v0.1.0
selectorstringRequired. The element to type into.v0.1.0
valuestringRequired. The text to type.v0.1.0
textstringCaptures the text of the element matched by the selector.v0.1.0
titlebooleanCaptures the page title.v0.1.0
uncheckstringUnticks the checkbox matched by the selector.v0.1.0
uploadobjectSets a file on an <input type=file> — no scripted file dialogs.v0.1.0
filestringRequired. The workdir-relative file to attach; must exist.v0.1.0
selectorstringRequired. The <input type=file> element.v0.1.0
wait_hiddenstringWaits until the CSS selector is hidden or absent.v0.1.0
wait_visiblestringWaits until the CSS selector is visible.v0.1.0
runnerstringRequired. Names the browser runner to drive.v0.1.0

store #

KeyTypeDescriptionSince
fromobjectRequired. Where the value comes from — exactly one source.v0.1.0
bodystreamExtracts from the preceding http step’s response body via a json path or regex.v0.1.0
filefileReads a generated file: a json path selects a value, or text: true captures the whole content.v0.1.0
headerstringCaptures an HTTP response header value by name.v0.1.0
messagestreamExtracts from the preceding grpc step’s response message via a json path.v0.1.0
rowsstreamExtracts from the preceding query step’s result rows (a JSON array) via a json path.v0.1.0
stdoutstreamExtracts from the preceding step’s stdout via a json path or matches regex, or captures the whole stream with trim.v0.1.0
valuestreamExtracts from the last browser-captured value via a json path or regex.v0.1.0
namestringRequired. The variable name; later steps reference the captured value as ${name}.v0.1.0

signal #

Sends a named POSIX signal to a managed service’s process group (#23) - the race-free alternative to kill/killall for graceful-shutdown tests. POSIX-only at runtime; Windows reports a clear execution error.

KeyTypeDescriptionSince
servicestringRequired. A service declared in the scenario’s services: list or started by a suite.setup service: step.v0.3.0
signalstringRequired. TERM, INT, HUP, USR1, USR2, or KILL (optional SIG prefix accepted).v0.3.0
waitobjectBlock until the signaled process exits; a still-running process fails the step.v0.3.0
timeoutstringGo duration bounding the wait (default 5s).v0.3.0

service #

KeyTypeDescriptionSince
clear_envbooleanStart the child from an empty environment instead of inheriting the host environment (#16). On Windows a small system-critical set (SystemRoot, SystemDrive, TEMP, TMP, PATHEXT) is always retained.v0.3.0
commandstringRequired. The program to run. Tokenized and exec’d directly unless shell: true.v0.1.0
cwdstringWorking directory relative to the scenario workdir.v0.1.0
envmap of stringEnvironment variables, layered over the scenario env, with ${name} expansion.v0.1.0
max_log_bytesintegerMaximum bytes of combined stdout/stderr atago retains for this service. The oldest bytes are dropped first and the retained log starts with a truncation notice, so readiness excerpts and preserved log artifacts (which only ever need the tail) stay bounded. Omit for the 8 MiB default.v0.10.0
namestringRequired. Identifies the service in diagnostics and signal: steps; unique per scenario.v0.1.0
pass_envarray of stringHost variables copied into the cleared environment (#16). Requires clear_env: true; unset host variables are skipped.v0.3.0
readyobjectHow to wait until the service accepts work before steps run. When omitted, steps start as soon as the process is spawned.v0.1.0
delaystringSimply waits this Go duration — a last resort when no observable readiness signal exists.v0.1.0
filestringReady when this workdir-relative file exists and is non-empty — the canonical pattern for a server publishing its listen address.v0.1.0
logstringReady when the service’s combined stdout/stderr matches this regular expression.v0.1.0
portstringReady when this TCP address (host:port) accepts a connection.v0.1.0
storestringUsed with file: captures the ready file’s trimmed content into ${<name>} so steps can reference a dynamic address or port.v0.1.0
timeoutstringBounds the readiness wait as a Go duration (default “5s”).v0.1.0
shellbooleanRuns the command through the POSIX shell (pipes, redirects, ${}).v0.1.0

mock_server #

A declarative stub HTTP server (#24): routes match on exact method+path (query string excluded); an unmatched request answers 404 and is still recorded.

KeyTypeDescriptionSince
namestringRequired. Identifies the server: seeds ${<name>.url} / ${<name>.port} and is referenced by mock: asserts. Unique per scenario.v0.3.0
routesarray of mockRouteCanned responses, matched top-down on exact method+path (query string excluded; deliberately no patterns). An unmatched request answers 404 and is still recorded.v0.3.0

mock_server routes[*] #

One canned response. At most one of json/body/body_file supplies the payload; status defaults to 200.

KeyTypeDescriptionSince
bodystringInline text response body.v0.3.0
body_filestringSpec-relative response body file, confined to the spec directory.v0.3.0
delaystringGo duration to sleep before responding - for retry testing.v0.3.0
headermap of stringExtra response headers to set.v0.3.0
jsonanyInline response document, marshaled with Content-Type: application/json.v0.3.0
methodstringRequired. HTTP method to match (case-insensitive).v0.3.0
pathstringRequired. Exact request path to match (query string excluded).v0.3.0
statusintegerResponse status code (default 200).v0.3.0

assert #

An assert sets one or more target families; each is an independent check and all must hold (e.g. exit_code + stdout + file in one block).

KeyTypeDescriptionSince
bodystreamMatches the HTTP response body of the preceding http step with the stream matchers.v0.1.0
changeschangesAssertValid after a run/pty step: pins exactly which files that step created, modified, and deleted in the scenario workdir. Each set list is exhaustive in both directions.v0.3.0
dirdirBlack-box checks over a generated directory: existence, expected/forbidden children, entry counts, glob coverage, or a whole-tree snapshot manifest.v0.1.0
durationdurationAssertBounds how long the preceding measurable step (run/http/query/grpc/pty) took, with Go-duration lt/lte/gt/gte bounds.v0.3.0
exit_codeexitCodeAsserts the preceding command’s exit status: a bare integer, {not: N}, or a documented set {in: [0, 2]}.v0.1.0
filefileChecks a generated file: existence, content substrings, byte-exact equality, JSONPath checks, executability, or a snapshot.v0.1.0
grpc_statusintegerAsserts the numeric gRPC status code of the preceding grpc step (0 = OK).v0.1.0
headerheaderMatchMatches one HTTP response header of the preceding http step by name.v0.1.0
imageimageInspects a generated image’s decoded properties (format, dimensions, alpha) and optionally compares its pixels against a baseline. Every set field must hold.v0.1.0
messagestreamMatches the preceding grpc step’s response message (as JSON) with the stream matchers.v0.1.0
mockmockAssertAsserts what the CLI under test actually sent to a declared mock server: request count, and header/body matchers on the last matching recorded request.v0.3.0
pdfpdfChecks a generated PDF: page count, Info-dictionary metadata, and extracted text. Every set field must hold.v0.1.0
rowsstreamMatches the preceding query step’s result rows, captured as a JSON array, with the stream matchers (json path/length, contains, …).v0.1.0
screenstreamThe rendered terminal screen of the preceding pty step (#27): the transcript replayed through a vt10x emulator, asserted as plain text (line.n = screen row).v0.3.0
statusintegerAsserts the HTTP response status code of the preceding http step.v0.1.0
stderrstreamMatches the preceding step’s captured standard error with exactly one stream matcher.v0.1.0
stdoutstreamMatches the preceding step’s captured standard output with exactly one stream matcher.v0.1.0
valuestreamMatches the value captured by the last browser text/eval/attribute/title action with the stream matchers.v0.1.0

stream matchers (stdout / stderr / body / rows / message / value / screen) #

KeyTypeDescriptionSince
containsstringOrListRequires every listed substring (a scalar counts as a one-element list) to be present.v0.1.0
emptybooleanAsserts the stream is empty (true) or non-empty (false).v0.1.0
equalsstringRequires the stream to equal this string exactly (CRLF and one trailing newline are normalized).v0.1.0
jsonjsonChecksParses the stream as JSON and applies one JSONPath check, or a list of checks that must all hold.v0.1.0
lineinteger1-based line selector: applies the matcher to that single line instead of the whole stream. Not itself a matcher; does not compose with json/snapshot.v0.1.0
matchesstringRequires the stream to match this Go (RE2) regular expression.v0.1.0
not_containsstringOrListRequires every listed substring to be absent.v0.1.0
not_equalsstringRequires the stream NOT to equal this string.v0.1.0
not_matchesstringRequires the stream NOT to match this Go (RE2) regular expression.v0.1.0
snapshotstringCompares the stream against a committed golden file (spec-relative path). Volatile details (ANSI, temp paths, UUIDs, timestamps, ports, CRLF) are normalized; refresh with atago snapshot update.v0.1.0
trimbooleanStore-only (#158): capture the whole stream. trim: true strips surrounding whitespace; trim: false keeps bytes verbatim.v0.6.0
yamljsonChecksParses the stream as YAML and applies one JSONPath check, or a list of checks that must all hold.v0.1.0

exit_code #

KeyTypeDescriptionSince
notintegerRequired. Asserts the exit code is anything but this value.v0.1.0
inarray of integerRequired. The exit code must be one of these values (#19) — the contract shape of grep (0/1) or terraform plan -detailed-exitcode (0/2).v0.3.0

file #

KeyTypeDescriptionSince
containsstringOrListRequires every listed substring to be present in the file content.v0.1.0
equalsstringByte-exact content match against an inline literal (no CRLF/newline normalization).v0.6.0
equals_filestringByte-exact content match against another workdir-confined file (round-trip/idempotence; no CRLF/newline normalization).v0.6.0
executablebooleanAsserts whether the file has an executable bit set (POSIX).v0.1.0
existsbooleanAsserts the file exists (true) or is absent (false).v0.1.0
jsonjsonChecksParses the file as JSON and applies one JSONPath check, or a list of checks that must all hold.v0.1.0
not_containsstringOrListRequires every listed substring to be absent from the file content.v0.1.0
pathstringRequired. The file under test, resolved against the scenario workdir when relative (confined to it).v0.1.0
snapshotstringCompares the file content against a committed golden file, with the standard snapshot normalization.v0.1.0
textbooleanStore-only (#158): capture the whole file content verbatim instead of extracting a value via a json path.v0.6.0

dir #

KeyTypeDescriptionSince
containsarray of stringChild paths (relative to path) that must exist; nested paths are allowed and confined to the directory.v0.1.0
countintegerAsserts the exact number of direct entries (files only under recursive: true).v0.1.0
existsbooleanAsserts the path exists and is a directory (false asserts it is absent).v0.1.0
globstringRequires at least one entry to match this shell glob (basename match for patterns without /).v0.1.0
ignorearray of stringGlob patterns excluded from the recursive walk and the snapshot manifest (*.log, .git/**).v0.3.0
max_countintegerUpper bound on the number of entries.v0.1.0
min_countintegerLower bound on the number of entries.v0.1.0
not_containsarray of stringChild paths (relative to path) that must NOT exist.v0.1.0
pathstringRequired. The directory under test, resolved against the scenario workdir when relative.v0.1.0
recursivebooleanApply contains/not_contains/count/glob to the whole tree (#25): counts see files only; glob matches relative paths, or basenames for patterns without /.v0.3.0
snapshotstringGolden tree manifest (#25): sorted relative paths, one line per entry (dir/file sha256/link). Composes only with ignore; refresh with –update-snapshots.v0.3.0

changes #

Pins the exact workdir delta of the immediately preceding run/pty step (#70): which files it created, modified, and deleted. Each set field is EXHAUSTIVE in both directions (every observed path must match an entry, every entry must match a path), so modified: [] asserts “modified nothing”. An omitted field is unconstrained. Entries are workdir-relative doublestar globs, always /-separated: a single * stays within one path segment while ** crosses / at any depth (site/** covers the whole tree, dist/**/*.css composes with a suffix). A backslash escapes a literal metacharacter (\[, \?, \*) — a\[1\].txt matches the file a[1].txt; the escape is portable because entries are always /-separated.

KeyTypeDescriptionSince
createdchangesEntriesExhaustive list of paths the step created: every observed creation must match an entry and vice versa. [] asserts “created nothing”.v0.3.0
deletedchangesEntriesExhaustive list of paths the step deleted. [] asserts “deleted nothing”.v0.3.0
modifiedchangesEntriesExhaustive list of paths the step modified (content-based, not mtime). [] asserts “modified nothing”.v0.3.0

duration #

Bounds the wall-clock time of the immediately preceding run/http/query/grpc/pty step (#31). At least one bound; lt/lte and gt/gte are mutually exclusive. Values are Go duration strings (2s, 100ms).

KeyTypeDescriptionSince
gtstringExclusive lower bound as a Go duration.v0.3.0
gtestringInclusive lower bound as a Go duration.v0.3.0
ltstringExclusive upper bound as a Go duration (e.g. “2s”).v0.3.0
ltestringInclusive upper bound as a Go duration.v0.3.0

image #

KeyTypeDescriptionSince
alphabooleanAsserts whether the image actually carries transparency (any non-opaque pixel), scanning decoded pixels.v0.1.0
formatpng | jpeg | gif | webp | bmp | tiff | avif | svgAsserts the encoded format, detected from content: png, jpeg, gif, webp, bmp, tiff, avif, or svg.v0.1.0
heightintegerAsserts the exact pixel height.v0.1.0
max_diffnumberMaximum allowed normalized mean per-pixel difference (0..1) for similar_to. Defaults to 0 (exact); lossy formats need a small tolerance like 0.02.v0.1.0
max_heightintegerUpper bound on the pixel height.v0.1.0
max_widthintegerUpper bound on the pixel width.v0.1.0
min_heightintegerLower bound on the pixel height.v0.1.0
min_widthintegerLower bound on the pixel width.v0.1.0
pathstringRequired. The image file under test, resolved against the scenario workdir when relative.v0.1.0
similar_tostringBaseline image to compare decoded pixels against. A relative path resolves against the spec file’s directory; both images must share dimensions.v0.1.0
widthintegerAsserts the exact pixel width.v0.1.0

pdf #

KeyTypeDescriptionSince
max_pagesintegerUpper bound on the page count.v0.1.0
metadatamap of stringMaps an Info-dictionary field (title, author, subject, keywords, creator, producer; case-insensitive) to a substring its value must contain.v0.1.0
min_pagesintegerLower bound on the page count.v0.1.0
pagesintegerAsserts the exact page count.v0.1.0
pathstringRequired. The PDF under test, resolved against the scenario workdir when relative.v0.1.0
textstreamApplies the stream matchers to the text extracted from the PDF’s content streams.v0.1.0

mock #

Checks what the CLI under test sent to a mock server (#24): filter by path/method, pin the exact count (or require at least one match), and match header/body of the LAST matching request.

KeyTypeDescriptionSince
bodystreamMatches the body of the LAST matching recorded request with the stream matchers.v0.3.0
countintegerAsserts the exact number of matching requests (without it, at least one must exist).v0.3.0
headerheaderMatchMatches a header of the LAST matching recorded request.v0.3.0
methodstringFilters recorded requests by method (case-insensitive).v0.3.0
namestringRequired. References a declared mock server by name.v0.3.0
pathstringFilters recorded requests by exact path.v0.3.0

header matcher #

KeyTypeDescriptionSince
containsstringRequires the header value to contain this substring.v0.1.0
equalsstringRequires the header value to equal this string exactly.v0.1.0
matchesstringRegexp the header value must match - the natural shape for auth headers (^Bearer ).v0.3.0
namestringRequired. The header name to check (case-insensitive).v0.1.0

json / yaml checks #

KeyTypeDescriptionSince
equalsanyv0.1.0
gtnumberRequires the selected numeric value to be greater than this bound.v0.1.0
gtenumberRequires the selected numeric value to be at least this bound.v0.1.0
lengthintegerAsserts the selected array or string has exactly this length.v0.1.0
ltnumberRequires the selected numeric value to be less than this bound.v0.1.0
ltenumberRequires the selected numeric value to be at most this bound.v0.1.0
matchesstringRequires the selected value (as a string) to match this Go regular expression.v0.1.0
pathstringRequired. JSONPath selecting the value under test (e.g. “$.items[0].name”).v0.1.0

retry #

KeyTypeDescriptionSince
intervalstringWait between attempts as a Go duration (e.g. “200ms”). Empty means no wait.v0.1.0
timesintegerRequired. Maximum number of attempts (>= 1).v0.1.0
untilassertRequired. A single assertion polled after each attempt; the loop stops as soon as it passes. If it never passes, the step fails.v0.1.0

skip / only conditions #

KeyTypeDescriptionSince
commandstringTrue when this probe command (run through the shell) exits 0.v0.1.0
envstringTrue when the named environment variable is non-empty.v0.1.0
oslinux | darwin | windowsMatches the host operating system (linux, darwin, windows).v0.1.0

runners.<name> #

A runner is discriminated by type: only the fields for that type are allowed, so cross-type fields are rejected and editors can narrow completion (#44).

KeyTypeDescriptionSince
type: cmd
cwdstringWorking directory for commands run through this runner, relative to the scenario workdir.v0.1.0
timeoutstringDefault timeout for steps using this runner, as a Go duration.v0.1.0
typeanySelects the cmd runner: local command execution (the implicit default for run steps).v0.1.0
type: http
base_urlstringBase URL every http step’s path is appended to.v0.1.0
cwdstringUnused for http runners; accepted for uniformity.v0.1.0
timeoutstringRequest timeout as a Go duration.v0.1.0
typeanySelects the http runner: HTTP requests from http steps.v0.1.0
type: db
cwdstringUnused for db runners; accepted for uniformity.v0.1.0
driversqlite | sqlite3 | postgres | postgresql | mysqlNames the database/sql driver explicitly (sqlite, postgres, or mysql), overriding scheme inference from the dsn.v0.1.0
dsnstringRequired. Data source name, e.g. “sqlite:${workdir}/app.db”, “postgres://user:pass@host/db”, or “mysql://user:pass@host:3306/db”. Pure-Go drivers are bundled.v0.1.0
timeoutstringStatement timeout as a Go duration.v0.1.0
typeanySelects the db runner: SQL from query steps.v0.1.0
type: ssh
cwdstringRemote working directory for commands.v0.1.0
hoststringRequired. Remote host, as host or host:port (default port 22).v0.1.0
insecure_host_keybooleanMust be set to true to connect without a known_hosts file, explicitly disabling host-key verification.v0.1.0
key_filestringPath to a private key for key authentication.v0.1.0
known_hostsstringknown_hosts file verifying the host key (recommended).v0.1.0
passwordstringPassword authentication (prefer key_file, and keep the value in an env var).v0.1.0
timeoutstringCommand timeout as a Go duration.v0.1.0
typeanySelects the ssh runner: running commands on a remote host.v0.1.0
userstringRequired. Login user.v0.1.0
type: grpc
cwdstringUnused for grpc runners; accepted for uniformity.v0.1.0
targetstringRequired. host:port of the gRPC server; the schema is resolved via server reflection.v0.1.0
timeoutstringCall timeout as a Go duration.v0.1.0
tlsbooleanConnect with TLS (default plaintext).v0.1.0
typeanySelects the grpc runner: unary gRPC calls from grpc steps.v0.1.0
type: browser
browser_argsarray of stringExtra Chrome launch flags (bare names, no leading ‘–’), e.g. ‘disable-gpu’ or ‘window-size=1280,720’.v0.1.0
cwdstringUnused for browser runners; accepted for uniformity.v0.1.0
exec_pathstringPath to a specific Chrome/Chromium binary instead of the one discovered on PATH.v0.1.0
headlessbooleanRun Chrome without a visible window (default true); set false to debug headed.v0.1.0
timeoutstringSession timeout as a Go duration.v0.1.0
typeanySelects the browser runner: headless Chrome driven by cdp steps.v0.1.0

defaults #

Spec-wide default fragments merged into every matching element at load time (#39). Authoring sugar only: an explicit value always wins, maps shallow-merge, and a boolean default is OR-ed in. Not a macro/include system.

KeyTypeDescriptionSince
runobjectLayered beneath every run step. command and retry are per-step and rejected here. The environment-shaping subset (env, clear_env, pass_env, sandbox_home) also layers onto pty steps, which share the same environment surface (#77); the run-only fields (runner, shell, cwd, timeout, stdin, redirects) stay per-step and never reach pty steps.v0.1.0
clear_envbooleanStart the child from an empty environment instead of inheriting the host environment (#16). On Windows a small system-critical set (SystemRoot, SystemDrive, TEMP, TMP, PATHEXT) is always retained.v0.3.0
cwdstringDefault working directory for every run step.v0.1.0
envmap of stringDefault env map shallow-merged beneath every run step’s own env.v0.1.0
pass_envarray of stringHost variables copied into the cleared environment (#16). Requires clear_env: true; unset host variables are skipped.v0.3.0
runnerstringDefault runner name for every run step.v0.1.0
sandbox_homebooleanPoint the child’s home and per-OS config/cache/data/state dirs at ${workdir}/.atago-home so a CLI touching ~/.config, ~/.cache, or %APPDATA% runs hermetically (#71). Precedence: step env > sandbox > pass_env > host; composes with clear_env.v0.3.0
shellbooleanDefault shell for every run step (an authored shell: false on a step cannot override a defaulted true).v0.1.0
timeoutstringDefault timeout for every run step (a step’s own timeout wins).v0.1.0
scenarioobjectScenario-level defaults. Only env is supported; it shallow-merges beneath each scenario’s own env.v0.1.0
envmap of stringEnv map shallow-merged beneath every scenario’s own env.v0.1.0
serviceobjectLayered beneath every service. name and command identify a service and are rejected here; a whole ready probe is copied in when a service declares none.v0.1.0
clear_envbooleanStart the child from an empty environment instead of inheriting the host environment (#16). On Windows a small system-critical set (SystemRoot, SystemDrive, TEMP, TMP, PATHEXT) is always retained.v0.3.0
cwdstringDefault working directory for every service.v0.1.0
envmap of stringDefault env map for every service.v0.1.0
pass_envarray of stringHost variables copied into the cleared environment (#16). Requires clear_env: true; unset host variables are skipped.v0.3.0
readyobjectDefault readiness probe for every service (a service’s own ready wins).v0.1.0
delaystringSee service.ready.delay.v0.1.0
filestringSee service.ready.file.v0.1.0
logstringSee service.ready.log.v0.1.0
portstringSee service.ready.port.v0.1.0
storestringSee service.ready.store.v0.1.0
timeoutstringSee service.ready.timeout.v0.1.0
shellbooleanDefault shell for every service.v0.1.0

Editor support (JSON Schema) #

A JSON Schema lives at schema/atago.schema.json. With the YAML language server you get completion and validation as you type — step types, every matcher, and the ${workdir} / ${env:NAME} / ${name} / $${...} expansion rules. atago init and atago record already emit this header as the first line of every generated spec, so scaffolded specs get completion out of the box. To add it to an existing spec, use the absolute URL (it resolves in any project, unlike a repo-relative path):

# yaml-language-server: $schema=https://raw.githubusercontent.com/nao1215/atago/main/schema/atago.schema.json
version: "1"

The report and manifest outputs have schemas too: report.schema.json and manifest.schema.json.

Shell completion #

atago completion <bash|zsh|fish|powershell> prints a completion script for your shell.

Exit codes #

CodeMeaning
0all scenarios passed
1one or more failed
2spec error (YAML syntax or schema/semantic validation)
3CLI-invocation error (unknown subcommand, bad flag, or no matching spec files)
4execution error
5internal error
6security policy violation

Ctrl-C/SIGTERM stops the run cleanly: in-flight processes, services, and sessions are torn down, partial results are reported, and the run exits 4.