Skip to main content

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

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

msri-0.2.2.tar.gz (125.8 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

msri-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.musllinux_1_1_x86_64.whl (3.2 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64musllinux: musl 1.1+ x86-64

msri-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl (2.9 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64musllinux: musl 1.1+ ARM64

msri-0.2.2-py3-none-macosx_11_0_arm64.whl (2.8 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

msri-0.2.2-py3-none-macosx_10_12_x86_64.whl (2.9 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

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

Hashes for msri-0.2.2.tar.gz
Algorithm Hash digest
SHA256 d66ce36103dd461594c260a01b5fce5bb95bf97912eb09cf1f9682f9642fdbc0
MD5 2540bce094a2bba8911611ac8eabb4f1
BLAKE2b-256 9f36f650b80c966b430cc181a2e05b20557951bf40b63ebc67d1ebddb1bf6a52

See more details on using hashes here.

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

Hashes for msri-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.musllinux_1_1_x86_64.whl
Algorithm Hash digest
SHA256 91b0c7272ea189537d849233ccd5638fe7ef400a384a143c165f3114fd30e2aa
MD5 f986927f4f90ed9f23179b117194df95
BLAKE2b-256 0089b667b0656cdb309e97dd6e7d258ee7abf03f9281c3ab5a9a3a82646eafc4

See more details on using hashes here.

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

Hashes for msri-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl
Algorithm Hash digest
SHA256 3b7393fc936453e95c2a327bc0f42977f2824ac4b9beb178e242836ad0293e02
MD5 a06471844f56e1c35ade173b95722057
BLAKE2b-256 4d931c97efd463329fc91ecae81dfd4f44a40bbb2dd55c88763fe9e9fe175a5c

See more details on using hashes here.

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

Hashes for msri-0.2.2-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 527fcddb1124bfd01f27c2674f233c1e6a2dec2c0aa181580c54e64e2a8e6433
MD5 1e421df204b9653b28675ce927fe6d8f
BLAKE2b-256 bf2dd2624a880beb551cf982cc5fda9921e11c3f5edf9d3fb110ff5febdc9197

See more details on using hashes here.

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

Hashes for msri-0.2.2-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 e55147979a55e1ab5d54a9bcac8e8bef5450aa5c2c8e08d9a1ac0bc47d6ab537
MD5 2674f2b0df6b9e4d7185ab1e1ef58b66
BLAKE2b-256 d4a4aba9d9bf6e4c3041b8da85ea477c56036454c45a876018cf66edbbc7ece3

See more details on using hashes here.

Release history Release notifications | RSS feed

0.2.3

5 files

This release

0.2.2 This release

5 files

0.2.1

5 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page