missouri
Show-me state. End-to-end testing as directed graphs of filesystem states.
Missouri tests a CLI tool by modeling its behavior as a directed graph of filesystem states. A state is a directory. It holds the exact files that must exist at that point in the test. A transition is a shell command. Missouri runs the command, then compares the resulting directory against the target state directory, byte for byte.
There is no assertion language. The expected state is the directory.
How it works
A test suite is a set of directories, and each directory is a state. Each
state's .missouri/missouri.yml declares its transitions. A transition
names a command to run and the state directory that the filesystem must
match after the command. Missouri finds every path through the graph,
runs each path in a temp directory with a cleared environment, and diffs
the result against the target.
clean/ # starting state (empty project)
.missouri/
missouri.yml # transitions: [{command: "echo hello > out.txt", target: ../built}]
built/ # expected state after command
.missouri/
missouri.yml
out.txt # file that should exist: contains "hello"
$ missouri run
✓ [1/1]
PASS clean → built 14ms
1 passed, 0 failed, 1 step in 14ms
A state can have several outgoing transitions, which is branching, and several states can point at the same target, which is convergence. The directory tree is the test suite.
Isolation
Every command runs with env_clear(). The process inherits no
environment variable from the host. Declare every variable a test needs
in the test config. The test then behaves the same on your machine and in
CI.
For stronger isolation, missouri also runs a command inside a nix shell or a Docker container.
Beyond filesystem diffs
A state can also declare assertions. An assertion is a shell command, and its exit code and output decide whether it passes. A transition can declare a custom comparator for a file that a byte-for-byte diff reads wrong, and a background service for a command that needs a server running. An agent assertion hands a judgment call to an LLM.
Install
The package is msri on PyPI and npm, because missouri was taken. The
command is missouri everywhere, and both names install together.
cargo install --locked missouri
brew install cjohnhanson/tap/missouri
uv tool install msri
npm install -g msri
cargo install builds from source. It needs Rust 1.88 and a C
compiler. The other three carry a prebuilt binary for macOS and Linux,
x86-64 and arm64, published by a tagged release.
To build the unreleased main branch:
cargo install --locked --git https://github.com/cjohnhanson/missouri
Or run it without installing:
uvx msri run
npx msri run
From that point the releases
page also carries
prebuilt archives and a .deb. Each archive holds the binary and the man
page. Install a .deb with dpkg -i: it
is a file, not a repository, so apt-get install does not reach it.
Check the install with missouri --version.
Usage
missouri init # set up a new project
missouri state add <name> # create a state directory
missouri run # execute all test paths
missouri run -v # verbose output
missouri list # show states, transitions, paths
missouri validate # check graph is well-formed
missouri report # generate a report from a recorded run
missouri docs [topic] # bundled documentation
Documentation
- What is Missouri?. The testing model, why graphs, and how a path runs.
- Getting Started. A walkthrough of a first test suite.
- Writing Tests. Transitions, assertions, comparators, and services.
- CLI Reference. Every command and every config field.
Related
- tisket. An issue tracker. Markdown issues with YAML frontmatter, in the repository.
- zettel. Zettelkasten notes for a repository.
- almanac. An agent skill index over pluggable sources.
- gaff. A context-lifecycle handler for coding agents.
- mdstore. The frontmattered markdown library that tisket, zettel, and almanac store documents with.
License
MIT.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file msri-0.2.2.tar.gz.
File metadata
- Download URL: msri-0.2.2.tar.gz
- Upload date:
- Size: 125.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d66ce36103dd461594c260a01b5fce5bb95bf97912eb09cf1f9682f9642fdbc0
|
|
| MD5 |
2540bce094a2bba8911611ac8eabb4f1
|
|
| BLAKE2b-256 |
9f36f650b80c966b430cc181a2e05b20557951bf40b63ebc67d1ebddb1bf6a52
|
File details
Details for the file msri-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.musllinux_1_1_x86_64.whl.
File metadata
- Download URL: msri-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.musllinux_1_1_x86_64.whl
- Upload date:
- Size: 3.2 MB
- Tags: Python 3, manylinux: glibc 2.17+ x86-64, musllinux: musl 1.1+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
91b0c7272ea189537d849233ccd5638fe7ef400a384a143c165f3114fd30e2aa
|
|
| MD5 |
f986927f4f90ed9f23179b117194df95
|
|
| BLAKE2b-256 |
0089b667b0656cdb309e97dd6e7d258ee7abf03f9281c3ab5a9a3a82646eafc4
|
File details
Details for the file msri-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl.
File metadata
- Download URL: msri-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl
- Upload date:
- Size: 2.9 MB
- Tags: Python 3, manylinux: glibc 2.17+ ARM64, musllinux: musl 1.1+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3b7393fc936453e95c2a327bc0f42977f2824ac4b9beb178e242836ad0293e02
|
|
| MD5 |
a06471844f56e1c35ade173b95722057
|
|
| BLAKE2b-256 |
4d931c97efd463329fc91ecae81dfd4f44a40bbb2dd55c88763fe9e9fe175a5c
|
File details
Details for the file msri-0.2.2-py3-none-macosx_11_0_arm64.whl.
File metadata
- Download URL: msri-0.2.2-py3-none-macosx_11_0_arm64.whl
- Upload date:
- Size: 2.8 MB
- Tags: Python 3, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
527fcddb1124bfd01f27c2674f233c1e6a2dec2c0aa181580c54e64e2a8e6433
|
|
| MD5 |
1e421df204b9653b28675ce927fe6d8f
|
|
| BLAKE2b-256 |
bf2dd2624a880beb551cf982cc5fda9921e11c3f5edf9d3fb110ff5febdc9197
|
File details
Details for the file msri-0.2.2-py3-none-macosx_10_12_x86_64.whl.
File metadata
- Download URL: msri-0.2.2-py3-none-macosx_10_12_x86_64.whl
- Upload date:
- Size: 2.9 MB
- Tags: Python 3, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.13 {"installer":{"name":"uv","version":"0.12.13","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e55147979a55e1ab5d54a9bcac8e8bef5450aa5c2c8e08d9a1ac0bc47d6ab537
|
|
| MD5 |
2674f2b0df6b9e4d7185ab1e1ef58b66
|
|
| BLAKE2b-256 |
d4a4aba9d9bf6e4c3041b8da85ea477c56036454c45a876018cf66edbbc7ece3
|