missouri configuration format
Missouri uses YAML config files named missouri.yml. There are two levels. The project-level config has one file per project root. The state-level config has one file per state directory.
Config file locations
Missouri loads the project-level config from the first file it finds, in this order:
<root>/missouri.yml, the root-level config. It can includetest_dir.<root>/<config_dir>/missouri.yml, the config-dir-level config.
The root-level file wins when both files exist.
The state-level config lives at <state_dir>/<config_dir>/missouri.yml.
Project-level missouri.yml
# The directory that holds the test states, relative to this config file.
# When set, state discovery starts here instead of at the project root.
test_dir: tests/smoke
# Environment variables that every state inherits.
# A state-level variable of the same name overrides the value here.
env:
RUST_BACKTRACE: "1"
APP_ENV: test
# Commands that run in order before any test path.
# Execution stops at the first failure.
setup:
- name: "build project" # optional label
command: "cargo build --release"
shell: true # default: true
- command: "db-seed"
shell: false
# Nixpkgs packages for transition, assertion, and comparator commands.
# Commands use the environment from one warm-up `nix shell`.
# If missouri cannot read that environment, each command runs inside its own `nix shell`.
packages:
- python3
- uv
- git
# Workspace mode: a list of member directories.
# When set, `missouri run` runs each member on its own.
members:
- my-tool/tests/missouri
- other-tool/tests/missouriFields
| Field | Type | Default | Description |
|---|---|---|---|
test_dir |
string | (none) | Start state discovery in this subdirectory. |
env |
map<string, string> | {} |
Project-level environment variables. |
setup |
list of SetupCommand | [] |
Commands to run before the test paths. |
packages |
list of string | [] |
Nixpkgs packages for the sandbox. |
members |
list of string | [] |
Workspace member directories. |
docker |
bool | false |
Run every transition inside a Docker container with no network access. It overrides packages. An assertion, a comparator, and a service run on the host, so missouri refuses each under docker: true. |
docker_image |
string | debian:bookworm-slim |
The image the containers run. Requires docker: true. |
SetupCommand
| Field | Type | Default | Description |
|---|---|---|---|
name |
string | auto-generated (setup[N]) |
A label for the output. |
command |
string | required | The command to run. |
shell |
bool | true |
Run the command through sh -c. When false, missouri splits the command on whitespace and runs it directly. |
State-level missouri.yml
# Environment variables for this state.
# Missouri merges these over the project-level env.
# A state variable of the same name wins.
env:
DB_URL: "postgres://localhost/test"
# Transitions out of this state.
transitions:
- name: "build" # optional label
command: "make build"
target: "../built" # relative path to the target state directory
shell: true # default: true
stdout: "expected stdout\n" # optional exact-match assertion
stderr: "" # optional exact-match assertion
# Background services (see Services section)
services:
- command: "my-server --port 0"
# Network interception (see Network section)
network:
replay: recordings/worker.flow
# Comparison overrides (see Comparators section)
comparators:
files:
- path: "dist/manifest.json"
command: "compare-json"
- path: "logs/"
ignore: true
env:
- name: BUILD_TIMESTAMP
ignore: true
network:
- path: "api.example.com/v1/*"
command: "compare-api"
- path: "*.googleapis.com/**"
ignore: true
# Assertions to verify properties of this state.
assertions:
- name: "check output" # optional label
command: "echo hello"
shell: true # default: true
stdout: "hello\n" # optional exact-match
stderr: "" # optional exact-match
should_fail: false # default: false
services: # optional background services
- command: "my-server --port 0"An empty config ({}) is valid. It declares a terminal state with no outgoing transitions and no assertions.
Fields
| Field | Type | Default | Description |
|---|---|---|---|
env |
map | {} |
Environment variables for this state. Missouri merges them over the project-level env, and a state variable of the same name wins. |
transitions |
list of Transition | [] |
The transitions out of this state. |
assertions |
list of Assertion | [] |
The assertions that check this state. |
entrypoint |
bool | false |
When true, this state’s fixture is a complete start point. A path can begin here, and a path that arrives here stops. |
doc |
string | (none) | Prose that describes this state. missouri docgen renders it before the state’s file tree. |
Transition
| Field | Type | Default | Description |
|---|---|---|---|
name |
string | auto-generated (statename[N]) |
A label for the output. |
command |
string | required | The command to run. |
shell |
bool | true |
Run the command through sh -c. When false, missouri splits the command on whitespace. |
target |
string | required | The relative path to the target state directory. |
stdout |
string | (none) | The exact stdout to expect. Missouri checks it in every mode that runs the transition. |
stderr |
string | (none) | The exact stderr to expect. Missouri checks it in every mode that runs the transition. |
services |
list of Service | [] |
Background services to run during this transition. |
network |
NetworkConfig | (none) | The network interception config. |
comparators |
Comparators | (none) | Change how missouri compares specific files, environment variables, or network requests. |
doc |
string | (none) | Prose that describes this transition. missouri docgen renders it. |
Assertion
Set command or agent, but not both.
| Field | Type | Default | Description |
|---|---|---|---|
name |
string | auto-generated | A label for the output. |
command |
string | (none) | The command to run. Required unless you set agent. |
agent |
string | (none) | The agent eval name. It matches <config_dir>/<name>.md. Conflicts with command. |
shell |
bool | true |
Run the command through sh -c. Applies to command assertions only. |
stdout |
string | (none) | The exact stdout to expect. Applies to command assertions only. |
stderr |
string | (none) | The exact stderr to expect. Applies to command assertions only. |
should_fail |
bool | false |
When true, the assertion passes if the command exits non-zero. Missouri still matches stdout and stderr when you set them. Applies to command assertions only. |
services |
list of Service | [] |
Background services to run during this assertion. |
Comparators
A comparator changes how missouri compares a path, an environment variable, or a network request during a transition. Declare comparators under the comparators key on a transition.
File comparators (comparators.files)
| Field | Type | Default | Description |
|---|---|---|---|
path |
string | required | A relative path. A trailing / means a directory subtree. |
command |
string | (none) | A custom comparator command. Missouri passes two paths as arguments: actual, then expected. |
ignore |
bool | false |
Remove this path from the comparison. |
Set command or ignore: true. When an entry sets both, ignore wins
and the command never runs.
Env comparators (comparators.env)
| Field | Type | Default | Description |
|---|---|---|---|
name |
string | required | The environment variable name. |
command |
string | (none) | A custom comparator command. Missouri passes the two values as arguments. |
ignore |
bool | false |
Remove this environment variable from the comparison. |
Network comparators (comparators.network)
| Field | Type | Default | Description |
|---|---|---|---|
path |
string | required | A URL path pattern, such as "api.example.com/v1/messages" or "*.googleapis.com/**". |
command |
string | (none) | A custom comparator command. |
ignore |
bool | false |
Remove the matching requests from the comparison. |
Network interception
Configure network interception on each transition under the network key. Missouri uses mitmdump, from mitmproxy, to intercept HTTP and HTTPS traffic. Each transition uses one mode.
Replay mode replays traffic that you recorded earlier:
network:
replay: recordings/worker.flowMissouri resolves the replay path against the source state’s <config_dir>/ directory.
Record mode captures the traffic during the transition:
network:
record: trueMissouri writes each recorded flow to <source_state>/<config_dir>/recordings/<transition_name>.flow.
When network interception is active, missouri sets these environment variables for the transition command:
| Variable | Value |
|---|---|
HTTPS_PROXY |
http://127.0.0.1:<port> |
HTTP_PROXY |
http://127.0.0.1:<port> |
NODE_EXTRA_CA_CERTS |
~/.mitmproxy/mitmproxy-ca-cert.pem |
mitmdump must be on PATH. Add mitmproxy to packages, or install it yourself.
Services
Attach a background service to a transition or to an assertion. A service is a long-running process. Missouri starts it before the command runs. Missouri then stops it after the command finishes, first with SIGTERM and then with SIGKILL.
services:
- command: "my-server --port 0"
shell: true # default: true
port_pattern: "Serving on port (\\d+)" # regex with one capture group
ready: "curl -sf http://localhost:$PORT/health"| Field | Type | Default | Description |
|---|---|---|---|
command |
string | required | The command that starts the service. |
shell |
bool | true |
Run the command through sh -c. |
port_pattern |
string | listening.*:(\d+) (runtime default) |
A regex that reads the port number from stderr. It must hold exactly one capture group. Missouri applies the default at runtime, not in the config schema. Omit the field to use the default pattern. |
ready |
string | (none) | A readiness check command. Missouri retries it with exponential backoff, from 100ms to 5s, up to 10 times. $PORT is set in the environment. |
The service starts and prints its port to stderr. Missouri reads the port and sets these environment variables:
- With one service,
$PORT. - With several services,
$PORTholds the first service’s port, and$PORT_0,$PORT_1, and so on hold each port in order.
Missouri starts each service in its own process group, so cleanup can stop the whole process tree. Port detection times out after 30 seconds. If the service prints no matching line to stderr in that time, missouri stops the service and fails the step.
Ignore patterns
The file <config_dir>/ignore, for example .missouri/ignore, uses gitignore syntax. Its patterns remove paths from the filesystem comparison for every transition.
# .missouri/ignore
*.log
tmp/
!important.logThe standard gitignore rules apply. A trailing / matches a directory. A ! negates a pattern. A ** matches across directory boundaries. A # starts a comment.
When you set test_dir, missouri loads the ignore file from the test directory’s config directory, for example tests/.missouri/ignore.
Shared bin directory
Missouri prepends <config_dir>/bin/ to PATH for every command. This works at two levels:
- The project bin,
<root>/<config_dir>/bin/, reaches every state and transition. - A state bin,
<state>/<config_dir>/bin/, reaches that state’s assertions and the transitions that start there.
The PATH order is state bin, then project bin, then the base PATH.
When you set test_dir, missouri looks for the project bin in the test directory first. It then falls back to the root config directory.
Sandbox and packages
When the project config sets packages, missouri gets the packages from nixpkgs through nix shell. For each suite, missouri runs warm-up once before the paths run in parallel. During warm-up, missouri resolves the nixpkgs flake reference to a pinned commit hash. Parallel commands never read the flake registry. During warm-up, missouri runs /usr/bin/env -0 inside one nix shell with the packages. If /usr/bin/env is missing or does not accept -0, Missouri cannot read the environment during warm-up. The warm-up step records the environment that nix shell gives a command. This environment puts the package directories first in PATH. It also includes any other variables that nix shell sets. During the run, missouri roots those store paths to prevent garbage collection from deleting them.
With this environment, each transition, assertion, and comparator command runs without its own nix shell. Each command sees the same PATH as a command inside nix shell. The command’s stderr contains no messages from nix itself. Nix writes nothing to the cache under the command’s HOME. If missouri cannot read the environment from warm-up, it prints a warning. In this case, missouri runs each command inside its own nix shell. This fallback takes more time. The warning names MISSOURI_SANDBOX=preinstalled as the way to skip nix when the packages are already on PATH.
The MISSOURI_SANDBOX environment variable overrides the sandbox behavior:
| Value | Effect |
|---|---|
preinstalled |
Skip the nix shell. Assume that every package is already on PATH. Use this inside a nix derivation where the packages are nativeCheckInputs. |
Missouri exits with an error when packages is not empty, nix is not on PATH, and MISSOURI_SANDBOX is not preinstalled.
State graph model
Missouri models a test suite as a directed graph. The states are the nodes, and the transitions are the edges.
A state is a directory on disk. Its contents are a snapshot of the filesystem at one point in the test. Each state directory holds a <config_dir>/missouri.yml file that declares its outgoing transitions and its assertions.
A transition is a command that changes the filesystem from one state to another. Missouri runs the command in a temp copy of the source state. It then diffs the result against the expected target state.
A root state has no inbound transitions. Test path enumeration starts at the root states.
A terminal state has no outgoing transitions. Its config is empty, or it holds assertions only. A test path ends here.
A test path is a walk through the graph from a root state. It ends at a terminal state, at a state that sets entrypoint: true, or at a cycle where every successor is already visited. Missouri enumerates every such path and runs the paths in parallel. A graph that branches (A -> B and A -> C) produces two paths.
A chained path is a multi-step path such as A -> B -> C. Missouri carries the temp directory from one transition forward as the input to the next. It does not copy the intermediate state from disk again.
Assertions run at the state boundaries. Full mode is the default. In Full mode, the source state’s assertions run before the first transition, and the target state’s assertions run after each transition. In CheckOnly mode, only the assertions run. Missouri skips the transitions and the filesystem comparison. In NoCheck mode, missouri skips the assertions.
In workspace mode, set by a members list in the project config, missouri treats each member directory as its own project. It runs the members one after another and reports the results for each member.