Skip to content
missouri configuration format

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:

  1. <root>/missouri.yml, the root-level config. It can include test_dir.
  2. <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/missouri

Fields

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.flow

Missouri resolves the replay path against the source state’s <config_dir>/ directory.

Record mode captures the traffic during the transition:

network:
  record: true

Missouri 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, $PORT holds 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.log

The 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.