Repository: onecodex/finch-rs (language: python)

Issue:
split finch-rs into library and binary
Libraries [should not have a cargo.lock whereas binaries should](https://doc.rust-lang.org/cargo/faq.html#why-do-binaries-have-cargolock-in-version-control-but-not-libraries). The fact that finch-rs doesn't have a lockfile means that the `finch-rs` binary can't easily continue supporting a particular version of Rust without constantly running CI to verify that it compiles. A (possibly transitive) dependency could be updated at any time, breaking the build (this happened when I was working on #46). A lockfile prevents the build breaking at any time, but is ignored by libraries. The library version of finch-rs would need a minimum rust version of `stable`, since some of its dependencies require stable (for example [`object`](https://crates.io/crates/object)).
Separate CLI and lib
Closes #48


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 0f97873..3fbfe94 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -6,7 +6,7 @@ on:
   pull_request:
 
 jobs:
-  python-compile:
+  python-bindings:
     runs-on: ubuntu-latest
     steps:
       - name: Checkout
@@ -15,27 +15,37 @@ jobs:
       - uses: actions-rs/toolchain@v1
         with:
           profile: minimal
-          toolchain: nightly
+          toolchain: stable
           override: true
+
       - name: version info
         run:  rustc --version; cargo --version;
 
       - name: Install python headers
-        run: sudo apt-get update && sudo apt-get install python3-dev python3-pip
+        run: sudo apt-get update && sudo apt-get install python3-dev python3-pip python3-venv
 
       - name: Install maturin
-        run: | 
-          pip3 install --user maturin
+        run: |
+          python3 -m venv venv
+          . venv/bin/activate
+          pip3 install toml
+          pip3 install maturin
           pip3 show maturin
-
-
+      - name: add library to venv
+        run: |
+          . venv/bin/activate
+          cd lib
+          maturin develop --cargo-extra-args="--features=python"
       - name: compile finch with python bindings
-        run: ~/.local/bin/maturin build --cargo-extra-args="--features=python" --release --strip --manylinux=off
+        run: |
+          . venv/bin/activate
+          cd lib
+          maturin build --cargo-extra-args="--features=python" --release --strip --manylinux=off
 
   tests:
     strategy:
       matrix:
-        rust-version: [1.38.0, stable]
+        rust-version: [1.43.0, stable]
     runs-on: ubuntu-latest
     steps:
       - name: Checkout
@@ -51,7 +61,7 @@ jobs:
         run:  rustc --version; cargo --version;
 
       - name: Run all tests
-        run: cargo test
+        run: cargo test --all
 
   fmt:
     runs-on: ubuntu-latest
@@ -85,4 +95,4 @@ jobs:
       - uses: actions-rs/cargo@v1
         with:
           command: clippy
-          args: -- -D warnings
+          args: --all -- -D warnings
diff --git a/.gitignore b/.gitignore
index 5b2da7f..eec141d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,4 @@
 target
-Cargo.lock
 .DS_Store
 
 *.swp
@@ -9,3 +8,5 @@ venv/
 dist/
 __pycache__/
 .idea/
+lib/Cargo.lock
+
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644
index 0000000..2ae55a4
--- /dev/null
+++ b/Cargo.lock
@@ -0,0 +1,1114 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+[[package]]
+name = "adler"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
+
+[[package]]
+name = "aho-corasick"
+version = "0.7.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1"
+
+[[package]]
+name = "assert_cmd"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3dc1679af9a1ab4bea16f228b05d18f8363f8327b1fa8db00d2760cfafc6b61e"
+dependencies = [
+ "doc-comment",
+ "predicates",
+ "predicates-core",
+ "predicates-tree",
+ "wait-timeout",
+]
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
+name = "bincode"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d"
+dependencies = [
+ "byteorder",
+ "serde",
+]
+
+[[package]]
+name = "bit-set"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de"
+dependencies = [
+ "bit-vec",
+]
+
+[[package]]
+name = "bit-vec"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
+
+[[package]]
+name = "bitflags"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
+
+[[package]]
+name = "buf_redux"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f"
+dependencies = [
+ "memchr",
+ "safemem",
+]
+
+[[package]]
+name = "bytecount"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72feb31ffc86498dacdbd0fcebb56138e7177a8cc5cea4516031d15ae85a742e"
+
+[[package]]
+name = "byteorder"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b"
+
+[[package]]
+name = "bzip2"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b"
+dependencies = [
+ "bzip2-sys",
+ "libc",
+]
+
+[[package]]
+name = "bzip2-sys"
+version = "0.1.9+1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad3b39a260062fca31f7b0b12f207e8f2590a67d32ec7d59c20484b07ea7285e"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+]
+
+[[package]]
+name = "capnp"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee33f13b9419d35f9ae6e0ee2e5ef6bd059a4d0da2fda16a88ddaf57dfe9acca"
+
+[[package]]
+name = "cc"
+version = "1.0.66"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48"
+
+[[package]]
+name = "cfg-if"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "clap"
+version = "2.33.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002"
+dependencies = [
+ "ansi_term",
+ "atty",
+ "bitflags",
+ "strsim",
+ "textwrap",
+ "unicode-width",
+ "vec_map",
+]
+
+[[package]]
+name = "const_fn"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6"
+
+[[package]]
+name = "crc32fast"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
+dependencies = [
+ "cfg-if 1.0.0",
+]
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775"
+dependencies = [
+ "cfg-if 1.0.0",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9"
+dependencies = [
+ "cfg-if 1.0.0",
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1aaa739f95311c2c7887a76863f500026092fb1dce0161dab577e559ef3569d"
+dependencies = [
+ "cfg-if 1.0.0",
+ "const_fn",
+ "crossbeam-utils",
+ "lazy_static",
+ "memoffset",
+ "scopeguard",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d"
+dependencies = [
+ "autocfg",
+ "cfg-if 1.0.0",
+ "lazy_static",
+]
+
+[[package]]
+name = "ctor"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10bcb9d7dcbf7002aaffbb53eac22906b64cdcc127971dcc387d8eb7c95d5560"
+dependencies = [
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "difference"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
+
+[[package]]
+name = "doc-comment"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
+
+[[package]]
+name = "either"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
+
+[[package]]
+name = "finch"
+version = "0.4.0"
+dependencies = [
+ "anyhow",
+ "assert_cmd",
+ "clap",
+ "finch_lib",
+ "predicates",
+ "proptest",
+ "serde_json",
+]
+
+[[package]]
+name = "finch_lib"
+version = "0.4.0"
+dependencies = [
+ "bincode",
+ "capnp",
+ "memmap",
+ "murmurhash3",
+ "ndarray",
+ "needletail",
+ "numpy",
+ "predicates",
+ "proptest",
+ "pyo3",
+ "rayon",
+ "serde",
+ "serde_json",
+ "thiserror",
+]
+
+[[package]]
+name = "flate2"
+version = "1.0.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7411863d55df97a419aa64cb4d2f167103ea9d767e2c54a1868b7ac3f6b47129"
+dependencies = [
+ "cfg-if 1.0.0",
+ "crc32fast",
+ "libc",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "float-cmp"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1267f4ac4f343772758f7b1bdcbe767c218bbab93bb432acbf5162bbf85a6c4"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "getrandom"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
+dependencies = [
+ "cfg-if 1.0.0",
+ "libc",
+ "wasi 0.9.0+wasi-snapshot-preview1",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8"
+dependencies = [
+ "cfg-if 1.0.0",
+ "libc",
+ "wasi 0.10.1+wasi-snapshot-preview1",
+]
+
+[[package]]
+name = "ghost"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a5bcf1bbeab73aa4cf2fde60a846858dc036163c7c33bec309f8d17de785479"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "indoc"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5a75aeaaef0ce18b58056d306c27b07436fbb34b8816c53094b76dd81803136"
+dependencies = [
+ "unindent",
+]
+
+[[package]]
+name = "instant"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec"
+dependencies = [
+ "cfg-if 1.0.0",
+]
+
+[[package]]
+name = "inventory"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f0f7efb804ec95e33db9ad49e4252f049e37e8b0a4652e3cd61f7999f2eff7f"
+dependencies = [
+ "ctor",
+ "ghost",
+ "inventory-impl",
+]
+
+[[package]]
+name = "inventory-impl"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75c094e94816723ab936484666968f5b58060492e880f3c8d00489a1e244fa51"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "itoa"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libc"
+version = "0.2.82"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929"
+
+[[package]]
+name = "lock_api"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312"
+dependencies = [
+ "scopeguard",
+]
+
+[[package]]
+name = "lzma-sys"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bdb4b7c3eddad11d3af9e86c487607d2d2442d185d848575365c4856ba96d619"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+]
+
+[[package]]
+name = "matrixmultiply"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "916806ba0031cd542105d916a97c8572e1fa6dd79c9c51e7eb43a09ec2dd84c1"
+dependencies = [
+ "rawpointer",
+]
+
+[[package]]
+name = "memchr"
+version = "2.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
+
+[[package]]
+name = "memmap"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "memoffset"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "157b4208e3059a8f9e78d559edc658e13df41410cb3ae03979c83130067fdd87"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "miniz_oxide"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d"
+dependencies = [
+ "adler",
+ "autocfg",
+]
+
+[[package]]
+name = "murmurhash3"
+version = "0.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2983372caf4480544083767bf2d27defafe32af49ab4df3a0b7fc90793a3664"
+
+[[package]]
+name = "ndarray"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c0d5c9540a691d153064dc47a4db2504587a75eae07bf1d73f7a596ebc73c04"
+dependencies = [
+ "matrixmultiply",
+ "num-complex",
+ "num-integer",
+ "num-traits",
+ "rawpointer",
+]
+
+[[package]]
+name = "needletail"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "786b5d6f108373c38d3f96e3e141d8c07abec03a7442528b73fe6a3c432fef9a"
+dependencies = [
+ "buf_redux",
+ "bytecount",
+ "bzip2",
+ "flate2",
+ "memchr",
+ "xz2",
+]
+
+[[package]]
+name = "normalize-line-endings"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
+
+[[package]]
+name = "num-complex"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
+dependencies = [
+ "autocfg",
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "num_cpus"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
+dependencies = [
+ "hermit-abi",
+ "libc",
+]
+
+[[package]]
+name = "numpy"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f65308af05bc6952d28e2d51c730dedf6e16d48699795cb7c33d6a9db59f850"
+dependencies = [
+ "cfg-if 0.1.10",
+ "libc",
+ "ndarray",
+ "num-complex",
+ "num-traits",
+ "pyo3",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb"
+dependencies = [
+ "instant",
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ccb628cad4f84851442432c60ad8e1f607e29752d0bf072cbd0baf28aa34272"
+dependencies = [
+ "cfg-if 1.0.0",
+ "instant",
+ "libc",
+ "redox_syscall 0.1.57",
+ "smallvec",
+ "winapi",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c5d65c4d95931acda4498f675e332fcbdc9a06705cd07086c510e9b6009cd1c1"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+
+[[package]]
+name = "predicates"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73dd9b7b200044694dfede9edf907c1ca19630908443e9447e624993700c6932"
+dependencies = [
+ "difference",
+ "float-cmp",
+ "normalize-line-endings",
+ "predicates-core",
+ "regex",
+]
+
+[[package]]
+name = "predicates-core"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb3dbeaaf793584e29c58c7e3a82bbb3c7c06b63cea68d13b0e3cddc124104dc"
+
+[[package]]
+name = "predicates-tree"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aee95d988ee893cb35c06b148c80ed2cd52c8eea927f50ba7a0be1a786aeab73"
+dependencies = [
+ "predicates-core",
+ "treeline",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "proptest"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12e6c80c1139113c28ee4670dc50cc42915228b51f56a9e407f0ec60f966646f"
+dependencies = [
+ "bit-set",
+ "bitflags",
+ "byteorder",
+ "lazy_static",
+ "num-traits",
+ "quick-error",
+ "rand 0.7.3",
+ "rand_chacha 0.2.2",
+ "rand_xorshift",
+ "regex-syntax",
+ "rusty-fork",
+ "tempfile",
+]
+
+[[package]]
+name = "pyo3"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00ca634cf3acd58a599b535ed6cb188223298977d471d146121792bfa23b754c"
+dependencies = [
+ "cfg-if 1.0.0",
+ "ctor",
+ "indoc",
+ "inventory",
+ "libc",
+ "parking_lot",
+ "paste",
+ "pyo3-macros",
+ "unindent",
+]
+
+[[package]]
+name = "pyo3-macros"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "483ac516dbda6789a5b4be0271e7a31b9ad4ec8c0a5955050e8076f72bdbef8f"
+dependencies = [
+ "pyo3-macros-backend",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pyo3-macros-backend"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15230cabcda008f03565ed8bac40f094cbb5ee1b46e6551f1ec3a0e922cf7df9"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "quick-error"
+version = "1.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
+
+[[package]]
+name = "quote"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
+dependencies = [
+ "getrandom 0.1.16",
+ "libc",
+ "rand_chacha 0.2.2",
+ "rand_core 0.5.1",
+ "rand_hc 0.2.0",
+]
+
+[[package]]
+name = "rand"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18519b42a40024d661e1714153e9ad0c3de27cd495760ceb09710920f1098b1e"
+dependencies = [
+ "libc",
+ "rand_chacha 0.3.0",
+ "rand_core 0.6.1",
+ "rand_hc 0.3.0",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.5.1",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.6.1",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
+dependencies = [
+ "getrandom 0.1.16",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c026d7df8b298d90ccbbc5190bd04d85e159eaf5576caeacf8741da93ccbd2e5"
+dependencies = [
+ "getrandom 0.2.2",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
+dependencies = [
+ "rand_core 0.5.1",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73"
+dependencies = [
+ "rand_core 0.6.1",
+]
+
+[[package]]
+name = "rand_xorshift"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8"
+dependencies = [
+ "rand_core 0.5.1",
+]
+
+[[package]]
+name = "rawpointer"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
+
+[[package]]
+name = "rayon"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674"
+dependencies = [
+ "autocfg",
+ "crossbeam-deque",
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a"
+dependencies = [
+ "crossbeam-channel",
+ "crossbeam-deque",
+ "crossbeam-utils",
+ "lazy_static",
+ "num_cpus",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.1.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
+
+[[package]]
+name = "redox_syscall"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05ec8ca9416c5ea37062b502703cd7fcb207736bc294f6e0cf367ac6fc234570"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "regex"
+version = "1.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+ "thread_local",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
+
+[[package]]
+name = "remove_dir_all"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "rusty-fork"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f"
+dependencies = [
+ "fnv",
+ "quick-error",
+ "tempfile",
+ "wait-timeout",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
+
+[[package]]
+name = "safemem"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072"
+
+[[package]]
+name = "scopeguard"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+
+[[package]]
+name = "serde"
+version = "1.0.120"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "166b2349061381baf54a58e4b13c89369feb0ef2eaa57198899e2312aac30aab"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.120"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ca2a8cb5805ce9e3b95435e3765b7b553cecc762d938d409434338386cb5775"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.61"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
+
+[[package]]
+name = "strsim"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
+
+[[package]]
+name = "syn"
+version = "1.0.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc60a3d73ea6594cd712d830cc1f0390fd71542d8c8cd24e70cc54cdfd5e05d5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-xid",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
+dependencies = [
+ "cfg-if 1.0.0",
+ "libc",
+ "rand 0.8.2",
+ "redox_syscall 0.2.4",
+ "remove_dir_all",
+ "winapi",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "thread_local"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb9bc092d0d51e76b2b19d9d85534ffc9ec2db959a2523cdae0697e2972cd447"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "treeline"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
+
+[[package]]
+name = "unindent"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f14ee04d9415b52b3aeab06258a3f07093182b88ba0f9b8d203f211a7a7d41c7"
+
+[[package]]
+name = "vec_map"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
+
+[[package]]
+name = "wait-timeout"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "wasi"
+version = "0.9.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
+
+[[package]]
+name = "wasi"
+version = "0.10.1+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93c6c3420963c5c64bca373b25e77acb562081b9bb4dd5bb864187742186cea9"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "xz2"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c179869f34fc7c01830d3ce7ea2086bc3a07e0d35289b667d0a8bf910258926c"
+dependencies = [
+ "lzma-sys",
+]
diff --git a/Cargo.toml b/Cargo.toml
index 0d01616..aa4214b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,44 +1,5 @@
-[package]
-name = "finch"
-version = "0.3.0"
-authors = ["Roderick Bovee & One Codex <roderick@onecodex.com>"]
-description = "An implementation of min-wise independent permutation locality sensitive hashing ('MinHashing') for genomic data and command-line utility for manipulation."
-keywords = ["minhash", "bioinformatics", "sketches"]
-categories = ["command-line-utilities", "science"]
-repository = "https://github.com/onecodex/finch-rs"
-license = "MIT"
-readme = "./README.md"
-edition = "2018"
-
-[dependencies]
-bincode = "1.2.0"
-capnp = "0.9.4"
-clap = "2.33.0"
-failure = "0.1.2"
-memmap = "0.7.0"
-murmurhash3 = "0.0.5"
-ndarray = "0.13"
-needletail = "0.3.1"
-numpy = { version = "0.7.0", optional = true }
-pyo3 = { version = "0.8.2", optional = true, features=["extension-module"] }
-rayon = "1.2.0"
-serde = "1.0.101"
-serde_derive = "1.0.101"
-serde_json = "1.0.41"
-
-[dev-dependencies]
-assert_cmd = "0.10"
-predicates = "1"
-proptest = "0.9.0"
-
-[features]
-default = []
-python = ["numpy", "pyo3"]
-
-[lib]
-crate-type=["cdylib", "rlib"]
-name = "finch"
-
-[package.metadata.maturin]
-maintainer = "One Codex"
-classifier = ["Intended Audience :: Science/Research", "License :: OSI Approved :: MIT License", "Topic :: Scientific/Engineering :: Bio-Informatics"]
+[workspace]
+members = [
+    "cli",
+    "lib",
+]
diff --git a/README.md b/README.md
index 99b828f..e3a9693 100644
--- a/README.md
+++ b/README.md
@@ -172,26 +172,44 @@ There are several other implementations of the Mash algorithm which should be co
 Notes:
 - <sup>1</sup> Please see, however, [this issue tracking interoperability](https://github.com/marbl/Mash/issues/27) and note that other implementations may use a different seed value.
 
-## Python Support ##
+## Python Support ##e
+You can compile Finch into a python library with:
 
-Optional Python bindings require a nightly rust compiler, and [maturin](https://github.com/PyO3/maturin). Compile Finch into a python library with:
 ```bash
-rustup default nightly
 pip install maturin
+cd lib
 maturin install --cargo-extra-args="--features=python" --release --strip
 # or maturin develop, etc
 # to cross-compile linux wheels:
+cp ../README.md .
+# and edit the readme key of config.toml
 docker run --rm -v $(pwd):/io konstin2/maturin:master build --cargo-extra-args="--features=python" --release --strip
 ```
 
 Then, e.g. to calculate the similarities between two E. coli:
+
 ```python
-from finch import sketch_file
+from cli import sketch_file
+
 sketch_one = sketch_file('WIS_EcoB_v2.fas')
 sketch_two = sketch_file('WIS_Eco10798_DRAFTv1.fas')
 cont, jacc = sketch_one.compare(sketch_two)
 ```
 
+## Cap'n Proto
+
+There is a `finch.capnp` in `src/serialization` file and the output of the MinHash schema (https://github.com/marbl/Mash/blob/54e6d66b7720035a2605a02892cad027ef3231ef/src/mash/capnp/MinHash.capnp) 
++ the changes by @bovee in https://github.com/bovee/Mash/blob/master/src/mash/capnp/MinHash.capnp
+
+Both are generated after installing `capnp` and `cargo install capnpc` with the following command:
+
+```bash
+capnp compile -orust:finch-lib/src/serialization/ --src-prefix=finch-lib/src/serialization/ finch-lib/src/serialization/finch.capnp
+capnp compile -orust:finch-lib/src/serialization/ --src-prefix=finch-lib/src/serialization/ finch-lib/src/serialization/mash.capnp
+```
+
+and then search and replace for the `crate::` path to fix it `crate::serialization::`.
+
 ## Contributions ##
 
 Problems or suggestions for improvement can be reported through GitHub issues.
diff --git a/cli/Cargo.toml b/cli/Cargo.toml
new file mode 100644
index 0000000..1609c49
--- /dev/null
+++ b/cli/Cargo.toml
@@ -0,0 +1,24 @@
+[package]
+name = "finch"
+version = "0.4.0"
+authors = ["One Codex <vincent@onecodex.com>"]
+description = "An implementation of min-wise independent permutation locality sensitive hashing ('MinHashing') for genomic data and command-line utility for manipulation."
+keywords = ["minhash", "bioinformatics", "sketches"]
+categories = ["command-line-utilities", "science"]
+repository = "https://github.com/onecodex/finch-rs"
+license = "MIT"
+readme = "../README.md"
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+clap = "2.33.0"
+finch_lib = { version = "0.4", path = "../lib" }
+serde_json = "1"
+anyhow = "1"
+
+[dev-dependencies]
+assert_cmd = "1"
+predicates = "1"
+proptest = "0.10"
diff --git a/src/main_parsing.rs b/cli/src/cli.rs
similarity index 57%
rename from src/main_parsing.rs
rename to cli/src/cli.rs
index 979f358..4b02eea 100644
--- a/src/main_parsing.rs
+++ b/cli/src/cli.rs
@@ -1,49 +1,124 @@
-use std::mem::{discriminant, size_of};
+use anyhow::{anyhow, bail, Result};
+use clap::{crate_authors, crate_version, App, AppSettings, Arg, ArgMatches, SubCommand};
+use finch::filtering::FilterParams;
+use finch::sketch_schemes::SketchParams;
 use std::str::FromStr;
 
-use clap::{App, Arg, ArgMatches};
-use failure::{bail, format_err};
+pub fn build_cli() -> App<'static, 'static> {
+    App::new("finch")
+        .version(crate_version!())
+        .author(crate_authors!())
+        .about("Tool for working with genomic MinHash sketches")
+        .setting(AppSettings::VersionlessSubcommands)
+        .setting(AppSettings::ArgRequiredElseHelp)
+        .subcommand(info_command())
+        .subcommand(sketch_command())
+        .subcommand(dist_command())
+        .subcommand(hist_command())
+}
 
-use crate::filtering::FilterParams;
-use crate::serialization::Sketch;
-use crate::sketch_schemes::SketchParams;
-use crate::Result;
+fn info_command() -> App<'static, 'static> {
+    let mut info_command = SubCommand::with_name("info")
+        .about("Display basic statistics")
+        .arg(
+            Arg::with_name("INPUT")
+                .help("Return stats on these file(s)")
+                .multiple(true)
+                .required(true),
+        );
+    info_command = add_filter_options(info_command);
+    info_command = add_sketch_options(info_command);
+    info_command
+}
 
-pub fn get_int_arg<T: FromStr>(matches: &ArgMatches, key: &str) -> Result<T> {
-    let display_key = key.replace("_", "-");
-    Ok(matches
-        .value_of(key)
-        .ok_or_else(|| format_err!("Bad {}", display_key))?
-        .parse::<T>()
-        .map_err(|_| {
-            if size_of::<T>() == 1 {
-                format_err!("{} must be a positive integer (<256)", display_key)
-            } else {
-                format_err!("{} must be a positive integer", display_key)
-            }
-        })?)
+fn sketch_command() -> App<'static, 'static> {
+    let mut sketch_command = SubCommand::with_name("sketch")
+        .about("Create sketches from FASTA/Q file(s)")
+        .arg(
+            Arg::with_name("INPUT")
+                .help("The file(s) to sketch")
+                .multiple(true)
+                .required(true),
+        )
+        .arg(
+            Arg::with_name("binary_format")
+                .short("b")
+                .long("finch-binary-format")
+                .help("Outputs sketch to a finch-native binary format"),
+        )
+        .arg(
+            Arg::with_name("mash_binary_format")
+                .short("B")
+                .long("mash-binary-format")
+                .conflicts_with("binary_format")
+                .help("Outputs sketch in a binary format compatible with `mash`"),
+        );
+    sketch_command = add_output_options(sketch_command);
+    sketch_command = add_filter_options(sketch_command);
+    sketch_command = add_sketch_options(sketch_command);
+    sketch_command
 }
 
-pub fn get_float_arg<T: Copy + FromStr + Into<f64>>(
-    matches: &ArgMatches,
-    key: &str,
-    limit: f64,
-) -> Result<T> {
-    let display_key = key.replace("_", "-");
-    Ok(matches
-        .value_of(key)
-        .ok_or_else(|| format_err!("Bad {}", display_key))?
-        .parse::<T>()
-        .map_err(|_| format_err!("{} must be a number", display_key))
-        .and_then(|r| {
-            if 0f64 <= r.into() && r.into() <= limit {
-                return Ok(r);
-            }
-            bail!("{} must be between 0 and {}", display_key, limit)
-        })?)
+fn dist_command() -> App<'static, 'static> {
+    let mut dist_command = SubCommand::with_name("dist")
+        .about("Compute distances between sketches")
+        .arg(
+            Arg::with_name("INPUT")
+                .help("Sketchfile(s) to make comparisons for")
+                .multiple(true)
+                .required(true),
+        )
+        .arg(
+            Arg::with_name("pairwise")
+                .short("p")
+                .long("pairwise")
+                .conflicts_with("queries")
+                .help("Calculate distances between all sketches"),
+        )
+        .arg(
+            Arg::with_name("queries")
+                .short("q")
+                .long("queries")
+                .help("All distances are from these sketches (sketches must be in the first file)")
+                .multiple(true)
+                .conflicts_with("pairwise")
+                .takes_value(true),
+        )
+        .arg(
+            Arg::with_name("max_distance")
+                .short("d")
+                .long("max-dist")
+                .help("Only report distances under this threshold")
+                .default_value("1.0")
+                .takes_value(true),
+        )
+        .arg(
+            Arg::with_name("old_dist_mode")
+                .long("old-dist")
+                .help("Calculate distances using the old containment-biased Finch mode"),
+        );
+    dist_command = add_output_options(dist_command);
+    dist_command = add_filter_options(dist_command);
+    dist_command = add_sketch_options(dist_command);
+    dist_command
+}
+
+fn hist_command() -> App<'static, 'static> {
+    let mut hist_command = SubCommand::with_name("hist")
+        .about("Display histograms of kmer abundances")
+        .arg(
+            Arg::with_name("INPUT")
+                .help("Generate histograms from these file(s)")
+                .multiple(true)
+                .required(true),
+        );
+    hist_command = add_output_options(hist_command);
+    hist_command = add_filter_options(hist_command);
+    hist_command = add_sketch_options(hist_command);
+    hist_command
 }
 
-pub fn add_filter_options<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
+fn add_filter_options<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
     app.arg(Arg::with_name("no_filter")
          .long("no-filter")
          .conflicts_with("filter")
@@ -72,44 +147,7 @@ pub fn add_filter_options<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
          .default_value("1"))
 }
 
-pub fn parse_filter_options(matches: &ArgMatches, kmer_length: u8) -> Result<FilterParams> {
-    let filter_on = match (
-        matches.is_present("filter"),
-        matches.is_present("no_filter"),
-    ) {
-        (true, true) => panic!("Can't have both filtering and no filtering!"),
-        (true, false) => Some(true),
-        (false, true) => Some(false),
-        (false, false) => None,
-    };
-
-    let min_abun_filter = if matches.occurrences_of("min_abun_filter") > 0 {
-        Some(get_int_arg::<u32>(matches, "min_abun_filter")?)
-    } else {
-        None
-    };
-
-    let max_abun_filter = if matches.occurrences_of("max_abun_filter") > 0 {
-        Some(get_int_arg::<u32>(matches, "max_abun_filter")?)
-    } else {
-        None
-    };
-
-    let mut err_filter =
-        get_float_arg::<f64>(matches, "err_filter", 100f64 / f64::from(kmer_length))?;
-    err_filter *= f64::from(kmer_length) / 100f64;
-
-    let strand_filter = get_float_arg::<f64>(matches, "strand_filter", 1f64)?;
-
-    Ok(FilterParams {
-        filter_on,
-        abun_filter: (min_abun_filter, max_abun_filter),
-        err_filter,
-        strand_filter,
-    })
-}
-
-pub fn add_sketch_options<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
+fn add_sketch_options<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
     // note we're defining groups for the arguments depending on which
     // sketch_type they're used with, but clap doesn't allow us to flag
     // argument conflicts/requirements based off another argument's value
@@ -159,6 +197,83 @@ pub fn add_sketch_options<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
          .help("Allow sketching files with fewer kmers than `n_hashes` [`sketch-type=mash` only]"))
 }
 
+fn add_output_options<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
+    app.arg(
+        Arg::with_name("output_file")
+            .short("o")
+            .long("output")
+            .help("Output to this file")
+            .takes_value(true),
+    )
+    .arg(
+        Arg::with_name("std_out")
+            .short("O")
+            .long("std-out")
+            .help("Output to stdout ('print to terminal')")
+            .conflicts_with("output_file"),
+    )
+}
+
+pub fn get_int_arg<T: FromStr>(matches: &ArgMatches, key: &str) -> Result<T> {
+    let display_key = key.replace("_", "-");
+    Ok(matches
+        .value_of(key)
+        .ok_or_else(|| anyhow!("Bad {}", display_key))?
+        .parse::<T>()
+        .map_err(|_| anyhow!("{} must be a positive integer", display_key))?)
+}
+
+pub fn get_float_arg(matches: &ArgMatches, key: &str, limit: f64) -> Result<f64> {
+    let display_key = key.replace("_", "-");
+    Ok(matches
+        .value_of(key)
+        .ok_or_else(|| anyhow!("Bad {}", display_key))?
+        .parse::<f64>()
+        .map_err(|_| anyhow!("{} must be a number", display_key))
+        .and_then(|r| {
+            if 0f64 <= r && r <= limit {
+                return Ok(r);
+            }
+            bail!("{} must be between 0 and {}", display_key, limit)
+        })?)
+}
+
+pub fn parse_filter_options(matches: &ArgMatches, kmer_length: u8) -> Result<FilterParams> {
+    let filter_on = match (
+        matches.is_present("filter"),
+        matches.is_present("no_filter"),
+    ) {
+        (true, true) => panic!("Can't have both filtering and no filtering!"),
+        (true, false) => Some(true),
+        (false, true) => Some(false),
+        (false, false) => None,
+    };
+
+    let min_abun_filter = if matches.occurrences_of("min_abun_filter") > 0 {
+        Some(get_int_arg::<u32>(matches, "min_abun_filter")?)
+    } else {
+        None
+    };
+
+    let max_abun_filter = if matches.occurrences_of("max_abun_filter") > 0 {
+        Some(get_int_arg::<u32>(matches, "max_abun_filter")?)
+    } else {
+        None
+    };
+
+    let mut err_filter = get_float_arg(matches, "err_filter", 100f64 / f64::from(kmer_length))?;
+    err_filter *= f64::from(kmer_length) / 100f64;
+
+    let strand_filter = get_float_arg(matches, "strand_filter", 1f64)?;
+
+    Ok(FilterParams {
+        filter_on,
+        abun_filter: (min_abun_filter, max_abun_filter),
+        err_filter,
+        strand_filter,
+    })
+}
+
 pub fn parse_sketch_options(
     matches: &ArgMatches,
     kmer_length: u8,
@@ -220,113 +335,6 @@ pub fn parse_sketch_options(
             }
             SketchParams::AllCounts { kmer_length }
         }
-        _ => panic!("A unknown sketch type was selected"),
+        _ => bail!("A unknown sketch type was selected"),
     })
 }
-
-pub fn update_sketch_params(
-    matches: &ArgMatches,
-    sketch_params: &mut SketchParams,
-    sketch: &Sketch,
-    name: &str,
-) -> Result<()> {
-    let new_sketch_params = &sketch.sketch_params;
-
-    // check that the sketching type is the same; we may want to remove
-    // this check at some point?
-    if discriminant(sketch_params) != discriminant(new_sketch_params) {
-        bail!("Sketch types are not the same")
-    }
-
-    // if arguments weren't provided use the ones from the multisketch
-    match sketch_params {
-        SketchParams::Mash {
-            final_size,
-            kmer_length,
-            hash_seed,
-            ..
-        } => {
-            if matches.occurrences_of("n_hashes") == 0 {
-                *final_size = new_sketch_params.expected_size();
-            }
-            if matches.occurrences_of("kmer_length") == 0 {
-                *kmer_length = new_sketch_params.k();
-            } else if *kmer_length != new_sketch_params.k() {
-                bail!(
-                    "Specified kmer length {} does not match {} from sketch {}",
-                    kmer_length,
-                    new_sketch_params.k(),
-                    name
-                );
-            }
-            let (_, _, new_hash_seed, _) = new_sketch_params.hash_info();
-            if matches.occurrences_of("seed") == 0 {
-                *hash_seed = new_hash_seed;
-            } else if *hash_seed != new_hash_seed {
-                bail!(
-                    "Specified hash seed {} does not match {} from sketch {}",
-                    hash_seed,
-                    new_hash_seed,
-                    name
-                );
-            }
-            // TODO: do we need to update any of the other sketch params?
-        }
-        SketchParams::Scaled {
-            kmer_length,
-            hash_seed,
-            scale,
-            ..
-        } => {
-            // TODO: these two are identical to above so some DRY might be good?
-            if matches.occurrences_of("kmer_length") == 0 {
-                *kmer_length = new_sketch_params.k();
-            } else if *kmer_length != new_sketch_params.k() {
-                bail!(
-                    "Specified kmer length {} does not match {} from sketch {}",
-                    kmer_length,
-                    new_sketch_params.k(),
-                    name
-                );
-            }
-            let (_, _, new_hash_seed, new_scale) = new_sketch_params.hash_info();
-            if matches.occurrences_of("seed") == 0 {
-                *hash_seed = new_hash_seed;
-            } else if *hash_seed != new_hash_seed {
-                bail!(
-                    "Specified hash seed {} does not match {} from sketch {}",
-                    hash_seed,
-                    new_hash_seed,
-                    name
-                );
-            }
-
-            if let Some(new_scale_num) = new_scale {
-                if matches.occurrences_of("scale") == 0 {
-                    *scale = new_scale_num;
-                } else if (*scale - new_scale_num).abs() < std::f64::EPSILON {
-                    // TODO: maybe this should have a slightly larger delta?
-                    bail!(
-                        "Specified scale {} does not match {} from sketch {}",
-                        scale,
-                        new_scale_num,
-                        name
-                    );
-                }
-            }
-        }
-        SketchParams::AllCounts { kmer_length } => {
-            if matches.occurrences_of("kmer_length") == 0 {
-                *kmer_length = new_sketch_params.k();
-            } else if *kmer_length != new_sketch_params.k() {
-                bail!(
-                    "Specified kmer length {} does not match {} from sketch {}",
-                    kmer_length,
-                    new_sketch_params.k(),
-                    name
-                );
-            }
-        }
-    }
-    Ok(())
-}
diff --git a/cli/src/main.rs b/cli/src/main.rs
new file mode 100644
index 0000000..e25010b
--- /dev/null
+++ b/cli/src/main.rs
@@ -0,0 +1,441 @@
+use std::collections::{HashMap, HashSet};
+use std::fs::File;
+use std::io::{stdout, Write};
+
+use anyhow::{anyhow, bail, Context, Result};
+use clap::ArgMatches;
+
+use crate::cli::{get_float_arg, get_int_arg, parse_filter_options, parse_sketch_options};
+use finch::distance::distance;
+use finch::serialization::{
+    write_finch_file, write_mash_file, MultiSketch, Sketch, SketchDistance, FINCH_BIN_EXT,
+    FINCH_EXT, MASH_EXT,
+};
+use finch::sketch_schemes::SketchParams;
+use finch::statistics::{cardinality, hist};
+use finch::{format_err, open_sketch_file, sketch_files};
+use std::mem::discriminant;
+
+mod cli;
+
+fn output_to<F>(output_fn: F, output: Option<&str>, extension: &str) -> Result<()>
+where
+    F: Fn(&mut dyn Write) -> Result<()>,
+{
+    match output {
+        None => {
+            let mut out = stdout();
+            output_fn(&mut out)?;
+        }
+        Some(o) => {
+            // if the filename doesn't have the right extension
+            // add it on
+            let filename = String::from(o);
+            let out_filename = if filename.ends_with(extension) {
+                filename
+            } else {
+                filename + extension
+            };
+
+            let mut out = File::create(&out_filename)
+                .context(format!("unable to create '{}'", out_filename))?;
+            output_fn(&mut out)?;
+        }
+    };
+    Ok(())
+}
+
+fn run() -> Result<()> {
+    let matches = cli::build_cli().get_matches();
+
+    match matches.subcommand() {
+        ("sketch", Some(matches)) => {
+            let file_ext = if matches.is_present("binary_format") {
+                FINCH_BIN_EXT
+            } else if matches.is_present("mash_binary_format") {
+                MASH_EXT
+            } else {
+                FINCH_EXT
+            };
+
+            if matches.is_present("output_file") || matches.is_present("std_out") {
+                let sketches = parse_mash_files(matches)?;
+                let output = matches.value_of("output_file");
+
+                output_to(
+                    |writer| {
+                        if file_ext == FINCH_BIN_EXT {
+                            write_finch_file(writer, &sketches)?;
+                        } else if file_ext == MASH_EXT {
+                            write_mash_file(writer, &sketches)?;
+                        } else {
+                            let multisketch = MultiSketch::from_sketches(&sketches)?;
+                            serde_json::to_writer(writer, &multisketch)?;
+                        }
+                        Ok(())
+                    },
+                    output,
+                    &file_ext,
+                )?;
+            } else {
+                // special case for "sketching in place"
+                generate_sketch_files(matches, file_ext)?;
+            }
+        }
+        ("dist", Some(matches)) => {
+            let old_mode = matches.is_present("old_dist_mode");
+
+            let max_dist = get_float_arg(matches, "max_distance", 1f64)?;
+            let all_sketches = parse_mash_files(matches)?;
+
+            let mut query_sketches = Vec::new();
+            if matches.is_present("pairwise") {
+                for sketch in &all_sketches {
+                    query_sketches.push(sketch);
+                }
+            } else if matches.is_present("queries") {
+                let query_names: HashSet<String> = matches
+                    .values_of("queries")
+                    .unwrap() // we already know it's present
+                    .map(|s| s.to_string())
+                    .collect();
+
+                for sketch in &all_sketches {
+                    if query_names.contains(&sketch.name) {
+                        query_sketches.push(&sketch);
+                    }
+                }
+            } else {
+                if all_sketches.is_empty() {
+                    bail!("No sketches present!");
+                }
+                query_sketches.push(all_sketches.first().unwrap());
+            }
+
+            let distances =
+                calc_sketch_distances(&query_sketches, &all_sketches, old_mode, max_dist);
+
+            output_to(
+                |writer| {
+                    serde_json::to_writer(writer, &distances)
+                        .map_err(|_| anyhow!("Could not serialize JSON to file"))?;
+                    Ok(())
+                },
+                matches.value_of("output_file"),
+                ".json",
+            )?;
+        }
+        ("hist", Some(matches)) => {
+            let mut hist_map: HashMap<String, Vec<u64>> = HashMap::new();
+            let multisketch = parse_mash_files(matches)?;
+
+            for sketch in multisketch {
+                hist_map.insert(sketch.name.to_string(), hist(&sketch.hashes));
+            }
+
+            output_to(
+                |writer| {
+                    serde_json::to_writer(writer, &hist_map)
+                        .map_err(|_| anyhow!("Could not serialize JSON to file"))?;
+                    Ok(())
+                },
+                matches.value_of("output_file"),
+                ".json",
+            )?;
+        }
+        ("info", Some(matches)) => {
+            // TODO: this should probably output JSON
+            let multisketch = parse_mash_files(matches)?;
+
+            for sketch in multisketch {
+                print!("{}", &sketch.name);
+                println!(" (from {}bp)", sketch.seq_length);
+                let kmers = &sketch.hashes;
+                if let Ok(c) = cardinality(kmers) {
+                    println!("  Estimated # of Unique Kmers: {}", c);
+                }
+
+                let histogram = hist(kmers);
+                let mean = histogram
+                    .iter()
+                    .enumerate()
+                    .map(|(i, v)| ((i as f32 + 1f32) * *v as f32, *v as f32))
+                    .fold((0f32, 0f32), |e, s| (e.0 + s.0, e.1 + s.1));
+                println!("  Estimated Average Depth: {}x", mean.0 / mean.1);
+
+                let mut total_gc: u64 = 0;
+                for kmer in kmers {
+                    total_gc += kmer
+                        .kmer
+                        .iter()
+                        .map(|b| match *b {
+                            b'G' | b'g' | b'C' | b'c' => u64::from(kmer.count),
+                            _ => 0,
+                        })
+                        .sum::<u64>();
+                }
+                let total_bases = if kmers.is_empty() {
+                    0f32
+                } else {
+                    mean.0 * kmers[0].kmer.len() as f32
+                };
+                println!(
+                    "  Estimated % GC: {}%",
+                    100f32 * total_gc as f32 / total_bases
+                );
+            }
+        }
+        other => bail!("Unknown subcommand: {:?}", other.0),
+    };
+
+    Ok(())
+}
+
+fn main() {
+    if let Err(err) = run() {
+        eprintln!("Error: {:?}", err);
+        std::process::exit(1);
+    }
+}
+
+fn generate_sketch_files(matches: &ArgMatches, file_ext: &str) -> Result<()> {
+    let filenames: Vec<_> = matches
+        .values_of("INPUT")
+        .ok_or_else(|| format_err!("Bad INPUT"))?
+        .collect();
+
+    let kmer_length: u8 = get_int_arg(matches, "kmer_length")?;
+    let filters = parse_filter_options(matches, kmer_length)?;
+    let sketch_params = parse_sketch_options(matches, kmer_length, filters.filter_on)?;
+
+    for filename in filenames {
+        if filename.ends_with(".json")
+            || filename.ends_with(FINCH_EXT)
+            || filename.ends_with(FINCH_BIN_EXT)
+            || filename.ends_with(MASH_EXT)
+        {
+            bail!("Filename {} is not a sequence file?", filename);
+        }
+
+        let sketches = sketch_files(&[filename], &sketch_params, &filters)?;
+
+        let out_filename = filename.to_string() + file_ext;
+        let mut out = File::create(&out_filename)
+            .map_err(|_| format_err!("Could not open {}", out_filename))?;
+        if matches.is_present("binary_format") {
+            write_finch_file(&mut out, &sketches)?;
+        } else if matches.is_present("mash_binary_format") {
+            write_mash_file(&mut out, &sketches)?;
+        } else {
+            let multisketch: MultiSketch = MultiSketch::from_sketches(&sketches)?;
+            serde_json::to_writer(&mut out, &multisketch)?;
+        }
+    }
+    Ok(())
+}
+
+fn parse_mash_files(matches: &ArgMatches) -> Result<Vec<Sketch>> {
+    let filenames: Vec<_> = matches
+        .values_of("INPUT")
+        .ok_or_else(|| anyhow!("Bad INPUT"))?
+        .collect();
+
+    let mut sketch_filenames = Vec::new();
+    let mut seq_filenames = Vec::new();
+    for filename in filenames {
+        if filename.ends_with(".json")
+            || filename.ends_with(FINCH_EXT)
+            || filename.ends_with(FINCH_BIN_EXT)
+            || filename.ends_with(MASH_EXT)
+        {
+            sketch_filenames.push(filename);
+        } else {
+            seq_filenames.push(filename);
+        }
+    }
+
+    let kmer_length: u8 = get_int_arg(matches, "kmer_length")?;
+    let mut filters = parse_filter_options(matches, kmer_length)?;
+    let mut sketch_params = parse_sketch_options(matches, kmer_length, filters.filter_on)?;
+
+    let mut filename_iter = sketch_filenames.iter();
+    if let Some(first_filename) = filename_iter.next() {
+        let mut sketches = open_sketch_file(first_filename)?;
+
+        update_sketch_params(matches, &mut sketch_params, &sketches[0], first_filename)?;
+        // we also have to handle updating filter options separately because
+        // kmer_length changes how we calculate the `err_filter`
+        if matches.occurrences_of("kmer_length") == 0 {
+            filters = parse_filter_options(matches, sketch_params.k())?;
+        }
+
+        // now do the filtering for the first sketch file
+        if filters.filter_on == Some(true) {
+            for mut sketch in &mut sketches {
+                filters.filter_sketch(&mut sketch);
+            }
+        }
+
+        // and then handle the rest of the sketch files
+        for filename in filename_iter {
+            let extra_sketches = open_sketch_file(filename)?;
+            // check new sketches are compatible with original file
+            for sketch in &extra_sketches {
+                if let Some((name, v1, v2)) =
+                    sketch_params.check_compatibility(&sketch.sketch_params)
+                {
+                    bail!(
+                        "Sketch {} has {} {}, but working value is {}",
+                        sketch.name,
+                        name,
+                        v2,
+                        v1,
+                    );
+                }
+            }
+            sketches.extend(extra_sketches);
+            if filters.filter_on == Some(true) {
+                for mut sketch in &mut sketches {
+                    filters.filter_sketch(&mut sketch);
+                }
+            }
+        }
+
+        // now handle the sequences
+        let extra_sketches = sketch_files(&seq_filenames, &sketch_params, &filters)?;
+        sketches.extend(extra_sketches);
+        Ok(sketches)
+    } else {
+        // now handle the sequences
+        let sketches = sketch_files(&seq_filenames, &sketch_params, &filters)?;
+        Ok(sketches)
+    }
+}
+
+fn calc_sketch_distances(
+    query_sketches: &[&Sketch],
+    ref_sketches: &[Sketch],
+    old_mode: bool,
+    max_distance: f64,
+) -> Vec<SketchDistance> {
+    let mut distances = Vec::new();
+    for ref_sketch in ref_sketches {
+        for query_sketch in query_sketches {
+            if query_sketch == &ref_sketch {
+                continue;
+            }
+            let distance = distance(&query_sketch, &ref_sketch, old_mode).unwrap();
+            if distance.mash_distance <= max_distance {
+                distances.push(distance);
+            }
+        }
+    }
+    distances
+}
+
+pub fn update_sketch_params(
+    matches: &ArgMatches,
+    sketch_params: &mut SketchParams,
+    sketch: &Sketch,
+    name: &str,
+) -> Result<()> {
+    let new_sketch_params = &sketch.sketch_params;
+
+    // check that the sketching type is the same; we may want to remove
+    // this check at some point?
+    if discriminant(sketch_params) != discriminant(new_sketch_params) {
+        bail!("Sketch types are not the same")
+    }
+
+    // if arguments weren't provided use the ones from the multisketch
+    match sketch_params {
+        SketchParams::Mash {
+            final_size,
+            kmer_length,
+            hash_seed,
+            ..
+        } => {
+            if matches.occurrences_of("n_hashes") == 0 {
+                *final_size = new_sketch_params.expected_size();
+            }
+            if matches.occurrences_of("kmer_length") == 0 {
+                *kmer_length = new_sketch_params.k();
+            } else if *kmer_length != new_sketch_params.k() {
+                bail!(
+                    "Specified kmer length {} does not match {} from sketch {}",
+                    kmer_length,
+                    new_sketch_params.k(),
+                    name
+                );
+            }
+            let (_, _, new_hash_seed, _) = new_sketch_params.hash_info();
+            if matches.occurrences_of("seed") == 0 {
+                *hash_seed = new_hash_seed;
+            } else if *hash_seed != new_hash_seed {
+                bail!(
+                    "Specified hash seed {} does not match {} from sketch {}",
+                    hash_seed,
+                    new_hash_seed,
+                    name
+                );
+            }
+            // TODO: do we need to update any of the other sketch params?
+        }
+        SketchParams::Scaled {
+            kmer_length,
+            hash_seed,
+            scale,
+            ..
+        } => {
+            // TODO: these two are identical to above so some DRY might be good?
+            if matches.occurrences_of("kmer_length") == 0 {
+                *kmer_length = new_sketch_params.k();
+            } else if *kmer_length != new_sketch_params.k() {
+                bail!(
+                    "Specified kmer length {} does not match {} from sketch {}",
+                    kmer_length,
+                    new_sketch_params.k(),
+                    name
+                );
+            }
+            let (_, _, new_hash_seed, new_scale) = new_sketch_params.hash_info();
+            if matches.occurrences_of("seed") == 0 {
+                *hash_seed = new_hash_seed;
+            } else if *hash_seed != new_hash_seed {
+                bail!(
+                    "Specified hash seed {} does not match {} from sketch {}",
+                    hash_seed,
+                    new_hash_seed,
+                    name
+                );
+            }
+
+            if let Some(new_scale_num) = new_scale {
+                if matches.occurrences_of("scale") == 0 {
+                    *scale = new_scale_num;
+                } else if (*scale - new_scale_num).abs() < std::f64::EPSILON {
+                    // TODO: maybe this should have a slightly larger delta?
+                    bail!(
+                        "Specified scale {} does not match {} from sketch {}",
+                        scale,
+                        new_scale_num,
+                        name
+                    );
+                }
+            }
+        }
+        SketchParams::AllCounts { kmer_length } => {
+            if matches.occurrences_of("kmer_length") == 0 {
+                *kmer_length = new_sketch_params.k();
+            } else if *kmer_length != new_sketch_params.k() {
+                bail!(
+                    "Specified kmer length {} does not match {} from sketch {}",
+                    kmer_length,
+                    new_sketch_params.k(),
+                    name
+                );
+            }
+        }
+    }
+    Ok(())
+}
diff --git a/lib/Cargo.toml b/lib/Cargo.toml
new file mode 100644
index 0000000..3e9fa49
--- /dev/null
+++ b/lib/Cargo.toml
@@ -0,0 +1,41 @@
+[package]
+name = "finch_lib"
+version = "0.4.0"
+authors = ["One Codex <vincent@onecodex.com>"]
+description = "An implementation of min-wise independent permutation locality sensitive hashing ('MinHashing') for genomic data and command-line utility for manipulation."
+keywords = ["minhash", "bioinformatics", "sketches"]
+categories = ["science"]
+repository = "https://github.com/onecodex/finch-rs"
+license = "MIT"
+readme = "../README.md"
+edition = "2018"
+
+[dependencies]
+bincode = "1.2.0"
+capnp = "0.14"
+memmap = "0.7.0"
+murmurhash3 = "0.0.5"
+ndarray = "0.14"
+needletail = "0.4"
+numpy = { version = "0.13", optional = true }
+pyo3 = { version = "0.13", optional = true }
+rayon = "1.2.0"
+serde = { version = "1.0", features = ["derive"] }
+serde_json = "1"
+thiserror = "1"
+
+[dev-dependencies]
+predicates = "1"
+proptest = "0.10"
+
+[features]
+default = []
+python = ["numpy", "pyo3", "pyo3/extension-module"]
+
+[lib]
+crate-type=["cdylib", "rlib"]
+name = "finch"
+
+[package.metadata.maturin]
+maintainer = "One Codex"
+classifier = ["Intended Audience :: Science/Research", "License :: OSI Approved :: MIT License", "Topic :: Scientific/Engineering :: Bio-Informatics"]
diff --git a/src/distance.rs b/lib/src/distance.rs
similarity index 100%
rename from src/distance.rs
rename to lib/src/distance.rs
diff --git a/lib/src/errors.rs b/lib/src/errors.rs
new file mode 100644
index 0000000..ce8cd6d
--- /dev/null
+++ b/lib/src/errors.rs
@@ -0,0 +1,44 @@
+use std::result::Result as StdResult;
+
+use thiserror::Error;
+
+#[derive(Error, Debug)]
+pub enum FinchError {
+    #[error("failed to load/read/write file: {0:?}")]
+    Io(#[from] std::io::Error),
+    #[error("capnproto error: {0:?}")]
+    Capnproto(#[from] capnp::Error),
+    #[error("failed to parse the fasta/fastq file: {0}")]
+    Needletail(#[from] needletail::errors::ParseError),
+    #[error("failed to parse as integer")]
+    IntError(#[from] core::num::ParseIntError),
+    #[error("failed to parse as float")]
+    FloatError(#[from] core::num::ParseFloatError),
+    #[error("enum value not found in schema")]
+    SchemaError(#[from] capnp::NotInSchema),
+    #[error("json error: {0:?}")]
+    Json(#[from] serde_json::Error),
+    #[error("Finch error: {0}")]
+    Message(String),
+}
+
+pub type FinchResult<T> = StdResult<T, FinchError>;
+
+// TODO: remove the macro magic if possible when done with moving off failure
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! bail {
+    ($e:expr) => {
+        return Err($crate::errors::FinchError::Message($e.to_owned()));
+    };
+    ($fmt:expr, $($arg:tt)*) => {
+        return Err($crate::errors::FinchError::Message(format!($fmt, $($arg)*)));
+    };
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! format_err {
+    ($($arg:tt)*) => { $crate::errors::FinchError::Message(format!($($arg)*)) }
+}
diff --git a/src/filtering.rs b/lib/src/filtering.rs
similarity index 99%
rename from src/filtering.rs
rename to lib/src/filtering.rs
index c23af3f..7301d4f 100644
--- a/src/filtering.rs
+++ b/lib/src/filtering.rs
@@ -1,10 +1,10 @@
 use std::cmp;
 use std::collections::HashMap;
 
+use crate::errors::FinchResult;
 use crate::serialization::Sketch;
 use crate::sketch_schemes::KmerCount;
 use crate::statistics::hist;
-use crate::Result;
 
 /// Used to pass around filter options for sketching
 #[derive(Clone, Debug, PartialEq)]
@@ -115,7 +115,7 @@ impl FilterParams {
         filter_stats
     }
 
-    pub fn from_serialized(filters: &HashMap<String, String>) -> Result<Self> {
+    pub fn from_serialized(filters: &HashMap<String, String>) -> FinchResult<Self> {
         let low_abun = if let Some(min_copies) = filters.get("minCopies") {
             Some(min_copies.parse()?)
         } else {
diff --git a/src/lib.rs b/lib/src/lib.rs
similarity index 58%
rename from src/lib.rs
rename to lib/src/lib.rs
index 6cdb544..8416dba 100644
--- a/src/lib.rs
+++ b/lib/src/lib.rs
@@ -1,17 +1,10 @@
-#![cfg_attr(feature = "python", feature(specialization))]
-
-extern crate capnp;
-#[macro_use]
-extern crate serde_derive;
-
 use std::fs::File;
 use std::io::{stdin, BufReader, Read};
 use std::path::Path;
-use std::result::Result as StdResult;
 
-use failure::{format_err, Error};
 use memmap::MmapOptions;
-use needletail::formats::parse_sequence_reader;
+use needletail::parse_fastx_reader;
+use needletail::parser::Format;
 use rayon::prelude::*;
 
 use crate::filtering::FilterParams;
@@ -25,26 +18,26 @@ pub mod filtering;
 pub mod sketch_schemes;
 // it would be nice if there was a `pub(in main)` or something for
 // main_parsing so we don't import it for `lib` itself
-pub mod main_parsing;
+pub mod errors;
 #[cfg(feature = "python")]
 pub mod python;
 pub mod serialization;
 pub mod statistics;
 
-pub type Result<T> = StdResult<T, Error>;
+use crate::errors::FinchResult;
 
 pub fn sketch_files(
     filenames: &[&str],
     sketch_params: &SketchParams,
     filters: &FilterParams,
-) -> Result<Vec<Sketch>> {
-    let sketches: Result<Vec<Sketch>> = filenames
+) -> FinchResult<Vec<Sketch>> {
+    let sketches: FinchResult<Vec<Sketch>> = filenames
         .par_iter()
         .map(|filename| {
             // open the file with a special case to handle stdin
-            let sin = stdin();
-            let reader: Box<dyn Read> = if filename == &"-" {
-                Box::new(sin.lock())
+            let reader: Box<dyn Read + Send> = if filename == &"-" {
+                // We're not locking it so technically not thread safe
+                Box::new(stdin())
             } else {
                 Box::new(File::open(&Path::new(filename))?)
             };
@@ -56,30 +49,31 @@ pub fn sketch_files(
 }
 
 pub fn sketch_stream<'a>(
-    reader: Box<dyn Read + 'a>,
+    reader: Box<dyn Read + Send + 'a>,
     name: &str,
     sketch_params: &SketchParams,
     filters: &FilterParams,
-) -> Result<Sketch> {
+) -> FinchResult<Sketch> {
     let mut filter_params = filters.clone();
     let mut sketcher = sketch_params.create_sketcher();
-    parse_sequence_reader(
-        reader,
-        |seq_type| {
-            // disable filtering for FASTA files unless it was explicitly specified
-            if filter_params.filter_on.is_none() {
-                filter_params.filter_on = match seq_type {
-                    "FASTA" => Some(false),
-                    "FASTQ" => Some(true),
-                    _ => panic!("Unknown sequence type"),
-                };
-            }
-        },
-        |seq| {
-            sketcher.process(seq);
-        },
-    )
-    .map_err(|e| format_err!("{}", e.to_string()))?;
+    // TODO: remove expects after removing failure
+    let mut fastx_reader = parse_fastx_reader(reader).expect("valid file TODO");
+    let mut seq_type = None;
+    while let Some(record) = fastx_reader.next() {
+        let seqrec = record.expect("invalid record");
+        if seq_type.is_none() {
+            seq_type = Some(seqrec.format());
+        }
+        sketcher.process(seqrec);
+    }
+
+    // disable filtering for FASTA files unless it was explicitly specified
+    if filter_params.filter_on.is_none() {
+        filter_params.filter_on = match seq_type.expect("Should have got a type") {
+            Format::Fasta => Some(false),
+            Format::Fastq => Some(true),
+        };
+    }
 
     let (seq_length, num_valid_kmers) = sketcher.total_bases_and_kmers();
     let hashes = sketcher.to_vec();
@@ -99,8 +93,13 @@ pub fn sketch_stream<'a>(
     })
 }
 
-pub fn open_sketch_file(filename: &str) -> Result<Vec<Sketch>> {
-    let file = File::open(filename).map_err(|_| format_err!("Error opening {}", &filename))?;
+pub fn open_sketch_file<P: AsRef<Path>>(path: P) -> FinchResult<Vec<Sketch>> {
+    let p = path.as_ref();
+    let filename = p
+        .file_name()
+        .ok_or_else(|| format_err!("Path does not have a filename: {:?}", p))?
+        .to_string_lossy();
+    let file = File::open(p).map_err(|_| format_err!("Error opening {:?}", p))?;
     if filename.ends_with(MASH_EXT) {
         let mut buf_reader = BufReader::new(file);
         read_mash_file(&mut buf_reader)
@@ -109,8 +108,8 @@ pub fn open_sketch_file(filename: &str) -> Result<Vec<Sketch>> {
         read_finch_file(&mut buf_reader)
     } else if filename.ends_with(FINCH_EXT) || filename.ends_with(".json") {
         let mapped = unsafe { MmapOptions::new().map(&file)? };
-        let multisketch: MultiSketch = serde_json::from_slice(&mapped)
-            .map_err(|_| format_err!("Error parsing {}", &filename))?;
+        let multisketch: MultiSketch =
+            serde_json::from_slice(&mapped).map_err(|_| format_err!("Error parsing {:?}", &p))?;
         multisketch.to_sketches()
     } else {
         Err(format_err!("File suffix is not *.bsk, *.msh, or *.sk"))
diff --git a/src/python.rs b/lib/src/python.rs
similarity index 92%
rename from src/python.rs
rename to lib/src/python.rs
index 85243fc..77a38d1 100644
--- a/src/python.rs
+++ b/lib/src/python.rs
@@ -1,28 +1,28 @@
 use std::collections::{HashSet, VecDeque};
-use std::fmt::Display;
 use std::fs::File;
 
-use failure::bail;
 use numpy::{PyArray, PyArray1, PyArray2};
 use pyo3::class::*;
-use pyo3::exceptions::{IndexError, KeyError};
+use pyo3::exceptions::{PyIndexError, PyKeyError};
 use pyo3::prelude::*;
 use pyo3::types::{PyAny, PyBytes, PyDict, PyList, PyTuple, PyType};
 use pyo3::{create_exception, wrap_pyfunction};
 
 use crate::distance::{distance, minmer_matrix};
+use crate::errors::FinchResult;
 use crate::filtering::FilterParams;
-use crate::serialization::{write_finch_file, Sketch as SType};
+use crate::serialization::{write_finch_file, Sketch as SketchRs};
 use crate::sketch_schemes::{KmerCount, SketchParams};
-use crate::{open_sketch_file, sketch_files as rs_sketch_files, Result as FinchResult};
+use crate::{bail, open_sketch_file, sketch_files as rs_sketch_files};
 
-create_exception!(finch, FinchError, pyo3::exceptions::Exception);
-
-fn to_pyerr(e: impl Display) -> PyErr {
-    PyErr::new::<FinchError, _>(format!("{}", e))
+create_exception!(finch, FinchError, pyo3::exceptions::PyException);
+macro_rules! py_try {
+    ($call:expr) => {
+        $call.map_err(|e| PyErr::new::<FinchError, _>(format!("{}", e)))?
+    };
 }
 
-fn merge_sketches(sketch: &mut SType, other: &SType, size: Option<usize>) -> FinchResult<()> {
+fn merge_sketches(sketch: &mut SketchRs, other: &SketchRs, size: Option<usize>) -> FinchResult<()> {
     // update my parameters from the remote's
     sketch.seq_length += other.seq_length;
     sketch.num_valid_kmers += other.num_valid_kmers;
@@ -100,35 +100,34 @@ fn merge_sketches(sketch: &mut SType, other: &SType, size: Option<usize>) -> Fin
     Ok(())
 }
 
-#[pyclass]
 /// A Multisketch is a collection of Sketchs with information about their
 /// generation parameters (to make sure they're consistant for distance
 /// calculation).
+#[pyclass]
 pub struct Multisketch {
-    pub sketches: Vec<SType>,
+    pub sketches: Vec<SketchRs>,
 }
 
 #[pymethods]
 impl Multisketch {
-    #[classmethod]
     /// open(filename: str)
     ///
     /// Takes a file path to a `.sk`, `.bsk` or a `.mash` file and returns the
     /// Multisketch contained within that file.
+    #[classmethod]
     pub fn open(_cls: &PyType, filename: &str) -> PyResult<Multisketch> {
         Ok(Multisketch {
-            sketches: open_sketch_file(filename).map_err(to_pyerr)?,
+            sketches: py_try!(open_sketch_file(filename)),
         })
     }
 
-    #[classmethod]
     /// from_sketches(sketches: List[Sketch])
     ///
     /// Create a Multisketch from a list of sketches. Useful for, e.g.
     /// workflows where a bunch of individual sketches are processed and then
     /// need to be outputed to one sketch file.
-    pub fn from_sketches(_cls: &PyType, sketches: &PyList) -> PyResult<Multisketch> {
-        let sketches: Vec<&Sketch> = sketches.extract()?;
+    #[classmethod]
+    pub fn from_sketches(_cls: &PyType, sketches: Vec<PyRef<Sketch>>) -> PyResult<Multisketch> {
         let sketches = sketches.iter().map(|s| s.s.clone()).collect();
         Ok(Multisketch { sketches })
     }
@@ -141,7 +140,7 @@ impl Multisketch {
         // TODO: support other file formats
         let mut out = File::create(&filename)
             .map_err(|_| PyErr::new::<FinchError, _>(format!("Could not create {}", filename)))?;
-        write_finch_file(&mut out, &self.sketches).map_err(to_pyerr)?;
+        py_try!(write_finch_file(&mut out, &self.sketches));
         Ok(())
     }
 
@@ -166,7 +165,7 @@ impl Multisketch {
         // containment as our metric
         let mut max_containment: f64 = 0.;
         for (ix, sketch) in self.sketches.iter().enumerate() {
-            let dist = distance(&query.s, &sketch, false).map_err(to_pyerr)?;
+            let dist = py_try!(distance(&query.s, &sketch, false));
             if dist.containment > max_containment {
                 max_containment = dist.containment;
                 best_sketch = ix;
@@ -184,7 +183,7 @@ impl Multisketch {
         let mut filtered_sketches = Vec::new();
         for sketch in &self.sketches {
             // TODO: use best_distance here and elsewhere?
-            let dist = distance(&query.s, &sketch, false).map_err(to_pyerr)?;
+            let dist = py_try!(distance(&query.s, &sketch, false));
             if dist.containment >= threshold {
                 filtered_sketches.push(sketch.clone());
             }
@@ -259,7 +258,7 @@ impl PyObjectProtocol for Multisketch {
 }
 
 #[inline]
-fn _get_sketch_index(sketches: &[SType], key: &PyAny) -> PyResult<usize> {
+fn _get_sketch_index(sketches: &[SketchRs], key: &PyAny) -> PyResult<usize> {
     if let Ok(int_key) = key.extract::<isize>() {
         let l = sketches.len() as isize;
         if -l <= int_key && int_key < 0 {
@@ -267,7 +266,7 @@ fn _get_sketch_index(sketches: &[SType], key: &PyAny) -> PyResult<usize> {
         } else if 0 <= int_key && int_key < l {
             Ok(int_key as usize)
         } else {
-            Err(PyErr::new::<IndexError, _>("index out of range"))
+            Err(PyErr::new::<PyIndexError, _>("index out of range"))
         }
     } else if let Ok(str_key) = key.extract::<&str>() {
         // TODO: we should maybe build an internal HashMap cache for this?
@@ -277,7 +276,7 @@ fn _get_sketch_index(sketches: &[SType], key: &PyAny) -> PyResult<usize> {
         if let Some(idx) = remove_idx {
             Ok(idx)
         } else {
-            Err(PyErr::new::<KeyError, _>(str_key.to_string()))
+            Err(PyErr::new::<PyKeyError, _>(str_key.to_string()))
         }
     } else {
         Err(PyErr::new::<FinchError, _>(
@@ -323,13 +322,13 @@ impl PySequenceProtocol for Multisketch {
 /// sequencing file.
 #[pyclass]
 pub struct Sketch {
-    pub s: SType,
+    pub s: SketchRs,
 }
 
 #[pymethods]
 impl Sketch {
     #[new]
-    fn __new__(obj: &PyRawObject, name: &str) -> PyResult<()> {
+    fn new(name: &str) -> Self {
         // TODO: take a hashes parameter: Vec<(usize, &[u8], u16, u16)>,
         // and a sketch_params?
         let sketch_params = SketchParams::Mash {
@@ -339,7 +338,7 @@ impl Sketch {
             kmer_length: 21,
             hash_seed: 0,
         };
-        let s = SType {
+        let s = SketchRs {
             name: name.to_string(),
             seq_length: 0,
             num_valid_kmers: 0,
@@ -348,8 +347,7 @@ impl Sketch {
             sketch_params,
             filter_params: FilterParams::default(),
         };
-        obj.init(Sketch { s });
-        Ok(())
+        Sketch { s }
     }
 
     #[getter]
@@ -477,7 +475,7 @@ impl Sketch {
     /// that have 'high' hashes because they're under `size`, this will
     /// potentially remove those hashes if the new sketch is large enough).
     pub fn merge(&mut self, sketch: &Sketch, size: Option<usize>) -> PyResult<()> {
-        Ok(merge_sketches(&mut self.s, &sketch.s, size).map_err(to_pyerr)?)
+        Ok(py_try!(merge_sketches(&mut self.s, &sketch.s, size)))
     }
 
     /// compare(self, sketch: Sketch, old_mode: bool = False) -> (float, float)
@@ -488,7 +486,7 @@ impl Sketch {
     /// older did; for most uses you probably don't want this.
     #[args(old_mode = false)]
     pub fn compare(&self, sketch: &Sketch, old_mode: bool) -> PyResult<(f64, f64)> {
-        let dist = distance(&sketch.s, &self.s, old_mode).map_err(to_pyerr)?;
+        let dist = py_try!(distance(&sketch.s, &self.s, old_mode));
 
         Ok((dist.containment, dist.jaccard))
     }
@@ -575,7 +573,7 @@ impl Sketch {
     /// this sketch's count array (`self.counts`).
     #[args(args = "*")]
     pub fn compare_matrix(&self, args: &PyTuple) -> PyResult<Py<PyArray2<i32>>> {
-        let sketches: Vec<&Sketch> = args.extract()?;
+        let sketches: Vec<PyRef<Sketch>> = args.extract()?;
         let sketch_kmers: Vec<&[KmerCount]> = sketches.iter().map(|s| &s.s.hashes[..]).collect();
         let result = minmer_matrix(&self.s.hashes, &sketch_kmers);
 
@@ -595,13 +593,14 @@ impl Sketch {
 
     #[setter]
     pub fn set_counts(&mut self, value: &PyArray1<i32>) -> PyResult<()> {
-        if value.len() != self.s.hashes.len() {
+        let val: Vec<i32> = value.extract()?;
+        if val.len() != self.s.hashes.len() {
             return Err(PyErr::new::<FinchError, _>(
                 "counts must be same length as sketch",
             ));
         }
         let mut new_hashes = Vec::new();
-        for (s, v) in self.s.hashes.iter_mut().zip(value.as_array().iter()) {
+        for (s, v) in self.s.hashes.iter_mut().zip(val.iter()) {
             if *v < 0 {
                 return Err(PyErr::new::<FinchError, _>(format!(
                     "Negative count {} not supported",
@@ -639,8 +638,8 @@ impl PyMappingProtocol for Sketch {
     }
 }
 
-impl From<SType> for Sketch {
-    fn from(s: SType) -> Self {
+impl From<SketchRs> for Sketch {
+    fn from(s: SketchRs) -> Self {
         Sketch { s }
     }
 }
@@ -688,18 +687,19 @@ pub fn sketch_file(
         err_filter: 1.,
         strand_filter: 0.1,
     };
-    let sketches = rs_sketch_files(&[filename], &sketch_params, &filters);
+    let mut sketches = py_try!(rs_sketch_files(&[filename], &sketch_params, &filters));
     Ok(Sketch {
-        s: sketches.map_err(to_pyerr)?.pop().unwrap(),
+        s: sketches.pop().unwrap(),
     })
 }
 
 /// Finch is a MinHash sketch processing library.
 #[pymodule]
-fn finch(_py: Python, m: &PyModule) -> PyResult<()> {
+fn finch(py: Python, m: &PyModule) -> PyResult<()> {
     m.add_class::<Multisketch>()?;
     m.add_class::<Sketch>()?;
     m.add_wrapped(wrap_pyfunction!(sketch_file))?;
+    m.add("FinchError", py.get_type::<FinchError>())?;
 
     Ok(())
 }
diff --git a/src/serialization/finch.capnp b/lib/src/serialization/finch.capnp
similarity index 100%
rename from src/serialization/finch.capnp
rename to lib/src/serialization/finch.capnp
diff --git a/lib/src/serialization/finch_capnp.rs b/lib/src/serialization/finch_capnp.rs
new file mode 100644
index 0000000..0616c3c
--- /dev/null
+++ b/lib/src/serialization/finch_capnp.rs
@@ -0,0 +1,982 @@
+// @generated by the capnpc-rust plugin to the Cap'n Proto schema compiler.
+// DO NOT EDIT.
+// source: finch.capnp
+
+
+#[repr(u16)]
+#[derive(Clone, Copy, PartialEq)]
+pub enum SketchMethod {
+  MurmurHash3 = 0,
+  MurmurHash3Scaled = 1,
+  None = 2,
+}
+impl ::capnp::traits::FromU16 for SketchMethod {
+  #[inline]
+  fn from_u16(value: u16) -> ::core::result::Result<SketchMethod, ::capnp::NotInSchema> {
+    match value {
+      0 => ::core::result::Result::Ok(SketchMethod::MurmurHash3),
+      1 => ::core::result::Result::Ok(SketchMethod::MurmurHash3Scaled),
+      2 => ::core::result::Result::Ok(SketchMethod::None),
+      n => ::core::result::Result::Err(::capnp::NotInSchema(n)),
+    }
+  }
+}
+impl ::capnp::traits::ToU16 for SketchMethod {
+  #[inline]
+  fn to_u16(self) -> u16 { self as u16 }
+}
+impl ::capnp::traits::HasTypeId for SketchMethod {
+  #[inline]
+  fn type_id() -> u64 { 0xf922_f4db_1e0b_2eaau64 }
+}
+
+pub mod filter_params {
+  #[derive(Copy, Clone)]
+  pub struct Owned(());
+  impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
+  impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
+  impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
+
+  #[derive(Clone, Copy)]
+  pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
+
+  impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,>  {
+    #[inline]
+    fn type_id() -> u64 { _private::TYPE_ID }
+  }
+  impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,>  {
+    fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
+      Reader { reader,  }
+    }
+  }
+
+  impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,>  {
+    fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
+      ::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
+    }
+  }
+
+  impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,>  {
+    fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
+      self.reader
+    }
+  }
+
+  impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,>  {
+    fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
+      self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
+    }
+  }
+
+  impl <'a,> Reader<'a,>  {
+    pub fn reborrow(&self) -> Reader<'_,> {
+      Reader { .. *self }
+    }
+
+    pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
+      self.reader.total_size()
+    }
+    #[inline]
+    pub fn get_filtered(self) -> bool {
+      self.reader.get_bool_field(0)
+    }
+    #[inline]
+    pub fn get_low_abun_filter(self) -> u32 {
+      self.reader.get_data_field::<u32>(1)
+    }
+    #[inline]
+    pub fn get_high_abun_filter(self) -> u32 {
+      self.reader.get_data_field::<u32>(2)
+    }
+    #[inline]
+    pub fn get_err_filter(self) -> f64 {
+      self.reader.get_data_field::<f64>(2)
+    }
+    #[inline]
+    pub fn get_strand_filter(self) -> f64 {
+      self.reader.get_data_field::<f64>(3)
+    }
+  }
+
+  pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
+  impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,>  {
+    #[inline]
+    fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
+  }
+  impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,>  {
+    #[inline]
+    fn type_id() -> u64 { _private::TYPE_ID }
+  }
+  impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,>  {
+    fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
+      Builder { builder,  }
+    }
+  }
+
+  impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,>  {
+    fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
+      self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
+    }
+  }
+
+  impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,>  {
+    fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
+      ::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
+    }
+    fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
+      ::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
+    }
+  }
+
+  impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,>  {
+    fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
+  }
+
+  impl <'a,> Builder<'a,>  {
+    pub fn into_reader(self) -> Reader<'a,> {
+      ::capnp::traits::FromStructReader::new(self.builder.into_reader())
+    }
+    pub fn reborrow(&mut self) -> Builder<'_,> {
+      Builder { .. *self }
+    }
+    pub fn reborrow_as_reader(&self) -> Reader<'_,> {
+      ::capnp::traits::FromStructReader::new(self.builder.into_reader())
+    }
+
+    pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
+      self.builder.into_reader().total_size()
+    }
+    #[inline]
+    pub fn get_filtered(self) -> bool {
+      self.builder.get_bool_field(0)
+    }
+    #[inline]
+    pub fn set_filtered(&mut self, value: bool)  {
+      self.builder.set_bool_field(0, value);
+    }
+    #[inline]
+    pub fn get_low_abun_filter(self) -> u32 {
+      self.builder.get_data_field::<u32>(1)
+    }
+    #[inline]
+    pub fn set_low_abun_filter(&mut self, value: u32)  {
+      self.builder.set_data_field::<u32>(1, value);
+    }
+    #[inline]
+    pub fn get_high_abun_filter(self) -> u32 {
+      self.builder.get_data_field::<u32>(2)
+    }
+    #[inline]
+    pub fn set_high_abun_filter(&mut self, value: u32)  {
+      self.builder.set_data_field::<u32>(2, value);
+    }
+    #[inline]
+    pub fn get_err_filter(self) -> f64 {
+      self.builder.get_data_field::<f64>(2)
+    }
+    #[inline]
+    pub fn set_err_filter(&mut self, value: f64)  {
+      self.builder.set_data_field::<f64>(2, value);
+    }
+    #[inline]
+    pub fn get_strand_filter(self) -> f64 {
+      self.builder.get_data_field::<f64>(3)
+    }
+    #[inline]
+    pub fn set_strand_filter(&mut self, value: f64)  {
+      self.builder.set_data_field::<f64>(3, value);
+    }
+  }
+
+  pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
+  impl ::capnp::capability::FromTypelessPipeline for Pipeline {
+    fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
+      Pipeline { _typeless: typeless,  }
+    }
+  }
+  impl Pipeline  {
+  }
+  mod _private {
+    use capnp::private::layout;
+    pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 4, pointers: 0 };
+    pub const TYPE_ID: u64 = 0x8dff_64f8_81c9_51eb;
+  }
+}
+
+pub mod sketch_params {
+  #[derive(Copy, Clone)]
+  pub struct Owned(());
+  impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
+  impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
+  impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
+
+  #[derive(Clone, Copy)]
+  pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
+
+  impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,>  {
+    #[inline]
+    fn type_id() -> u64 { _private::TYPE_ID }
+  }
+  impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,>  {
+    fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
+      Reader { reader,  }
+    }
+  }
+
+  impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,>  {
+    fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
+      ::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
+    }
+  }
+
+  impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,>  {
+    fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
+      self.reader
+    }
+  }
+
+  impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,>  {
+    fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
+      self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
+    }
+  }
+
+  impl <'a,> Reader<'a,>  {
+    pub fn reborrow(&self) -> Reader<'_,> {
+      Reader { .. *self }
+    }
+
+    pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
+      self.reader.total_size()
+    }
+    #[inline]
+    pub fn get_sketch_method(self) -> ::core::result::Result<crate::serialization::finch_capnp::SketchMethod,::capnp::NotInSchema> {
+      ::capnp::traits::FromU16::from_u16(self.reader.get_data_field::<u16>(0))
+    }
+    #[inline]
+    pub fn get_kmer_length(self) -> u8 {
+      self.reader.get_data_field::<u8>(2)
+    }
+    #[inline]
+    pub fn get_kmers_to_sketch(self) -> u64 {
+      self.reader.get_data_field::<u64>(1)
+    }
+    #[inline]
+    pub fn get_hash_seed(self) -> u64 {
+      self.reader.get_data_field::<u64>(2)
+    }
+    #[inline]
+    pub fn get_final_size(self) -> u64 {
+      self.reader.get_data_field::<u64>(3)
+    }
+    #[inline]
+    pub fn get_no_strict(self) -> bool {
+      self.reader.get_bool_field(24)
+    }
+    #[inline]
+    pub fn get_scale(self) -> f64 {
+      self.reader.get_data_field::<f64>(4)
+    }
+  }
+
+  pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
+  impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,>  {
+    #[inline]
+    fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
+  }
+  impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,>  {
+    #[inline]
+    fn type_id() -> u64 { _private::TYPE_ID }
+  }
+  impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,>  {
+    fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
+      Builder { builder,  }
+    }
+  }
+
+  impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,>  {
+    fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
+      self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
+    }
+  }
+
+  impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,>  {
+    fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
+      ::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
+    }
+    fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
+      ::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
+    }
+  }
+
+  impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,>  {
+    fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
+  }
+
+  impl <'a,> Builder<'a,>  {
+    pub fn into_reader(self) -> Reader<'a,> {
+      ::capnp::traits::FromStructReader::new(self.builder.into_reader())
+    }
+    pub fn reborrow(&mut self) -> Builder<'_,> {
+      Builder { .. *self }
+    }
+    pub fn reborrow_as_reader(&self) -> Reader<'_,> {
+      ::capnp::traits::FromStructReader::new(self.builder.into_reader())
+    }
+
+    pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
+      self.builder.into_reader().total_size()
+    }
+    #[inline]
+    pub fn get_sketch_method(self) -> ::core::result::Result<crate::serialization::finch_capnp::SketchMethod,::capnp::NotInSchema> {
+      ::capnp::traits::FromU16::from_u16(self.builder.get_data_field::<u16>(0))
+    }
+    #[inline]
+    pub fn set_sketch_method(&mut self, value: crate::serialization::finch_capnp::SketchMethod)  {
+      self.builder.set_data_field::<u16>(0, value as u16)
+    }
+    #[inline]
+    pub fn get_kmer_length(self) -> u8 {
+      self.builder.get_data_field::<u8>(2)
+    }
+    #[inline]
+    pub fn set_kmer_length(&mut self, value: u8)  {
+      self.builder.set_data_field::<u8>(2, value);
+    }
+    #[inline]
+    pub fn get_kmers_to_sketch(self) -> u64 {
+      self.builder.get_data_field::<u64>(1)
+    }
+    #[inline]
+    pub fn set_kmers_to_sketch(&mut self, value: u64)  {
+      self.builder.set_data_field::<u64>(1, value);
+    }
+    #[inline]
+    pub fn get_hash_seed(self) -> u64 {
+      self.builder.get_data_field::<u64>(2)
+    }
+    #[inline]
+    pub fn set_hash_seed(&mut self, value: u64)  {
+      self.builder.set_data_field::<u64>(2, value);
+    }
+    #[inline]
+    pub fn get_final_size(self) -> u64 {
+      self.builder.get_data_field::<u64>(3)
+    }
+    #[inline]
+    pub fn set_final_size(&mut self, value: u64)  {
+      self.builder.set_data_field::<u64>(3, value);
+    }
+    #[inline]
+    pub fn get_no_strict(self) -> bool {
+      self.builder.get_bool_field(24)
+    }
+    #[inline]
+    pub fn set_no_strict(&mut self, value: bool)  {
+      self.builder.set_bool_field(24, value);
+    }
+    #[inline]
+    pub fn get_scale(self) -> f64 {
+      self.builder.get_data_field::<f64>(4)
+    }
+    #[inline]
+    pub fn set_scale(&mut self, value: f64)  {
+      self.builder.set_data_field::<f64>(4, value);
+    }
+  }
+
+  pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
+  impl ::capnp::capability::FromTypelessPipeline for Pipeline {
+    fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
+      Pipeline { _typeless: typeless,  }
+    }
+  }
+  impl Pipeline  {
+  }
+  mod _private {
+    use capnp::private::layout;
+    pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 5, pointers: 0 };
+    pub const TYPE_ID: u64 = 0xf3cd_d237_a53c_a546;
+  }
+}
+
+pub mod kmer_count {
+  #[derive(Copy, Clone)]
+  pub struct Owned(());
+  impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
+  impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
+  impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
+
+  #[derive(Clone, Copy)]
+  pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
+
+  impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,>  {
+    #[inline]
+    fn type_id() -> u64 { _private::TYPE_ID }
+  }
+  impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,>  {
+    fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
+      Reader { reader,  }
+    }
+  }
+
+  impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,>  {
+    fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
+      ::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
+    }
+  }
+
+  impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,>  {
+    fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
+      self.reader
+    }
+  }
+
+  impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,>  {
+    fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
+      self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
+    }
+  }
+
+  impl <'a,> Reader<'a,>  {
+    pub fn reborrow(&self) -> Reader<'_,> {
+      Reader { .. *self }
+    }
+
+    pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
+      self.reader.total_size()
+    }
+    #[inline]
+    pub fn get_hash(self) -> u64 {
+      self.reader.get_data_field::<u64>(0)
+    }
+    #[inline]
+    pub fn get_kmer(self) -> ::capnp::Result<::capnp::data::Reader<'a>> {
+      ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0), ::core::option::Option::None)
+    }
+    pub fn has_kmer(&self) -> bool {
+      !self.reader.get_pointer_field(0).is_null()
+    }
+    #[inline]
+    pub fn get_count(self) -> u32 {
+      self.reader.get_data_field::<u32>(2)
+    }
+    #[inline]
+    pub fn get_extra_count(self) -> u32 {
+      self.reader.get_data_field::<u32>(3)
+    }
+    #[inline]
+    pub fn get_label(self) -> ::capnp::Result<::capnp::data::Reader<'a>> {
+      ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(1), ::core::option::Option::None)
+    }
+    pub fn has_label(&self) -> bool {
+      !self.reader.get_pointer_field(1).is_null()
+    }
+  }
+
+  pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
+  impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,>  {
+    #[inline]
+    fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
+  }
+  impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,>  {
+    #[inline]
+    fn type_id() -> u64 { _private::TYPE_ID }
+  }
+  impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,>  {
+    fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
+      Builder { builder,  }
+    }
+  }
+
+  impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,>  {
+    fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
+      self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
+    }
+  }
+
+  impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,>  {
+    fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
+      ::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
+    }
+    fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
+      ::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
+    }
+  }
+
+  impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,>  {
+    fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
+  }
+
+  impl <'a,> Builder<'a,>  {
+    pub fn into_reader(self) -> Reader<'a,> {
+      ::capnp::traits::FromStructReader::new(self.builder.into_reader())
+    }
+    pub fn reborrow(&mut self) -> Builder<'_,> {
+      Builder { .. *self }
+    }
+    pub fn reborrow_as_reader(&self) -> Reader<'_,> {
+      ::capnp::traits::FromStructReader::new(self.builder.into_reader())
+    }
+
+    pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
+      self.builder.into_reader().total_size()
+    }
+    #[inline]
+    pub fn get_hash(self) -> u64 {
+      self.builder.get_data_field::<u64>(0)
+    }
+    #[inline]
+    pub fn set_hash(&mut self, value: u64)  {
+      self.builder.set_data_field::<u64>(0, value);
+    }
+    #[inline]
+    pub fn get_kmer(self) -> ::capnp::Result<::capnp::data::Builder<'a>> {
+      ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0), ::core::option::Option::None)
+    }
+    #[inline]
+    pub fn set_kmer(&mut self, value: ::capnp::data::Reader<'_>)  {
+      self.builder.get_pointer_field(0).set_data(value);
+    }
+    #[inline]
+    pub fn init_kmer(self, size: u32) -> ::capnp::data::Builder<'a> {
+      self.builder.get_pointer_field(0).init_data(size)
+    }
+    pub fn has_kmer(&self) -> bool {
+      !self.builder.get_pointer_field(0).is_null()
+    }
+    #[inline]
+    pub fn get_count(self) -> u32 {
+      self.builder.get_data_field::<u32>(2)
+    }
+    #[inline]
+    pub fn set_count(&mut self, value: u32)  {
+      self.builder.set_data_field::<u32>(2, value);
+    }
+    #[inline]
+    pub fn get_extra_count(self) -> u32 {
+      self.builder.get_data_field::<u32>(3)
+    }
+    #[inline]
+    pub fn set_extra_count(&mut self, value: u32)  {
+      self.builder.set_data_field::<u32>(3, value);
+    }
+    #[inline]
+    pub fn get_label(self) -> ::capnp::Result<::capnp::data::Builder<'a>> {
+      ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(1), ::core::option::Option::None)
+    }
+    #[inline]
+    pub fn set_label(&mut self, value: ::capnp::data::Reader<'_>)  {
+      self.builder.get_pointer_field(1).set_data(value);
+    }
+    #[inline]
+    pub fn init_label(self, size: u32) -> ::capnp::data::Builder<'a> {
+      self.builder.get_pointer_field(1).init_data(size)
+    }
+    pub fn has_label(&self) -> bool {
+      !self.builder.get_pointer_field(1).is_null()
+    }
+  }
+
+  pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
+  impl ::capnp::capability::FromTypelessPipeline for Pipeline {
+    fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
+      Pipeline { _typeless: typeless,  }
+    }
+  }
+  impl Pipeline  {
+  }
+  mod _private {
+    use capnp::private::layout;
+    pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 2, pointers: 2 };
+    pub const TYPE_ID: u64 = 0x854e_abfe_76ab_932c;
+  }
+}
+
+pub mod sketch {
+  #[derive(Copy, Clone)]
+  pub struct Owned(());
+  impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
+  impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
+  impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
+
+  #[derive(Clone, Copy)]
+  pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
+
+  impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,>  {
+    #[inline]
+    fn type_id() -> u64 { _private::TYPE_ID }
+  }
+  impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,>  {
+    fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
+      Reader { reader,  }
+    }
+  }
+
+  impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,>  {
+    fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
+      ::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
+    }
+  }
+
+  impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,>  {
+    fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
+      self.reader
+    }
+  }
+
+  impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,>  {
+    fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
+      self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
+    }
+  }
+
+  impl <'a,> Reader<'a,>  {
+    pub fn reborrow(&self) -> Reader<'_,> {
+      Reader { .. *self }
+    }
+
+    pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
+      self.reader.total_size()
+    }
+    #[inline]
+    pub fn get_name(self) -> ::capnp::Result<::capnp::text::Reader<'a>> {
+      ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0), ::core::option::Option::None)
+    }
+    pub fn has_name(&self) -> bool {
+      !self.reader.get_pointer_field(0).is_null()
+    }
+    #[inline]
+    pub fn get_seq_length(self) -> u64 {
+      self.reader.get_data_field::<u64>(0)
+    }
+    #[inline]
+    pub fn get_num_valid_kmers(self) -> u64 {
+      self.reader.get_data_field::<u64>(1)
+    }
+    #[inline]
+    pub fn get_comment(self) -> ::capnp::Result<::capnp::text::Reader<'a>> {
+      ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(1), ::core::option::Option::None)
+    }
+    pub fn has_comment(&self) -> bool {
+      !self.reader.get_pointer_field(1).is_null()
+    }
+    #[inline]
+    pub fn get_hashes(self) -> ::capnp::Result<::capnp::struct_list::Reader<'a,crate::serialization::finch_capnp::kmer_count::Owned>> {
+      ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(2), ::core::option::Option::None)
+    }
+    pub fn has_hashes(&self) -> bool {
+      !self.reader.get_pointer_field(2).is_null()
+    }
+    #[inline]
+    pub fn get_filter_params(self) -> ::capnp::Result<crate::serialization::finch_capnp::filter_params::Reader<'a>> {
+      ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(3), ::core::option::Option::None)
+    }
+    pub fn has_filter_params(&self) -> bool {
+      !self.reader.get_pointer_field(3).is_null()
+    }
+    #[inline]
+    pub fn get_sketch_params(self) -> ::capnp::Result<crate::serialization::finch_capnp::sketch_params::Reader<'a>> {
+      ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(4), ::core::option::Option::None)
+    }
+    pub fn has_sketch_params(&self) -> bool {
+      !self.reader.get_pointer_field(4).is_null()
+    }
+  }
+
+  pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
+  impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,>  {
+    #[inline]
+    fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
+  }
+  impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,>  {
+    #[inline]
+    fn type_id() -> u64 { _private::TYPE_ID }
+  }
+  impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,>  {
+    fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
+      Builder { builder,  }
+    }
+  }
+
+  impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,>  {
+    fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
+      self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
+    }
+  }
+
+  impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,>  {
+    fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
+      ::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
+    }
+    fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
+      ::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
+    }
+  }
+
+  impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,>  {
+    fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
+  }
+
+  impl <'a,> Builder<'a,>  {
+    pub fn into_reader(self) -> Reader<'a,> {
+      ::capnp::traits::FromStructReader::new(self.builder.into_reader())
+    }
+    pub fn reborrow(&mut self) -> Builder<'_,> {
+      Builder { .. *self }
+    }
+    pub fn reborrow_as_reader(&self) -> Reader<'_,> {
+      ::capnp::traits::FromStructReader::new(self.builder.into_reader())
+    }
+
+    pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
+      self.builder.into_reader().total_size()
+    }
+    #[inline]
+    pub fn get_name(self) -> ::capnp::Result<::capnp::text::Builder<'a>> {
+      ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0), ::core::option::Option::None)
+    }
+    #[inline]
+    pub fn set_name(&mut self, value: ::capnp::text::Reader<'_>)  {
+      self.builder.get_pointer_field(0).set_text(value);
+    }
+    #[inline]
+    pub fn init_name(self, size: u32) -> ::capnp::text::Builder<'a> {
+      self.builder.get_pointer_field(0).init_text(size)
+    }
+    pub fn has_name(&self) -> bool {
+      !self.builder.get_pointer_field(0).is_null()
+    }
+    #[inline]
+    pub fn get_seq_length(self) -> u64 {
+      self.builder.get_data_field::<u64>(0)
+    }
+    #[inline]
+    pub fn set_seq_length(&mut self, value: u64)  {
+      self.builder.set_data_field::<u64>(0, value);
+    }
+    #[inline]
+    pub fn get_num_valid_kmers(self) -> u64 {
+      self.builder.get_data_field::<u64>(1)
+    }
+    #[inline]
+    pub fn set_num_valid_kmers(&mut self, value: u64)  {
+      self.builder.set_data_field::<u64>(1, value);
+    }
+    #[inline]
+    pub fn get_comment(self) -> ::capnp::Result<::capnp::text::Builder<'a>> {
+      ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(1), ::core::option::Option::None)
+    }
+    #[inline]
+    pub fn set_comment(&mut self, value: ::capnp::text::Reader<'_>)  {
+      self.builder.get_pointer_field(1).set_text(value);
+    }
+    #[inline]
+    pub fn init_comment(self, size: u32) -> ::capnp::text::Builder<'a> {
+      self.builder.get_pointer_field(1).init_text(size)
+    }
+    pub fn has_comment(&self) -> bool {
+      !self.builder.get_pointer_field(1).is_null()
+    }
+    #[inline]
+    pub fn get_hashes(self) -> ::capnp::Result<::capnp::struct_list::Builder<'a,crate::serialization::finch_capnp::kmer_count::Owned>> {
+      ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(2), ::core::option::Option::None)
+    }
+    #[inline]
+    pub fn set_hashes(&mut self, value: ::capnp::struct_list::Reader<'a,crate::serialization::finch_capnp::kmer_count::Owned>) -> ::capnp::Result<()> {
+      ::capnp::traits::SetPointerBuilder::set_pointer_builder(self.builder.get_pointer_field(2), value, false)
+    }
+    #[inline]
+    pub fn init_hashes(self, size: u32) -> ::capnp::struct_list::Builder<'a,crate::serialization::finch_capnp::kmer_count::Owned> {
+      ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(2), size)
+    }
+    pub fn has_hashes(&self) -> bool {
+      !self.builder.get_pointer_field(2).is_null()
+    }
+    #[inline]
+    pub fn get_filter_params(self) -> ::capnp::Result<crate::serialization::finch_capnp::filter_params::Builder<'a>> {
+      ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(3), ::core::option::Option::None)
+    }
+    #[inline]
+    pub fn set_filter_params(&mut self, value: crate::serialization::finch_capnp::filter_params::Reader<'_>) -> ::capnp::Result<()> {
+      ::capnp::traits::SetPointerBuilder::set_pointer_builder(self.builder.get_pointer_field(3), value, false)
+    }
+    #[inline]
+    pub fn init_filter_params(self, ) -> crate::serialization::finch_capnp::filter_params::Builder<'a> {
+      ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(3), 0)
+    }
+    pub fn has_filter_params(&self) -> bool {
+      !self.builder.get_pointer_field(3).is_null()
+    }
+    #[inline]
+    pub fn get_sketch_params(self) -> ::capnp::Result<crate::serialization::finch_capnp::sketch_params::Builder<'a>> {
+      ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(4), ::core::option::Option::None)
+    }
+    #[inline]
+    pub fn set_sketch_params(&mut self, value: crate::serialization::finch_capnp::sketch_params::Reader<'_>) -> ::capnp::Result<()> {
+      ::capnp::traits::SetPointerBuilder::set_pointer_builder(self.builder.get_pointer_field(4), value, false)
+    }
+    #[inline]
+    pub fn init_sketch_params(self, ) -> crate::serialization::finch_capnp::sketch_params::Builder<'a> {
+      ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(4), 0)
+    }
+    pub fn has_sketch_params(&self) -> bool {
+      !self.builder.get_pointer_field(4).is_null()
+    }
+  }
+
+  pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
+  impl ::capnp::capability::FromTypelessPipeline for Pipeline {
+    fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
+      Pipeline { _typeless: typeless,  }
+    }
+  }
+  impl Pipeline  {
+    pub fn get_filter_params(&self) -> crate::serialization::finch_capnp::filter_params::Pipeline {
+      ::capnp::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field(3))
+    }
+    pub fn get_sketch_params(&self) -> crate::serialization::finch_capnp::sketch_params::Pipeline {
+      ::capnp::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field(4))
+    }
+  }
+  mod _private {
+    use capnp::private::layout;
+    pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 2, pointers: 5 };
+    pub const TYPE_ID: u64 = 0xb602_150b_6621_a020;
+  }
+}
+
+pub mod multisketch {
+  #[derive(Copy, Clone)]
+  pub struct Owned(());
+  impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
+  impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
+  impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
+
+  #[derive(Clone, Copy)]
+  pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
+
+  impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,>  {
+    #[inline]
+    fn type_id() -> u64 { _private::TYPE_ID }
+  }
+  impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,>  {
+    fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
+      Reader { reader,  }
+    }
+  }
+
+  impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,>  {
+    fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
+      ::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
+    }
+  }
+
+  impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,>  {
+    fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
+      self.reader
+    }
+  }
+
+  impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,>  {
+    fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
+      self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
+    }
+  }
+
+  impl <'a,> Reader<'a,>  {
+    pub fn reborrow(&self) -> Reader<'_,> {
+      Reader { .. *self }
+    }
+
+    pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
+      self.reader.total_size()
+    }
+    #[inline]
+    pub fn get_sketches(self) -> ::capnp::Result<::capnp::struct_list::Reader<'a,crate::serialization::finch_capnp::sketch::Owned>> {
+      ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0), ::core::option::Option::None)
+    }
+    pub fn has_sketches(&self) -> bool {
+      !self.reader.get_pointer_field(0).is_null()
+    }
+  }
+
+  pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
+  impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,>  {
+    #[inline]
+    fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
+  }
+  impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,>  {
+    #[inline]
+    fn type_id() -> u64 { _private::TYPE_ID }
+  }
+  impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,>  {
+    fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
+      Builder { builder,  }
+    }
+  }
+
+  impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,>  {
+    fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
+      self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
+    }
+  }
+
+  impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,>  {
+    fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
+      ::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
+    }
+    fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
+      ::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
+    }
+  }
+
+  impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,>  {
+    fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
+  }
+
+  impl <'a,> Builder<'a,>  {
+    pub fn into_reader(self) -> Reader<'a,> {
+      ::capnp::traits::FromStructReader::new(self.builder.into_reader())
+    }
+    pub fn reborrow(&mut self) -> Builder<'_,> {
+      Builder { .. *self }
+    }
+    pub fn reborrow_as_reader(&self) -> Reader<'_,> {
+      ::capnp::traits::FromStructReader::new(self.builder.into_reader())
+    }
+
+    pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
+      self.builder.into_reader().total_size()
+    }
+    #[inline]
+    pub fn get_sketches(self) -> ::capnp::Result<::capnp::struct_list::Builder<'a,crate::serialization::finch_capnp::sketch::Owned>> {
+      ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0), ::core::option::Option::None)
+    }
+    #[inline]
+    pub fn set_sketches(&mut self, value: ::capnp::struct_list::Reader<'a,crate::serialization::finch_capnp::sketch::Owned>) -> ::capnp::Result<()> {
+      ::capnp::traits::SetPointerBuilder::set_pointer_builder(self.builder.get_pointer_field(0), value, false)
+    }
+    #[inline]
+    pub fn init_sketches(self, size: u32) -> ::capnp::struct_list::Builder<'a,crate::serialization::finch_capnp::sketch::Owned> {
+      ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(0), size)
+    }
+    pub fn has_sketches(&self) -> bool {
+      !self.builder.get_pointer_field(0).is_null()
+    }
+  }
+
+  pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
+  impl ::capnp::capability::FromTypelessPipeline for Pipeline {
+    fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
+      Pipeline { _typeless: typeless,  }
+    }
+  }
+  impl Pipeline  {
+  }
+  mod _private {
+    use capnp::private::layout;
+    pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 0, pointers: 1 };
+    pub const TYPE_ID: u64 = 0xe71d_cbc8_f49e_581a;
+  }
+}
diff --git a/src/serialization/json.rs b/lib/src/serialization/json.rs
similarity index 97%
rename from src/serialization/json.rs
rename to lib/src/serialization/json.rs
index 78fc73d..a26aa36 100644
--- a/src/serialization/json.rs
+++ b/lib/src/serialization/json.rs
@@ -2,15 +2,16 @@ use std::collections::HashMap;
 use std::fmt;
 use std::mem;
 
-use failure::bail;
-use serde::de::{self, Deserialize, Deserializer, Visitor};
-use serde::ser::{Serialize, SerializeStruct, Serializer};
+use serde::de::{self, Deserializer, Visitor};
+use serde::ser::{SerializeStruct, Serializer};
+use serde::{Deserialize, Serialize};
 
+use crate::bail;
+use crate::errors::FinchResult;
 use crate::filtering::FilterParams;
 pub use crate::serialization::mash::{read_mash_file, write_mash_file};
 use crate::serialization::Sketch;
 use crate::sketch_schemes::{KmerCount, SketchParams};
-use crate::Result as FinchResult;
 
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct JsonSketch {
diff --git a/lib/src/serialization/mash.capnp b/lib/src/serialization/mash.capnp
new file mode 100644
index 0000000..638e83d
--- /dev/null
+++ b/lib/src/serialization/mash.capnp
@@ -0,0 +1,120 @@
+# Copyright © 2015, Battelle National Biodefense Institute (BNBI);
+# all rights reserved. Authored by: Brian Ondov, Todd Treangen,
+# Sergey Koren, and Adam Phillippy
+#
+# See the LICENSE.txt file included with this software for license information.
+# Content of LICENSE.txt
+#PURPOSE
+#
+#Mash is a fast sequence distance estimator that uses the MinHash
+#algorithm and is designed to work with genomes and metagenomes in the
+#form of assemblies or reads. It is implemented in C++ and is
+#distributed with:
+#
+#KSeq
+#  lh3lh3.users.sourceforge.net/kseq.shtml
+#  MIT License
+#
+#MurmurHash3
+#  code.google.com/p/smhasher/wiki/MurmurHash3
+#  Public domain
+#
+#Open Bloom Filter
+#  https://code.google.com/p/bloom/source/browse/trunk/bloom_filter.hpp
+#  Common Public License
+#
+#COPYRIGHT LICENSE
+#
+#Copyright © 2015, Battelle National Biodefense Institute (BNBI);
+#all rights reserved. Authored by: Brian Ondov, Todd Treangen,
+#Sergey Koren, and Adam Phillippy
+#
+#This Software was prepared for the Department of Homeland Security
+#(DHS) by the Battelle National Biodefense Institute, LLC (BNBI) as
+#part of contract HSHQDC-07-C-00020 to manage and operate the National
+#Biodefense Analysis and Countermeasures Center (NBACC), a Federally
+#Funded Research and Development Center.
+#
+#Redistribution and use in source and binary forms, with or without
+#modification, are permitted provided that the following conditions are
+#met:
+#
+#1. Redistributions of source code must retain the above copyright
+#notice, this list of conditions and the following disclaimer.
+#
+#2. Redistributions in binary form must reproduce the above copyright
+#notice, this list of conditions and the following disclaimer in the
+#documentation and/or other materials provided with the distribution.
+#
+#3. Neither the name of the copyright holder nor the names of its
+#contributors may be used to endorse or promote products derived from
+#this software without specific prior written permission.
+#
+#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+#"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+#LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+#A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+#HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+#DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+#THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+#(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+#OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# + https://github.com/marbl/Mash/issues/112
+
+using Cxx = import "/capnp/c++.capnp";
+$Cxx.namespace("capnp");
+
+@0xc4c8b1ada05e7704;
+
+struct MinHash
+{
+	struct ReferenceList
+	{
+		struct Reference
+		{
+			sequence @0 : Text;
+			quality @1 : Text;
+			length @2 : UInt32;
+			length64 @ 7 : UInt64;
+			# https://github.com/marbl/Mash/issues/112
+			numValidKmers @9 : UInt64;
+			name @3 : Text;
+			comment @4 : Text;
+			hashes32 @5 : List(UInt32);
+			hashes64 @6 : List(UInt64);
+			counts32 @8 : List(UInt32);
+		}
+
+		references @0 : List(Reference);
+	}
+
+	struct LocusList
+	{
+		struct Locus
+		{
+			sequence @0 : UInt32;
+			position @1 : UInt32;
+			hash32 @2 : UInt32;
+			hash64 @3 : UInt64;
+		}
+
+		loci @0 : List(Locus);
+	}
+
+	kmerSize @0 : UInt32;
+	windowSize @1 : UInt32;
+	minHashesPerWindow @2 : UInt32;
+	concatenated @3 : Bool;
+	error @6 : Float32;
+	noncanonical @7 : Bool;
+	alphabet @8 : Text;
+	preserveCase @9 : Bool;
+	hashSeed @10 : UInt32 = 42;
+
+	referenceListOld @4 : ReferenceList;
+	referenceList @11 : ReferenceList;
+	locusList @5 : LocusList;
+}
diff --git a/src/serialization/mash.rs b/lib/src/serialization/mash.rs
similarity index 92%
rename from src/serialization/mash.rs
rename to lib/src/serialization/mash.rs
index a53825d..9bde301 100644
--- a/src/serialization/mash.rs
+++ b/lib/src/serialization/mash.rs
@@ -1,15 +1,13 @@
-use std::convert::TryFrom;
 use std::io::{BufRead, Write};
 
 use capnp::message;
 use capnp::serialize as capnp_serialize;
-use failure::format_err;
 
+use crate::errors::FinchResult;
 use crate::filtering::FilterParams;
 use crate::serialization::mash_capnp::min_hash;
 use crate::serialization::Sketch;
 use crate::sketch_schemes::{ItemHash, KmerCount, SketchParams};
-use crate::Result as FinchResult;
 
 pub fn write_mash_file(mut file: &mut dyn Write, sketches: &[Sketch]) -> FinchResult<()> {
     let params = SketchParams::from_sketches(&sketches)?;
@@ -50,12 +48,7 @@ pub fn write_mash_file(mut file: &mut dyn Write, sketches: &[Sketch]) -> FinchRe
             }
             let mash_counts = mash_sketch.init_counts32(sketch.hashes.len() as u32);
             for (j, hash) in sketch.hashes.iter().enumerate() {
-                mash_counts.reborrow().set(
-                    j as u32,
-                    TryFrom::try_from(hash.count).map_err(|_| {
-                        format_err!("Counts greater than 32-bit not supported in mash files")
-                    })?,
-                );
+                mash_counts.reborrow().set(j as u32, hash.count);
             }
         }
     }
@@ -65,7 +58,7 @@ pub fn write_mash_file(mut file: &mut dyn Write, sketches: &[Sketch]) -> FinchRe
 }
 
 pub fn read_mash_file(mut file: &mut dyn BufRead) -> FinchResult<Vec<Sketch>> {
-    let options = *message::ReaderOptions::new().traversal_limit_in_words(1024 * 1024 * 1024);
+    let options = *message::ReaderOptions::new().traversal_limit_in_words(Some(1024 * 1024 * 1024));
     let reader = capnp_serialize::read_message(&mut file, options)?;
     let mash_data: min_hash::Reader = reader.get_root::<min_hash::Reader>()?;
 
diff --git a/lib/src/serialization/mash_capnp.rs b/lib/src/serialization/mash_capnp.rs
new file mode 100644
index 0000000..6bf8e6d
--- /dev/null
+++ b/lib/src/serialization/mash_capnp.rs
@@ -0,0 +1,1044 @@
+// @generated by the capnpc-rust plugin to the Cap'n Proto schema compiler.
+// DO NOT EDIT.
+// source: mash.capnp
+
+
+pub mod min_hash {
+  #[derive(Copy, Clone)]
+  pub struct Owned(());
+  impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
+  impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
+  impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
+
+  #[derive(Clone, Copy)]
+  pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
+
+  impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,>  {
+    #[inline]
+    fn type_id() -> u64 { _private::TYPE_ID }
+  }
+  impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,>  {
+    fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
+      Reader { reader,  }
+    }
+  }
+
+  impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,>  {
+    fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
+      ::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
+    }
+  }
+
+  impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,>  {
+    fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
+      self.reader
+    }
+  }
+
+  impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,>  {
+    fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
+      self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
+    }
+  }
+
+  impl <'a,> Reader<'a,>  {
+    pub fn reborrow(&self) -> Reader<'_,> {
+      Reader { .. *self }
+    }
+
+    pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
+      self.reader.total_size()
+    }
+    #[inline]
+    pub fn get_kmer_size(self) -> u32 {
+      self.reader.get_data_field::<u32>(0)
+    }
+    #[inline]
+    pub fn get_window_size(self) -> u32 {
+      self.reader.get_data_field::<u32>(1)
+    }
+    #[inline]
+    pub fn get_min_hashes_per_window(self) -> u32 {
+      self.reader.get_data_field::<u32>(2)
+    }
+    #[inline]
+    pub fn get_concatenated(self) -> bool {
+      self.reader.get_bool_field(96)
+    }
+    #[inline]
+    pub fn get_reference_list_old(self) -> ::capnp::Result<crate::serialization::mash_capnp::min_hash::reference_list::Reader<'a>> {
+      ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0), ::core::option::Option::None)
+    }
+    pub fn has_reference_list_old(&self) -> bool {
+      !self.reader.get_pointer_field(0).is_null()
+    }
+    #[inline]
+    pub fn get_locus_list(self) -> ::capnp::Result<crate::serialization::mash_capnp::min_hash::locus_list::Reader<'a>> {
+      ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(1), ::core::option::Option::None)
+    }
+    pub fn has_locus_list(&self) -> bool {
+      !self.reader.get_pointer_field(1).is_null()
+    }
+    #[inline]
+    pub fn get_error(self) -> f32 {
+      self.reader.get_data_field::<f32>(4)
+    }
+    #[inline]
+    pub fn get_noncanonical(self) -> bool {
+      self.reader.get_bool_field(97)
+    }
+    #[inline]
+    pub fn get_alphabet(self) -> ::capnp::Result<::capnp::text::Reader<'a>> {
+      ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(2), ::core::option::Option::None)
+    }
+    pub fn has_alphabet(&self) -> bool {
+      !self.reader.get_pointer_field(2).is_null()
+    }
+    #[inline]
+    pub fn get_preserve_case(self) -> bool {
+      self.reader.get_bool_field(98)
+    }
+    #[inline]
+    pub fn get_hash_seed(self) -> u32 {
+      self.reader.get_data_field_mask::<u32>(5, 42)
+    }
+    #[inline]
+    pub fn get_reference_list(self) -> ::capnp::Result<crate::serialization::mash_capnp::min_hash::reference_list::Reader<'a>> {
+      ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(3), ::core::option::Option::None)
+    }
+    pub fn has_reference_list(&self) -> bool {
+      !self.reader.get_pointer_field(3).is_null()
+    }
+  }
+
+  pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
+  impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,>  {
+    #[inline]
+    fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
+  }
+  impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,>  {
+    #[inline]
+    fn type_id() -> u64 { _private::TYPE_ID }
+  }
+  impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,>  {
+    fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
+      Builder { builder,  }
+    }
+  }
+
+  impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,>  {
+    fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
+      self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
+    }
+  }
+
+  impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,>  {
+    fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
+      ::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
+    }
+    fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
+      ::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
+    }
+  }
+
+  impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,>  {
+    fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
+  }
+
+  impl <'a,> Builder<'a,>  {
+    pub fn into_reader(self) -> Reader<'a,> {
+      ::capnp::traits::FromStructReader::new(self.builder.into_reader())
+    }
+    pub fn reborrow(&mut self) -> Builder<'_,> {
+      Builder { .. *self }
+    }
+    pub fn reborrow_as_reader(&self) -> Reader<'_,> {
+      ::capnp::traits::FromStructReader::new(self.builder.into_reader())
+    }
+
+    pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
+      self.builder.into_reader().total_size()
+    }
+    #[inline]
+    pub fn get_kmer_size(self) -> u32 {
+      self.builder.get_data_field::<u32>(0)
+    }
+    #[inline]
+    pub fn set_kmer_size(&mut self, value: u32)  {
+      self.builder.set_data_field::<u32>(0, value);
+    }
+    #[inline]
+    pub fn get_window_size(self) -> u32 {
+      self.builder.get_data_field::<u32>(1)
+    }
+    #[inline]
+    pub fn set_window_size(&mut self, value: u32)  {
+      self.builder.set_data_field::<u32>(1, value);
+    }
+    #[inline]
+    pub fn get_min_hashes_per_window(self) -> u32 {
+      self.builder.get_data_field::<u32>(2)
+    }
+    #[inline]
+    pub fn set_min_hashes_per_window(&mut self, value: u32)  {
+      self.builder.set_data_field::<u32>(2, value);
+    }
+    #[inline]
+    pub fn get_concatenated(self) -> bool {
+      self.builder.get_bool_field(96)
+    }
+    #[inline]
+    pub fn set_concatenated(&mut self, value: bool)  {
+      self.builder.set_bool_field(96, value);
+    }
+    #[inline]
+    pub fn get_reference_list_old(self) -> ::capnp::Result<crate::serialization::mash_capnp::min_hash::reference_list::Builder<'a>> {
+      ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0), ::core::option::Option::None)
+    }
+    #[inline]
+    pub fn set_reference_list_old(&mut self, value: crate::serialization::mash_capnp::min_hash::reference_list::Reader<'_>) -> ::capnp::Result<()> {
+      ::capnp::traits::SetPointerBuilder::set_pointer_builder(self.builder.get_pointer_field(0), value, false)
+    }
+    #[inline]
+    pub fn init_reference_list_old(self, ) -> crate::serialization::mash_capnp::min_hash::reference_list::Builder<'a> {
+      ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(0), 0)
+    }
+    pub fn has_reference_list_old(&self) -> bool {
+      !self.builder.get_pointer_field(0).is_null()
+    }
+    #[inline]
+    pub fn get_locus_list(self) -> ::capnp::Result<crate::serialization::mash_capnp::min_hash::locus_list::Builder<'a>> {
+      ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(1), ::core::option::Option::None)
+    }
+    #[inline]
+    pub fn set_locus_list(&mut self, value: crate::serialization::mash_capnp::min_hash::locus_list::Reader<'_>) -> ::capnp::Result<()> {
+      ::capnp::traits::SetPointerBuilder::set_pointer_builder(self.builder.get_pointer_field(1), value, false)
+    }
+    #[inline]
+    pub fn init_locus_list(self, ) -> crate::serialization::mash_capnp::min_hash::locus_list::Builder<'a> {
+      ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(1), 0)
+    }
+    pub fn has_locus_list(&self) -> bool {
+      !self.builder.get_pointer_field(1).is_null()
+    }
+    #[inline]
+    pub fn get_error(self) -> f32 {
+      self.builder.get_data_field::<f32>(4)
+    }
+    #[inline]
+    pub fn set_error(&mut self, value: f32)  {
+      self.builder.set_data_field::<f32>(4, value);
+    }
+    #[inline]
+    pub fn get_noncanonical(self) -> bool {
+      self.builder.get_bool_field(97)
+    }
+    #[inline]
+    pub fn set_noncanonical(&mut self, value: bool)  {
+      self.builder.set_bool_field(97, value);
+    }
+    #[inline]
+    pub fn get_alphabet(self) -> ::capnp::Result<::capnp::text::Builder<'a>> {
+      ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(2), ::core::option::Option::None)
+    }
+    #[inline]
+    pub fn set_alphabet(&mut self, value: ::capnp::text::Reader<'_>)  {
+      self.builder.get_pointer_field(2).set_text(value);
+    }
+    #[inline]
+    pub fn init_alphabet(self, size: u32) -> ::capnp::text::Builder<'a> {
+      self.builder.get_pointer_field(2).init_text(size)
+    }
+    pub fn has_alphabet(&self) -> bool {
+      !self.builder.get_pointer_field(2).is_null()
+    }
+    #[inline]
+    pub fn get_preserve_case(self) -> bool {
+      self.builder.get_bool_field(98)
+    }
+    #[inline]
+    pub fn set_preserve_case(&mut self, value: bool)  {
+      self.builder.set_bool_field(98, value);
+    }
+    #[inline]
+    pub fn get_hash_seed(self) -> u32 {
+      self.builder.get_data_field_mask::<u32>(5, 42)
+    }
+    #[inline]
+    pub fn set_hash_seed(&mut self, value: u32)  {
+      self.builder.set_data_field_mask::<u32>(5, value, 42);
+    }
+    #[inline]
+    pub fn get_reference_list(self) -> ::capnp::Result<crate::serialization::mash_capnp::min_hash::reference_list::Builder<'a>> {
+      ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(3), ::core::option::Option::None)
+    }
+    #[inline]
+    pub fn set_reference_list(&mut self, value: crate::serialization::mash_capnp::min_hash::reference_list::Reader<'_>) -> ::capnp::Result<()> {
+      ::capnp::traits::SetPointerBuilder::set_pointer_builder(self.builder.get_pointer_field(3), value, false)
+    }
+    #[inline]
+    pub fn init_reference_list(self, ) -> crate::serialization::mash_capnp::min_hash::reference_list::Builder<'a> {
+      ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(3), 0)
+    }
+    pub fn has_reference_list(&self) -> bool {
+      !self.builder.get_pointer_field(3).is_null()
+    }
+  }
+
+  pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
+  impl ::capnp::capability::FromTypelessPipeline for Pipeline {
+    fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
+      Pipeline { _typeless: typeless,  }
+    }
+  }
+  impl Pipeline  {
+    pub fn get_reference_list_old(&self) -> crate::serialization::mash_capnp::min_hash::reference_list::Pipeline {
+      ::capnp::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field(0))
+    }
+    pub fn get_locus_list(&self) -> crate::serialization::mash_capnp::min_hash::locus_list::Pipeline {
+      ::capnp::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field(1))
+    }
+    pub fn get_reference_list(&self) -> crate::serialization::mash_capnp::min_hash::reference_list::Pipeline {
+      ::capnp::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field(3))
+    }
+  }
+  mod _private {
+    use capnp::private::layout;
+    pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 3, pointers: 4 };
+    pub const TYPE_ID: u64 = 0xd9d1_6806_af78_2606;
+  }
+
+  pub mod reference_list {
+    #[derive(Copy, Clone)]
+    pub struct Owned(());
+    impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
+    impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
+    impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
+
+    #[derive(Clone, Copy)]
+    pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
+
+    impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,>  {
+      #[inline]
+      fn type_id() -> u64 { _private::TYPE_ID }
+    }
+    impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,>  {
+      fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
+        Reader { reader,  }
+      }
+    }
+
+    impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,>  {
+      fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
+        ::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
+      }
+    }
+
+    impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,>  {
+      fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
+        self.reader
+      }
+    }
+
+    impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,>  {
+      fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
+        self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
+      }
+    }
+
+    impl <'a,> Reader<'a,>  {
+      pub fn reborrow(&self) -> Reader<'_,> {
+        Reader { .. *self }
+      }
+
+      pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
+        self.reader.total_size()
+      }
+      #[inline]
+      pub fn get_references(self) -> ::capnp::Result<::capnp::struct_list::Reader<'a,crate::serialization::mash_capnp::min_hash::reference_list::reference::Owned>> {
+        ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0), ::core::option::Option::None)
+      }
+      pub fn has_references(&self) -> bool {
+        !self.reader.get_pointer_field(0).is_null()
+      }
+    }
+
+    pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
+    impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,>  {
+      #[inline]
+      fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
+    }
+    impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,>  {
+      #[inline]
+      fn type_id() -> u64 { _private::TYPE_ID }
+    }
+    impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,>  {
+      fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
+        Builder { builder,  }
+      }
+    }
+
+    impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,>  {
+      fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
+        self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
+      }
+    }
+
+    impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,>  {
+      fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
+        ::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
+      }
+      fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
+        ::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
+      }
+    }
+
+    impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,>  {
+      fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
+    }
+
+    impl <'a,> Builder<'a,>  {
+      pub fn into_reader(self) -> Reader<'a,> {
+        ::capnp::traits::FromStructReader::new(self.builder.into_reader())
+      }
+      pub fn reborrow(&mut self) -> Builder<'_,> {
+        Builder { .. *self }
+      }
+      pub fn reborrow_as_reader(&self) -> Reader<'_,> {
+        ::capnp::traits::FromStructReader::new(self.builder.into_reader())
+      }
+
+      pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
+        self.builder.into_reader().total_size()
+      }
+      #[inline]
+      pub fn get_references(self) -> ::capnp::Result<::capnp::struct_list::Builder<'a,crate::serialization::mash_capnp::min_hash::reference_list::reference::Owned>> {
+        ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0), ::core::option::Option::None)
+      }
+      #[inline]
+      pub fn set_references(&mut self, value: ::capnp::struct_list::Reader<'a,crate::serialization::mash_capnp::min_hash::reference_list::reference::Owned>) -> ::capnp::Result<()> {
+        ::capnp::traits::SetPointerBuilder::set_pointer_builder(self.builder.get_pointer_field(0), value, false)
+      }
+      #[inline]
+      pub fn init_references(self, size: u32) -> ::capnp::struct_list::Builder<'a,crate::serialization::mash_capnp::min_hash::reference_list::reference::Owned> {
+        ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(0), size)
+      }
+      pub fn has_references(&self) -> bool {
+        !self.builder.get_pointer_field(0).is_null()
+      }
+    }
+
+    pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
+    impl ::capnp::capability::FromTypelessPipeline for Pipeline {
+      fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
+        Pipeline { _typeless: typeless,  }
+      }
+    }
+    impl Pipeline  {
+    }
+    mod _private {
+      use capnp::private::layout;
+      pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 0, pointers: 1 };
+      pub const TYPE_ID: u64 = 0xcf71_219d_02db_7ad0;
+    }
+
+    pub mod reference {
+      #[derive(Copy, Clone)]
+      pub struct Owned(());
+      impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
+      impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
+      impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
+
+      #[derive(Clone, Copy)]
+      pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
+
+      impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,>  {
+        #[inline]
+        fn type_id() -> u64 { _private::TYPE_ID }
+      }
+      impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,>  {
+        fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
+          Reader { reader,  }
+        }
+      }
+
+      impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,>  {
+        fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
+          ::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
+        }
+      }
+
+      impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,>  {
+        fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
+          self.reader
+        }
+      }
+
+      impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,>  {
+        fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
+          self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
+        }
+      }
+
+      impl <'a,> Reader<'a,>  {
+        pub fn reborrow(&self) -> Reader<'_,> {
+          Reader { .. *self }
+        }
+
+        pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
+          self.reader.total_size()
+        }
+        #[inline]
+        pub fn get_sequence(self) -> ::capnp::Result<::capnp::text::Reader<'a>> {
+          ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0), ::core::option::Option::None)
+        }
+        pub fn has_sequence(&self) -> bool {
+          !self.reader.get_pointer_field(0).is_null()
+        }
+        #[inline]
+        pub fn get_quality(self) -> ::capnp::Result<::capnp::text::Reader<'a>> {
+          ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(1), ::core::option::Option::None)
+        }
+        pub fn has_quality(&self) -> bool {
+          !self.reader.get_pointer_field(1).is_null()
+        }
+        #[inline]
+        pub fn get_length(self) -> u32 {
+          self.reader.get_data_field::<u32>(0)
+        }
+        #[inline]
+        pub fn get_name(self) -> ::capnp::Result<::capnp::text::Reader<'a>> {
+          ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(2), ::core::option::Option::None)
+        }
+        pub fn has_name(&self) -> bool {
+          !self.reader.get_pointer_field(2).is_null()
+        }
+        #[inline]
+        pub fn get_comment(self) -> ::capnp::Result<::capnp::text::Reader<'a>> {
+          ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(3), ::core::option::Option::None)
+        }
+        pub fn has_comment(&self) -> bool {
+          !self.reader.get_pointer_field(3).is_null()
+        }
+        #[inline]
+        pub fn get_hashes32(self) -> ::capnp::Result<::capnp::primitive_list::Reader<'a,u32>> {
+          ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(4), ::core::option::Option::None)
+        }
+        pub fn has_hashes32(&self) -> bool {
+          !self.reader.get_pointer_field(4).is_null()
+        }
+        #[inline]
+        pub fn get_hashes64(self) -> ::capnp::Result<::capnp::primitive_list::Reader<'a,u64>> {
+          ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(5), ::core::option::Option::None)
+        }
+        pub fn has_hashes64(&self) -> bool {
+          !self.reader.get_pointer_field(5).is_null()
+        }
+        #[inline]
+        pub fn get_length64(self) -> u64 {
+          self.reader.get_data_field::<u64>(1)
+        }
+        #[inline]
+        pub fn get_counts32(self) -> ::capnp::Result<::capnp::primitive_list::Reader<'a,u32>> {
+          ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(6), ::core::option::Option::None)
+        }
+        pub fn has_counts32(&self) -> bool {
+          !self.reader.get_pointer_field(6).is_null()
+        }
+        #[inline]
+        pub fn get_num_valid_kmers(self) -> u64 {
+          self.reader.get_data_field::<u64>(2)
+        }
+      }
+
+      pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
+      impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,>  {
+        #[inline]
+        fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
+      }
+      impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,>  {
+        #[inline]
+        fn type_id() -> u64 { _private::TYPE_ID }
+      }
+      impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,>  {
+        fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
+          Builder { builder,  }
+        }
+      }
+
+      impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,>  {
+        fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
+          self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
+        }
+      }
+
+      impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,>  {
+        fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
+          ::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
+        }
+        fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
+          ::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
+        }
+      }
+
+      impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,>  {
+        fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
+      }
+
+      impl <'a,> Builder<'a,>  {
+        pub fn into_reader(self) -> Reader<'a,> {
+          ::capnp::traits::FromStructReader::new(self.builder.into_reader())
+        }
+        pub fn reborrow(&mut self) -> Builder<'_,> {
+          Builder { .. *self }
+        }
+        pub fn reborrow_as_reader(&self) -> Reader<'_,> {
+          ::capnp::traits::FromStructReader::new(self.builder.into_reader())
+        }
+
+        pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
+          self.builder.into_reader().total_size()
+        }
+        #[inline]
+        pub fn get_sequence(self) -> ::capnp::Result<::capnp::text::Builder<'a>> {
+          ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0), ::core::option::Option::None)
+        }
+        #[inline]
+        pub fn set_sequence(&mut self, value: ::capnp::text::Reader<'_>)  {
+          self.builder.get_pointer_field(0).set_text(value);
+        }
+        #[inline]
+        pub fn init_sequence(self, size: u32) -> ::capnp::text::Builder<'a> {
+          self.builder.get_pointer_field(0).init_text(size)
+        }
+        pub fn has_sequence(&self) -> bool {
+          !self.builder.get_pointer_field(0).is_null()
+        }
+        #[inline]
+        pub fn get_quality(self) -> ::capnp::Result<::capnp::text::Builder<'a>> {
+          ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(1), ::core::option::Option::None)
+        }
+        #[inline]
+        pub fn set_quality(&mut self, value: ::capnp::text::Reader<'_>)  {
+          self.builder.get_pointer_field(1).set_text(value);
+        }
+        #[inline]
+        pub fn init_quality(self, size: u32) -> ::capnp::text::Builder<'a> {
+          self.builder.get_pointer_field(1).init_text(size)
+        }
+        pub fn has_quality(&self) -> bool {
+          !self.builder.get_pointer_field(1).is_null()
+        }
+        #[inline]
+        pub fn get_length(self) -> u32 {
+          self.builder.get_data_field::<u32>(0)
+        }
+        #[inline]
+        pub fn set_length(&mut self, value: u32)  {
+          self.builder.set_data_field::<u32>(0, value);
+        }
+        #[inline]
+        pub fn get_name(self) -> ::capnp::Result<::capnp::text::Builder<'a>> {
+          ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(2), ::core::option::Option::None)
+        }
+        #[inline]
+        pub fn set_name(&mut self, value: ::capnp::text::Reader<'_>)  {
+          self.builder.get_pointer_field(2).set_text(value);
+        }
+        #[inline]
+        pub fn init_name(self, size: u32) -> ::capnp::text::Builder<'a> {
+          self.builder.get_pointer_field(2).init_text(size)
+        }
+        pub fn has_name(&self) -> bool {
+          !self.builder.get_pointer_field(2).is_null()
+        }
+        #[inline]
+        pub fn get_comment(self) -> ::capnp::Result<::capnp::text::Builder<'a>> {
+          ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(3), ::core::option::Option::None)
+        }
+        #[inline]
+        pub fn set_comment(&mut self, value: ::capnp::text::Reader<'_>)  {
+          self.builder.get_pointer_field(3).set_text(value);
+        }
+        #[inline]
+        pub fn init_comment(self, size: u32) -> ::capnp::text::Builder<'a> {
+          self.builder.get_pointer_field(3).init_text(size)
+        }
+        pub fn has_comment(&self) -> bool {
+          !self.builder.get_pointer_field(3).is_null()
+        }
+        #[inline]
+        pub fn get_hashes32(self) -> ::capnp::Result<::capnp::primitive_list::Builder<'a,u32>> {
+          ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(4), ::core::option::Option::None)
+        }
+        #[inline]
+        pub fn set_hashes32(&mut self, value: ::capnp::primitive_list::Reader<'a,u32>) -> ::capnp::Result<()> {
+          ::capnp::traits::SetPointerBuilder::set_pointer_builder(self.builder.get_pointer_field(4), value, false)
+        }
+        #[inline]
+        pub fn init_hashes32(self, size: u32) -> ::capnp::primitive_list::Builder<'a,u32> {
+          ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(4), size)
+        }
+        pub fn has_hashes32(&self) -> bool {
+          !self.builder.get_pointer_field(4).is_null()
+        }
+        #[inline]
+        pub fn get_hashes64(self) -> ::capnp::Result<::capnp::primitive_list::Builder<'a,u64>> {
+          ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(5), ::core::option::Option::None)
+        }
+        #[inline]
+        pub fn set_hashes64(&mut self, value: ::capnp::primitive_list::Reader<'a,u64>) -> ::capnp::Result<()> {
+          ::capnp::traits::SetPointerBuilder::set_pointer_builder(self.builder.get_pointer_field(5), value, false)
+        }
+        #[inline]
+        pub fn init_hashes64(self, size: u32) -> ::capnp::primitive_list::Builder<'a,u64> {
+          ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(5), size)
+        }
+        pub fn has_hashes64(&self) -> bool {
+          !self.builder.get_pointer_field(5).is_null()
+        }
+        #[inline]
+        pub fn get_length64(self) -> u64 {
+          self.builder.get_data_field::<u64>(1)
+        }
+        #[inline]
+        pub fn set_length64(&mut self, value: u64)  {
+          self.builder.set_data_field::<u64>(1, value);
+        }
+        #[inline]
+        pub fn get_counts32(self) -> ::capnp::Result<::capnp::primitive_list::Builder<'a,u32>> {
+          ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(6), ::core::option::Option::None)
+        }
+        #[inline]
+        pub fn set_counts32(&mut self, value: ::capnp::primitive_list::Reader<'a,u32>) -> ::capnp::Result<()> {
+          ::capnp::traits::SetPointerBuilder::set_pointer_builder(self.builder.get_pointer_field(6), value, false)
+        }
+        #[inline]
+        pub fn init_counts32(self, size: u32) -> ::capnp::primitive_list::Builder<'a,u32> {
+          ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(6), size)
+        }
+        pub fn has_counts32(&self) -> bool {
+          !self.builder.get_pointer_field(6).is_null()
+        }
+        #[inline]
+        pub fn get_num_valid_kmers(self) -> u64 {
+          self.builder.get_data_field::<u64>(2)
+        }
+        #[inline]
+        pub fn set_num_valid_kmers(&mut self, value: u64)  {
+          self.builder.set_data_field::<u64>(2, value);
+        }
+      }
+
+      pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
+      impl ::capnp::capability::FromTypelessPipeline for Pipeline {
+        fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
+          Pipeline { _typeless: typeless,  }
+        }
+      }
+      impl Pipeline  {
+      }
+      mod _private {
+        use capnp::private::layout;
+        pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 3, pointers: 7 };
+        pub const TYPE_ID: u64 = 0x96c3_ea4c_bfe1_43bf;
+      }
+    }
+  }
+
+  pub mod locus_list {
+    #[derive(Copy, Clone)]
+    pub struct Owned(());
+    impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
+    impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
+    impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
+
+    #[derive(Clone, Copy)]
+    pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
+
+    impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,>  {
+      #[inline]
+      fn type_id() -> u64 { _private::TYPE_ID }
+    }
+    impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,>  {
+      fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
+        Reader { reader,  }
+      }
+    }
+
+    impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,>  {
+      fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
+        ::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
+      }
+    }
+
+    impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,>  {
+      fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
+        self.reader
+      }
+    }
+
+    impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,>  {
+      fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
+        self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
+      }
+    }
+
+    impl <'a,> Reader<'a,>  {
+      pub fn reborrow(&self) -> Reader<'_,> {
+        Reader { .. *self }
+      }
+
+      pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
+        self.reader.total_size()
+      }
+      #[inline]
+      pub fn get_loci(self) -> ::capnp::Result<::capnp::struct_list::Reader<'a,crate::serialization::mash_capnp::min_hash::locus_list::locus::Owned>> {
+        ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0), ::core::option::Option::None)
+      }
+      pub fn has_loci(&self) -> bool {
+        !self.reader.get_pointer_field(0).is_null()
+      }
+    }
+
+    pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
+    impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,>  {
+      #[inline]
+      fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
+    }
+    impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,>  {
+      #[inline]
+      fn type_id() -> u64 { _private::TYPE_ID }
+    }
+    impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,>  {
+      fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
+        Builder { builder,  }
+      }
+    }
+
+    impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,>  {
+      fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
+        self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
+      }
+    }
+
+    impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,>  {
+      fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
+        ::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
+      }
+      fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
+        ::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
+      }
+    }
+
+    impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,>  {
+      fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
+    }
+
+    impl <'a,> Builder<'a,>  {
+      pub fn into_reader(self) -> Reader<'a,> {
+        ::capnp::traits::FromStructReader::new(self.builder.into_reader())
+      }
+      pub fn reborrow(&mut self) -> Builder<'_,> {
+        Builder { .. *self }
+      }
+      pub fn reborrow_as_reader(&self) -> Reader<'_,> {
+        ::capnp::traits::FromStructReader::new(self.builder.into_reader())
+      }
+
+      pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
+        self.builder.into_reader().total_size()
+      }
+      #[inline]
+      pub fn get_loci(self) -> ::capnp::Result<::capnp::struct_list::Builder<'a,crate::serialization::mash_capnp::min_hash::locus_list::locus::Owned>> {
+        ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0), ::core::option::Option::None)
+      }
+      #[inline]
+      pub fn set_loci(&mut self, value: ::capnp::struct_list::Reader<'a,crate::serialization::mash_capnp::min_hash::locus_list::locus::Owned>) -> ::capnp::Result<()> {
+        ::capnp::traits::SetPointerBuilder::set_pointer_builder(self.builder.get_pointer_field(0), value, false)
+      }
+      #[inline]
+      pub fn init_loci(self, size: u32) -> ::capnp::struct_list::Builder<'a,crate::serialization::mash_capnp::min_hash::locus_list::locus::Owned> {
+        ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(0), size)
+      }
+      pub fn has_loci(&self) -> bool {
+        !self.builder.get_pointer_field(0).is_null()
+      }
+    }
+
+    pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
+    impl ::capnp::capability::FromTypelessPipeline for Pipeline {
+      fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
+        Pipeline { _typeless: typeless,  }
+      }
+    }
+    impl Pipeline  {
+    }
+    mod _private {
+      use capnp::private::layout;
+      pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 0, pointers: 1 };
+      pub const TYPE_ID: u64 = 0xe1dd_f186_e2b3_59dd;
+    }
+
+    pub mod locus {
+      #[derive(Copy, Clone)]
+      pub struct Owned(());
+      impl <'a> ::capnp::traits::Owned<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
+      impl <'a> ::capnp::traits::OwnedStruct<'a> for Owned { type Reader = Reader<'a>; type Builder = Builder<'a>; }
+      impl ::capnp::traits::Pipelined for Owned { type Pipeline = Pipeline; }
+
+      #[derive(Clone, Copy)]
+      pub struct Reader<'a> { reader: ::capnp::private::layout::StructReader<'a> }
+
+      impl <'a,> ::capnp::traits::HasTypeId for Reader<'a,>  {
+        #[inline]
+        fn type_id() -> u64 { _private::TYPE_ID }
+      }
+      impl <'a,> ::capnp::traits::FromStructReader<'a> for Reader<'a,>  {
+        fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a,> {
+          Reader { reader,  }
+        }
+      }
+
+      impl <'a,> ::capnp::traits::FromPointerReader<'a> for Reader<'a,>  {
+        fn get_from_pointer(reader: &::capnp::private::layout::PointerReader<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Reader<'a,>> {
+          ::core::result::Result::Ok(::capnp::traits::FromStructReader::new(reader.get_struct(default)?))
+        }
+      }
+
+      impl <'a,> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a,>  {
+        fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
+          self.reader
+        }
+      }
+
+      impl <'a,> ::capnp::traits::Imbue<'a> for Reader<'a,>  {
+        fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
+          self.reader.imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
+        }
+      }
+
+      impl <'a,> Reader<'a,>  {
+        pub fn reborrow(&self) -> Reader<'_,> {
+          Reader { .. *self }
+        }
+
+        pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
+          self.reader.total_size()
+        }
+        #[inline]
+        pub fn get_sequence(self) -> u32 {
+          self.reader.get_data_field::<u32>(0)
+        }
+        #[inline]
+        pub fn get_position(self) -> u32 {
+          self.reader.get_data_field::<u32>(1)
+        }
+        #[inline]
+        pub fn get_hash32(self) -> u32 {
+          self.reader.get_data_field::<u32>(2)
+        }
+        #[inline]
+        pub fn get_hash64(self) -> u64 {
+          self.reader.get_data_field::<u64>(2)
+        }
+      }
+
+      pub struct Builder<'a> { builder: ::capnp::private::layout::StructBuilder<'a> }
+      impl <'a,> ::capnp::traits::HasStructSize for Builder<'a,>  {
+        #[inline]
+        fn struct_size() -> ::capnp::private::layout::StructSize { _private::STRUCT_SIZE }
+      }
+      impl <'a,> ::capnp::traits::HasTypeId for Builder<'a,>  {
+        #[inline]
+        fn type_id() -> u64 { _private::TYPE_ID }
+      }
+      impl <'a,> ::capnp::traits::FromStructBuilder<'a> for Builder<'a,>  {
+        fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a, > {
+          Builder { builder,  }
+        }
+      }
+
+      impl <'a,> ::capnp::traits::ImbueMut<'a> for Builder<'a,>  {
+        fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
+          self.builder.imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
+        }
+      }
+
+      impl <'a,> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a,>  {
+        fn init_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, _size: u32) -> Builder<'a,> {
+          ::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
+        }
+        fn get_from_pointer(builder: ::capnp::private::layout::PointerBuilder<'a>, default: ::core::option::Option<&'a [capnp::Word]>) -> ::capnp::Result<Builder<'a,>> {
+          ::core::result::Result::Ok(::capnp::traits::FromStructBuilder::new(builder.get_struct(_private::STRUCT_SIZE, default)?))
+        }
+      }
+
+      impl <'a,> ::capnp::traits::SetPointerBuilder for Reader<'a,>  {
+        fn set_pointer_builder<'b>(pointer: ::capnp::private::layout::PointerBuilder<'b>, value: Reader<'a,>, canonicalize: bool) -> ::capnp::Result<()> { pointer.set_struct(&value.reader, canonicalize) }
+      }
+
+      impl <'a,> Builder<'a,>  {
+        pub fn into_reader(self) -> Reader<'a,> {
+          ::capnp::traits::FromStructReader::new(self.builder.into_reader())
+        }
+        pub fn reborrow(&mut self) -> Builder<'_,> {
+          Builder { .. *self }
+        }
+        pub fn reborrow_as_reader(&self) -> Reader<'_,> {
+          ::capnp::traits::FromStructReader::new(self.builder.into_reader())
+        }
+
+        pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
+          self.builder.into_reader().total_size()
+        }
+        #[inline]
+        pub fn get_sequence(self) -> u32 {
+          self.builder.get_data_field::<u32>(0)
+        }
+        #[inline]
+        pub fn set_sequence(&mut self, value: u32)  {
+          self.builder.set_data_field::<u32>(0, value);
+        }
+        #[inline]
+        pub fn get_position(self) -> u32 {
+          self.builder.get_data_field::<u32>(1)
+        }
+        #[inline]
+        pub fn set_position(&mut self, value: u32)  {
+          self.builder.set_data_field::<u32>(1, value);
+        }
+        #[inline]
+        pub fn get_hash32(self) -> u32 {
+          self.builder.get_data_field::<u32>(2)
+        }
+        #[inline]
+        pub fn set_hash32(&mut self, value: u32)  {
+          self.builder.set_data_field::<u32>(2, value);
+        }
+        #[inline]
+        pub fn get_hash64(self) -> u64 {
+          self.builder.get_data_field::<u64>(2)
+        }
+        #[inline]
+        pub fn set_hash64(&mut self, value: u64)  {
+          self.builder.set_data_field::<u64>(2, value);
+        }
+      }
+
+      pub struct Pipeline { _typeless: ::capnp::any_pointer::Pipeline }
+      impl ::capnp::capability::FromTypelessPipeline for Pipeline {
+        fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
+          Pipeline { _typeless: typeless,  }
+        }
+      }
+      impl Pipeline  {
+      }
+      mod _private {
+        use capnp::private::layout;
+        pub const STRUCT_SIZE: layout::StructSize = layout::StructSize { data: 3, pointers: 0 };
+        pub const TYPE_ID: u64 = 0xa648_d718_8f22_59f6;
+      }
+    }
+  }
+}
diff --git a/src/serialization/mod.rs b/lib/src/serialization/mod.rs
similarity index 94%
rename from src/serialization/mod.rs
rename to lib/src/serialization/mod.rs
index 37e1a4f..94b31fe 100644
--- a/src/serialization/mod.rs
+++ b/lib/src/serialization/mod.rs
@@ -1,28 +1,28 @@
-// Compile the capnp schema with `capnp compile ./src/serialization/finch.capnp -orust`
-//
-// paths are broken so you need `%s/::finch_capnp::/super::/g`; see:
-// https://github.com/capnproto/capnproto-rust/issues/16
-//
-// also add the following to disable most warnings:
-// #![allow(clippy::all)]
-// #![allow(dead_code)]
+// Those 2 files are generated so we just ignore everything in terms
+#[allow(clippy::all)]
+#[allow(dead_code)]
+#[cfg_attr(rustfmt, rustfmt_skip)]
 mod finch_capnp;
+#[allow(clippy::all)]
+#[allow(dead_code)]
+#[cfg_attr(rustfmt, rustfmt_skip)]
+mod mash_capnp;
 
 mod json;
 mod mash;
-mod mash_capnp;
 
 use std::io::{BufRead, Write};
 
 use capnp::message;
 use capnp::serialize as capnp_serialize;
+use serde::{Deserialize, Serialize};
 
+use crate::errors::FinchResult;
 use crate::filtering::FilterParams;
 use crate::serialization::finch_capnp::{multisketch, sketch_params, SketchMethod};
 pub use crate::serialization::json::{JsonSketch, MultiSketch};
 pub use crate::serialization::mash::{read_mash_file, write_mash_file};
 use crate::sketch_schemes::{KmerCount, SketchParams};
-use crate::Result;
 
 pub const FINCH_EXT: &str = ".sk";
 pub const FINCH_BIN_EXT: &str = ".bsk";
@@ -111,7 +111,7 @@ fn set_sketch_params(mut cap_sketch_params: sketch_params::Builder, sketch_param
     }
 }
 
-fn get_sketch_params(cap_sketch_params: sketch_params::Reader) -> Result<SketchParams> {
+fn get_sketch_params(cap_sketch_params: sketch_params::Reader) -> FinchResult<SketchParams> {
     Ok(match cap_sketch_params.get_sketch_method()? {
         SketchMethod::MurmurHash3 => SketchParams::Mash {
             kmers_to_sketch: cap_sketch_params.get_kmers_to_sketch() as usize,
@@ -132,7 +132,7 @@ fn get_sketch_params(cap_sketch_params: sketch_params::Reader) -> Result<SketchP
     })
 }
 
-pub fn write_finch_file(mut file: &mut dyn Write, sketches: &[Sketch]) -> Result<()> {
+pub fn write_finch_file(mut file: &mut dyn Write, sketches: &[Sketch]) -> FinchResult<()> {
     let mut message = message::Builder::new_default();
     let finch_file: multisketch::Builder = message.init_root::<multisketch::Builder>();
 
@@ -182,8 +182,8 @@ pub fn write_finch_file(mut file: &mut dyn Write, sketches: &[Sketch]) -> Result
     Ok(())
 }
 
-pub fn read_finch_file(mut file: &mut dyn BufRead) -> Result<Vec<Sketch>> {
-    let options = *message::ReaderOptions::new().traversal_limit_in_words(1024 * 1024 * 1024);
+pub fn read_finch_file(mut file: &mut dyn BufRead) -> FinchResult<Vec<Sketch>> {
+    let options = *message::ReaderOptions::new().traversal_limit_in_words(Some(1024 * 1024 * 1024));
     let reader = capnp_serialize::read_message(&mut file, options)?;
     let cap_data: multisketch::Reader = reader.get_root::<multisketch::Reader>()?;
     let cap_sketches = cap_data.get_sketches()?;
diff --git a/src/sketch_schemes/counts.rs b/lib/src/sketch_schemes/counts.rs
similarity index 96%
rename from src/sketch_schemes/counts.rs
rename to lib/src/sketch_schemes/counts.rs
index d1ecd85..24ce38c 100644
--- a/src/sketch_schemes/counts.rs
+++ b/lib/src/sketch_schemes/counts.rs
@@ -1,7 +1,8 @@
 use needletail::bitkmer::{bitmer_to_bytes, reverse_complement};
-use needletail::{Sequence, SequenceRecord};
+use needletail::Sequence;
 
 use crate::sketch_schemes::{KmerCount, SketchParams, SketchScheme};
+use needletail::parser::SequenceRecord;
 
 #[derive(Clone)]
 pub struct AllCountsSketcher {
diff --git a/src/sketch_schemes/hashing.rs b/lib/src/sketch_schemes/hashing.rs
similarity index 100%
rename from src/sketch_schemes/hashing.rs
rename to lib/src/sketch_schemes/hashing.rs
diff --git a/src/sketch_schemes/mash.rs b/lib/src/sketch_schemes/mash.rs
similarity index 97%
rename from src/sketch_schemes/mash.rs
rename to lib/src/sketch_schemes/mash.rs
index 8f4efab..c094657 100644
--- a/src/sketch_schemes/mash.rs
+++ b/lib/src/sketch_schemes/mash.rs
@@ -2,10 +2,11 @@ use std::collections::{BinaryHeap, HashMap};
 use std::hash::BuildHasherDefault;
 use std::usize;
 
-use needletail::{Sequence, SequenceRecord};
+use needletail::Sequence;
 
 use crate::sketch_schemes::hashing::{hash_f, HashedItem, NoHashHasher};
 use crate::sketch_schemes::{ItemHash, KmerCount, SketchParams, SketchScheme};
+use needletail::parser::SequenceRecord;
 
 #[derive(Clone, Debug)]
 pub struct MashSketcher {
@@ -66,7 +67,7 @@ impl MashSketcher {
 
 impl SketchScheme for MashSketcher {
     fn process(&mut self, seq: SequenceRecord) {
-        self.total_bases += seq.seq.len() as u64;
+        self.total_bases += seq.sequence().len() as u64;
         let rc = seq.reverse_complement();
         for (_, kmer, is_rev_complement) in
             seq.normalize(false).canonical_kmers(self.kmer_length, &rc)
diff --git a/src/sketch_schemes/mod.rs b/lib/src/sketch_schemes/mod.rs
similarity index 98%
rename from src/sketch_schemes/mod.rs
rename to lib/src/sketch_schemes/mod.rs
index 939d6aa..3db41cd 100644
--- a/src/sketch_schemes/mod.rs
+++ b/lib/src/sketch_schemes/mod.rs
@@ -3,12 +3,13 @@ mod hashing;
 pub mod mash;
 pub mod scaled;
 
-use failure::bail;
-use needletail::SequenceRecord;
+use needletail::parser::SequenceRecord;
+use serde::{Deserialize, Serialize};
 
+use crate::bail;
+use crate::errors::FinchResult;
 use crate::filtering::FilterParams;
 use crate::serialization::Sketch;
-use crate::Result as FinchResult;
 pub use hashing::ItemHash;
 
 #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Hash, Serialize)]
diff --git a/src/sketch_schemes/scaled.rs b/lib/src/sketch_schemes/scaled.rs
similarity index 98%
rename from src/sketch_schemes/scaled.rs
rename to lib/src/sketch_schemes/scaled.rs
index fdae06d..a319f31 100644
--- a/src/sketch_schemes/scaled.rs
+++ b/lib/src/sketch_schemes/scaled.rs
@@ -2,10 +2,11 @@ use std::collections::{BinaryHeap, HashMap};
 use std::hash::BuildHasherDefault;
 use std::usize;
 
-use needletail::{Sequence, SequenceRecord};
+use needletail::Sequence;
 
 use crate::sketch_schemes::hashing::{hash_f, HashedItem, NoHashHasher};
 use crate::sketch_schemes::{ItemHash, KmerCount, SketchParams, SketchScheme};
+use needletail::parser::SequenceRecord;
 
 #[derive(Clone, Debug)]
 pub struct ScaledSketcher {
@@ -65,7 +66,7 @@ impl ScaledSketcher {
 
 impl SketchScheme for ScaledSketcher {
     fn process(&mut self, seq: SequenceRecord) {
-        self.total_bases += seq.seq.len() as u64;
+        self.total_bases += seq.sequence().len() as u64;
         let rc = seq.reverse_complement();
         for (_, kmer, is_rev_complement) in
             seq.normalize(false).canonical_kmers(self.kmer_length, &rc)
diff --git a/src/statistics.rs b/lib/src/statistics.rs
similarity index 100%
rename from src/statistics.rs
rename to lib/src/statistics.rs
diff --git a/src/main.rs b/src/main.rs
deleted file mode 100644
index be5f792..0000000
--- a/src/main.rs
+++ /dev/null
@@ -1,461 +0,0 @@
-#[macro_use]
-extern crate clap;
-#[macro_use]
-extern crate failure;
-extern crate finch;
-extern crate serde_json;
-
-use std::collections::{HashMap, HashSet};
-use std::fs::File;
-use std::io::{stderr, stdout, Write};
-use std::process::exit;
-
-use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
-
-use finch::distance::distance;
-use finch::serialization::{
-    write_finch_file, write_mash_file, MultiSketch, Sketch, SketchDistance, FINCH_BIN_EXT,
-    FINCH_EXT, MASH_EXT,
-};
-use finch::statistics::{cardinality, hist};
-use finch::{open_sketch_file, sketch_files, Result};
-
-use finch::main_parsing::{
-    add_filter_options, add_sketch_options, get_float_arg, get_int_arg, parse_filter_options,
-    parse_sketch_options, update_sketch_params,
-};
-
-fn add_output_options<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> {
-    app.arg(
-        Arg::with_name("output_file")
-            .short("o")
-            .long("output")
-            .help("Output to this file")
-            .takes_value(true),
-    )
-    .arg(
-        Arg::with_name("std_out")
-            .short("O")
-            .long("std-out")
-            .help("Output to stdout ('print to terminal')")
-            .conflicts_with("output_file"),
-    )
-}
-
-fn output_to<F>(output_fn: F, output: Option<&str>, extension: &str) -> Result<()>
-where
-    F: Fn(&mut dyn Write) -> Result<()>,
-{
-    match output {
-        None => {
-            let mut out = stdout();
-            output_fn(&mut out)?;
-        }
-        Some(o) => {
-            // if the filename doesn't have the right extension
-            // add it on
-            let filename = String::from(o);
-            let out_filename = if filename.ends_with(extension) {
-                filename
-            } else {
-                filename + extension
-            };
-
-            let mut out = File::create(&out_filename)
-                .map_err(|_| format_err!("Could not create {}", out_filename))?;
-            output_fn(&mut out)?;
-        }
-    };
-    Ok(())
-}
-
-fn main() {
-    // see https://github.com/rust-lang-nursery/failure/issues/76
-    if let Err(err) = run() {
-        let mut serr = stderr();
-        let mut causes = err.iter_chain();
-        writeln!(
-            serr,
-            "Error: {}",
-            causes.next().expect("`causes` to at least contain `err`")
-        )
-        .expect("unable to write error to stderr");
-        for cause in causes {
-            writeln!(serr, "Caused by: {}", cause).expect("unable to write error to stderr");
-        }
-        // The following assumes an `Error`, use `if let Some(backtrace) ...` for a `Fail`
-        write!(serr, "{:?}", err.backtrace()).expect("unable to write error to stderr");
-        exit(1);
-    }
-}
-
-fn run() -> Result<()> {
-    let mut sketch_command = SubCommand::with_name("sketch")
-        .about("Create sketches from FASTA/Q file(s)")
-        .arg(
-            Arg::with_name("INPUT")
-                .help("The file(s) to sketch")
-                .multiple(true)
-                .required(true),
-        )
-        .arg(
-            Arg::with_name("binary_format")
-                .short("b")
-                .long("finch-binary-format")
-                .help("Outputs sketch to a finch-native binary format"),
-        )
-        .arg(
-            Arg::with_name("mash_binary_format")
-                .short("B")
-                .long("mash-binary-format")
-                .conflicts_with("binary_format")
-                .help("Outputs sketch in a binary format compatible with `mash`"),
-        );
-    sketch_command = add_output_options(sketch_command);
-    sketch_command = add_filter_options(sketch_command);
-    sketch_command = add_sketch_options(sketch_command);
-
-    let mut dist_command = SubCommand::with_name("dist")
-        .about("Compute distances between sketches")
-        .arg(
-            Arg::with_name("INPUT")
-                .help("Sketchfile(s) to make comparisons for")
-                .multiple(true)
-                .required(true),
-        )
-        .arg(
-            Arg::with_name("pairwise")
-                .short("p")
-                .long("pairwise")
-                .conflicts_with("queries")
-                .help("Calculate distances between all sketches"),
-        )
-        .arg(
-            Arg::with_name("queries")
-                .short("q")
-                .long("queries")
-                .help("All distances are from these sketches (sketches must be in the first file)")
-                .multiple(true)
-                .conflicts_with("pairwise")
-                .takes_value(true),
-        )
-        .arg(
-            Arg::with_name("max_distance")
-                .short("d")
-                .long("max-dist")
-                .help("Only report distances under this threshold")
-                .default_value("1.0")
-                .takes_value(true),
-        )
-        .arg(
-            Arg::with_name("old_dist_mode")
-                .long("old-dist")
-                .help("Calculate distances using the old containment-biased Finch mode"),
-        );
-    dist_command = add_output_options(dist_command);
-    dist_command = add_filter_options(dist_command);
-    dist_command = add_sketch_options(dist_command);
-
-    let mut hist_command = SubCommand::with_name("hist")
-        .about("Display histograms of kmer abundances")
-        .arg(
-            Arg::with_name("INPUT")
-                .help("Generate histograms from these file(s)")
-                .multiple(true)
-                .required(true),
-        );
-    hist_command = add_output_options(hist_command);
-    hist_command = add_filter_options(hist_command);
-    hist_command = add_sketch_options(hist_command);
-
-    let mut info_command = SubCommand::with_name("info")
-        .about("Display basic statistics")
-        .arg(
-            Arg::with_name("INPUT")
-                .help("Return stats on these file(s)")
-                .multiple(true)
-                .required(true),
-        );
-    info_command = add_output_options(info_command);
-    info_command = add_filter_options(info_command);
-    info_command = add_sketch_options(info_command);
-
-    let matches = App::new("finch")
-        .version(crate_version!())
-        .author(crate_authors!())
-        .about("Tool for working with genomic MinHash sketches")
-        .setting(AppSettings::VersionlessSubcommands)
-        .setting(AppSettings::ArgRequiredElseHelp)
-        .subcommand(sketch_command)
-        .subcommand(dist_command)
-        .subcommand(hist_command)
-        .subcommand(info_command)
-        .get_matches();
-
-    if let Some(matches) = matches.subcommand_matches("sketch") {
-        let file_ext = if matches.is_present("binary_format") {
-            FINCH_BIN_EXT
-        } else if matches.is_present("mash_binary_format") {
-            MASH_EXT
-        } else {
-            FINCH_EXT
-        };
-        if matches.is_present("output_file") || matches.is_present("std_out") {
-            let sketches = parse_mash_files(matches)?;
-            let output = matches.value_of("output_file");
-
-            output_to(
-                |writer| {
-                    if matches.is_present("binary_format") {
-                        write_finch_file(writer, &sketches)?;
-                    } else if matches.is_present("mash_binary_format") {
-                        write_mash_file(writer, &sketches)?;
-                    } else {
-                        let multisketch = MultiSketch::from_sketches(&sketches)?;
-                        serde_json::to_writer(writer, &multisketch)?;
-                    }
-                    Ok(())
-                },
-                output,
-                &file_ext,
-            )?;
-        } else {
-            // special case for "sketching in place"
-            generate_sketch_files(matches, file_ext)?;
-        }
-    } else if let Some(matches) = matches.subcommand_matches("dist") {
-        let old_mode = matches.is_present("old_dist_mode");
-
-        let max_dist = get_float_arg(matches, "max_distance", 1f64)?;
-        let all_sketches = parse_mash_files(matches)?;
-
-        let mut query_sketches = Vec::new();
-        if matches.is_present("pairwise") {
-            for sketch in &all_sketches {
-                query_sketches.push(sketch);
-            }
-        } else if matches.is_present("queries") {
-            let query_names: HashSet<String> = matches
-                .values_of("queries")
-                .unwrap() // we already know it's present
-                .map(|s| s.to_string())
-                .collect();
-
-            for sketch in &all_sketches {
-                if query_names.contains(&sketch.name) {
-                    query_sketches.push(&sketch);
-                }
-            }
-        } else {
-            if all_sketches.is_empty() {
-                bail!("No sketches present!");
-            }
-            query_sketches.push(all_sketches.first().unwrap());
-        }
-
-        let distances = calc_sketch_distances(&query_sketches, &all_sketches, old_mode, max_dist);
-
-        output_to(
-            |writer| {
-                serde_json::to_writer(writer, &distances)
-                    .map_err(|_| format_err!("Could not serialize JSON to file"))?;
-                Ok(())
-            },
-            matches.value_of("output_file"),
-            ".json",
-        )?;
-    } else if let Some(matches) = matches.subcommand_matches("hist") {
-        let mut hist_map: HashMap<String, Vec<u64>> = HashMap::new();
-        let multisketch = parse_mash_files(matches)?;
-
-        for sketch in multisketch {
-            hist_map.insert(sketch.name.to_string(), hist(&sketch.hashes));
-        }
-
-        output_to(
-            |writer| {
-                serde_json::to_writer(writer, &hist_map)
-                    .map_err(|_| format_err!("Could not serialize JSON to file"))?;
-                Ok(())
-            },
-            matches.value_of("output_file"),
-            ".json",
-        )?;
-    } else if let Some(matches) = matches.subcommand_matches("info") {
-        // TODO: this should probably output JSON
-        let multisketch = parse_mash_files(matches)?;
-
-        for sketch in multisketch {
-            print!("{}", &sketch.name);
-            println!(" (from {}bp)", sketch.seq_length);
-            let kmers = &sketch.hashes;
-            if let Ok(c) = cardinality(kmers) {
-                println!("  Estimated # of Unique Kmers: {}", c);
-            }
-
-            let histogram = hist(kmers);
-            let mean = histogram
-                .iter()
-                .enumerate()
-                .map(|(i, v)| ((i as f32 + 1f32) * *v as f32, *v as f32))
-                .fold((0f32, 0f32), |e, s| (e.0 + s.0, e.1 + s.1));
-            println!("  Estimated Average Depth: {}x", mean.0 / mean.1);
-
-            let mut total_gc: u64 = 0;
-            for kmer in kmers {
-                total_gc += kmer
-                    .kmer
-                    .iter()
-                    .map(|b| match *b {
-                        b'G' | b'g' | b'C' | b'c' => u64::from(kmer.count),
-                        _ => 0,
-                    })
-                    .sum::<u64>();
-            }
-            let total_bases = if kmers.is_empty() {
-                0f32
-            } else {
-                mean.0 * kmers[0].kmer.len() as f32
-            };
-            println!(
-                "  Estimated % GC: {}%",
-                100f32 * total_gc as f32 / total_bases
-            );
-        }
-    }
-    Ok(())
-}
-
-fn generate_sketch_files(matches: &ArgMatches, file_ext: &str) -> Result<()> {
-    let filenames: Vec<_> = matches
-        .values_of("INPUT")
-        .ok_or_else(|| format_err!("Bad INPUT"))?
-        .collect();
-
-    let kmer_length: u8 = get_int_arg(matches, "kmer_length")?;
-    let filters = parse_filter_options(matches, kmer_length)?;
-    let sketch_params = parse_sketch_options(matches, kmer_length, filters.filter_on)?;
-
-    for filename in filenames {
-        if filename.ends_with(".json")
-            || filename.ends_with(FINCH_EXT)
-            || filename.ends_with(FINCH_BIN_EXT)
-            || filename.ends_with(MASH_EXT)
-        {
-            bail!("Filename {} is not a sequence file?", filename);
-        }
-
-        let sketches = sketch_files(&[filename], &sketch_params, &filters)?;
-
-        let out_filename = filename.to_string() + file_ext;
-        let mut out = File::create(&out_filename)
-            .map_err(|_| format_err!("Could not open {}", out_filename))?;
-        if matches.is_present("binary_format") {
-            write_finch_file(&mut out, &sketches)?;
-        } else if matches.is_present("mash_binary_format") {
-            write_mash_file(&mut out, &sketches)?;
-        } else {
-            let multisketch: MultiSketch = MultiSketch::from_sketches(&sketches)?;
-            serde_json::to_writer(&mut out, &multisketch)?;
-        }
-    }
-    Ok(())
-}
-
-fn parse_mash_files(matches: &ArgMatches) -> Result<Vec<Sketch>> {
-    let filenames: Vec<_> = matches
-        .values_of("INPUT")
-        .ok_or_else(|| format_err!("Bad INPUT"))?
-        .collect();
-
-    let mut sketch_filenames = Vec::new();
-    let mut seq_filenames = Vec::new();
-    for filename in filenames {
-        if filename.ends_with(".json")
-            || filename.ends_with(FINCH_EXT)
-            || filename.ends_with(FINCH_BIN_EXT)
-            || filename.ends_with(MASH_EXT)
-        {
-            sketch_filenames.push(filename);
-        } else {
-            seq_filenames.push(filename);
-        }
-    }
-
-    let kmer_length: u8 = get_int_arg(matches, "kmer_length")?;
-    let mut filters = parse_filter_options(matches, kmer_length)?;
-    let mut sketch_params = parse_sketch_options(matches, kmer_length, filters.filter_on)?;
-
-    let mut filename_iter = sketch_filenames.iter();
-    if let Some(first_filename) = filename_iter.next() {
-        let mut sketches = open_sketch_file(first_filename)?;
-
-        update_sketch_params(matches, &mut sketch_params, &sketches[0], first_filename)?;
-        // we also have to handle updating filter options separately because
-        // kmer_length changes how we calculate the `err_filter`
-        if matches.occurrences_of("kmer_length") == 0 {
-            filters = parse_filter_options(matches, sketch_params.k())?;
-        }
-
-        // now do the filtering for the first sketch file
-        if filters.filter_on == Some(true) {
-            for mut sketch in &mut sketches {
-                filters.filter_sketch(&mut sketch);
-            }
-        }
-
-        // and then handle the rest of the sketch files
-        for filename in filename_iter {
-            let extra_sketches = open_sketch_file(filename)?;
-            // check new sketches are compatible with original file
-            for sketch in &extra_sketches {
-                if let Some((name, v1, v2)) =
-                    sketch_params.check_compatibility(&sketch.sketch_params)
-                {
-                    bail!(
-                        "Sketch {} has {} {}, but working value is {}",
-                        sketch.name,
-                        name,
-                        v2,
-                        v1,
-                    );
-                }
-            }
-            sketches.extend(extra_sketches);
-            if filters.filter_on == Some(true) {
-                for mut sketch in &mut sketches {
-                    filters.filter_sketch(&mut sketch);
-                }
-            }
-        }
-
-        // now handle the sequences
-        let extra_sketches = sketch_files(&seq_filenames, &sketch_params, &filters)?;
-        sketches.extend(extra_sketches);
-        Ok(sketches)
-    } else {
-        // now handle the sequences
-        sketch_files(&seq_filenames, &sketch_params, &filters)
-    }
-}
-
-fn calc_sketch_distances(
-    query_sketches: &[&Sketch],
-    ref_sketches: &[Sketch],
-    old_mode: bool,
-    max_distance: f64,
-) -> Vec<SketchDistance> {
-    let mut distances = Vec::new();
-    for ref_sketch in ref_sketches {
-        for query_sketch in query_sketches {
-            if query_sketch == &ref_sketch {
-                continue;
-            }
-            let distance = distance(&query_sketch, &ref_sketch, old_mode).unwrap();
-            if distance.mash_distance <= max_distance {
-                distances.push(distance);
-            }
-        }
-    }
-    distances
-}
diff --git a/src/serialization/finch_capnp.rs b/src/serialization/finch_capnp.rs
deleted file mode 100644
index 853775e..0000000
--- a/src/serialization/finch_capnp.rs
+++ /dev/null
@@ -1,1291 +0,0 @@
-// Generated by the capnpc-rust plugin to the Cap'n Proto schema compiler.
-// DO NOT EDIT.
-// source: src/serialization/finch.capnp
-#![allow(clippy::all)]
-#![allow(dead_code)]
-
-#[repr(u16)]
-#[derive(Clone, Copy, PartialEq)]
-pub enum SketchMethod {
-    MurmurHash3 = 0,
-    MurmurHash3Scaled = 1,
-    None = 2,
-}
-impl ::capnp::traits::FromU16 for SketchMethod {
-    #[inline]
-    fn from_u16(value: u16) -> ::std::result::Result<SketchMethod, ::capnp::NotInSchema> {
-        match value {
-            0 => ::std::result::Result::Ok(SketchMethod::MurmurHash3),
-            1 => ::std::result::Result::Ok(SketchMethod::MurmurHash3Scaled),
-            2 => ::std::result::Result::Ok(SketchMethod::None),
-            n => ::std::result::Result::Err(::capnp::NotInSchema(n)),
-        }
-    }
-}
-impl ::capnp::traits::ToU16 for SketchMethod {
-    #[inline]
-    fn to_u16(self) -> u16 {
-        self as u16
-    }
-}
-impl ::capnp::traits::HasTypeId for SketchMethod {
-    #[inline]
-    fn type_id() -> u64 {
-        0xf922_f4db_1e0b_2eaau64
-    }
-}
-
-pub mod filter_params {
-    #[derive(Copy, Clone)]
-    pub struct Owned;
-    impl<'a> ::capnp::traits::Owned<'a> for Owned {
-        type Reader = Reader<'a>;
-        type Builder = Builder<'a>;
-    }
-    impl<'a> ::capnp::traits::OwnedStruct<'a> for Owned {
-        type Reader = Reader<'a>;
-        type Builder = Builder<'a>;
-    }
-    impl ::capnp::traits::Pipelined for Owned {
-        type Pipeline = Pipeline;
-    }
-
-    #[derive(Clone, Copy)]
-    pub struct Reader<'a> {
-        reader: ::capnp::private::layout::StructReader<'a>,
-    }
-
-    impl<'a> ::capnp::traits::HasTypeId for Reader<'a> {
-        #[inline]
-        fn type_id() -> u64 {
-            _private::TYPE_ID
-        }
-    }
-    impl<'a> ::capnp::traits::FromStructReader<'a> for Reader<'a> {
-        fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a> {
-            Reader { reader: reader }
-        }
-    }
-
-    impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> {
-        fn get_from_pointer(
-            reader: &::capnp::private::layout::PointerReader<'a>,
-        ) -> ::capnp::Result<Reader<'a>> {
-            ::std::result::Result::Ok(::capnp::traits::FromStructReader::new(
-                reader.get_struct(::std::ptr::null())?,
-            ))
-        }
-    }
-
-    impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> {
-        fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
-            self.reader
-        }
-    }
-
-    impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> {
-        fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
-            self.reader
-                .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
-        }
-    }
-
-    impl<'a> Reader<'a> {
-        pub fn reborrow(&self) -> Reader {
-            Reader { ..*self }
-        }
-
-        pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
-            self.reader.total_size()
-        }
-        #[inline]
-        pub fn get_filtered(self) -> bool {
-            self.reader.get_bool_field(0)
-        }
-        #[inline]
-        pub fn get_low_abun_filter(self) -> u32 {
-            self.reader.get_data_field::<u32>(1)
-        }
-        #[inline]
-        pub fn get_high_abun_filter(self) -> u32 {
-            self.reader.get_data_field::<u32>(2)
-        }
-        #[inline]
-        pub fn get_err_filter(self) -> f64 {
-            self.reader.get_data_field::<f64>(2)
-        }
-        #[inline]
-        pub fn get_strand_filter(self) -> f64 {
-            self.reader.get_data_field::<f64>(3)
-        }
-    }
-
-    pub struct Builder<'a> {
-        builder: ::capnp::private::layout::StructBuilder<'a>,
-    }
-    impl<'a> ::capnp::traits::HasStructSize for Builder<'a> {
-        #[inline]
-        fn struct_size() -> ::capnp::private::layout::StructSize {
-            _private::STRUCT_SIZE
-        }
-    }
-    impl<'a> ::capnp::traits::HasTypeId for Builder<'a> {
-        #[inline]
-        fn type_id() -> u64 {
-            _private::TYPE_ID
-        }
-    }
-    impl<'a> ::capnp::traits::FromStructBuilder<'a> for Builder<'a> {
-        fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a> {
-            Builder { builder: builder }
-        }
-    }
-
-    impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> {
-        fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
-            self.builder
-                .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
-        }
-    }
-
-    impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> {
-        fn init_pointer(
-            builder: ::capnp::private::layout::PointerBuilder<'a>,
-            _size: u32,
-        ) -> Builder<'a> {
-            ::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
-        }
-        fn get_from_pointer(
-            builder: ::capnp::private::layout::PointerBuilder<'a>,
-        ) -> ::capnp::Result<Builder<'a>> {
-            ::std::result::Result::Ok(::capnp::traits::FromStructBuilder::new(
-                builder.get_struct(_private::STRUCT_SIZE, ::std::ptr::null())?,
-            ))
-        }
-    }
-
-    impl<'a> ::capnp::traits::SetPointerBuilder<Builder<'a>> for Reader<'a> {
-        fn set_pointer_builder<'b>(
-            pointer: ::capnp::private::layout::PointerBuilder<'b>,
-            value: Reader<'a>,
-            canonicalize: bool,
-        ) -> ::capnp::Result<()> {
-            pointer.set_struct(&value.reader, canonicalize)
-        }
-    }
-
-    impl<'a> Builder<'a> {
-        #[deprecated(since = "0.9.2", note = "use into_reader()")]
-        pub fn as_reader(self) -> Reader<'a> {
-            self.into_reader()
-        }
-        pub fn into_reader(self) -> Reader<'a> {
-            ::capnp::traits::FromStructReader::new(self.builder.into_reader())
-        }
-        pub fn reborrow(&mut self) -> Builder {
-            Builder { ..*self }
-        }
-        pub fn reborrow_as_reader(&self) -> Reader {
-            ::capnp::traits::FromStructReader::new(self.builder.into_reader())
-        }
-
-        pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
-            self.builder.into_reader().total_size()
-        }
-        #[inline]
-        pub fn get_filtered(self) -> bool {
-            self.builder.get_bool_field(0)
-        }
-        #[inline]
-        pub fn set_filtered(&mut self, value: bool) {
-            self.builder.set_bool_field(0, value);
-        }
-        #[inline]
-        pub fn get_low_abun_filter(self) -> u32 {
-            self.builder.get_data_field::<u32>(1)
-        }
-        #[inline]
-        pub fn set_low_abun_filter(&mut self, value: u32) {
-            self.builder.set_data_field::<u32>(1, value);
-        }
-        #[inline]
-        pub fn get_high_abun_filter(self) -> u32 {
-            self.builder.get_data_field::<u32>(2)
-        }
-        #[inline]
-        pub fn set_high_abun_filter(&mut self, value: u32) {
-            self.builder.set_data_field::<u32>(2, value);
-        }
-        #[inline]
-        pub fn get_err_filter(self) -> f64 {
-            self.builder.get_data_field::<f64>(2)
-        }
-        #[inline]
-        pub fn set_err_filter(&mut self, value: f64) {
-            self.builder.set_data_field::<f64>(2, value);
-        }
-        #[inline]
-        pub fn get_strand_filter(self) -> f64 {
-            self.builder.get_data_field::<f64>(3)
-        }
-        #[inline]
-        pub fn set_strand_filter(&mut self, value: f64) {
-            self.builder.set_data_field::<f64>(3, value);
-        }
-    }
-
-    pub struct Pipeline {
-        _typeless: ::capnp::any_pointer::Pipeline,
-    }
-    impl ::capnp::capability::FromTypelessPipeline for Pipeline {
-        fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
-            Pipeline {
-                _typeless: typeless,
-            }
-        }
-    }
-    impl Pipeline {}
-    mod _private {
-        use capnp::private::layout;
-        pub const STRUCT_SIZE: layout::StructSize = layout::StructSize {
-            data: 4,
-            pointers: 0,
-        };
-        pub const TYPE_ID: u64 = 0x8dff_64f8_81c9_51eb;
-    }
-}
-
-pub mod sketch_params {
-    #[derive(Copy, Clone)]
-    pub struct Owned;
-    impl<'a> ::capnp::traits::Owned<'a> for Owned {
-        type Reader = Reader<'a>;
-        type Builder = Builder<'a>;
-    }
-    impl<'a> ::capnp::traits::OwnedStruct<'a> for Owned {
-        type Reader = Reader<'a>;
-        type Builder = Builder<'a>;
-    }
-    impl ::capnp::traits::Pipelined for Owned {
-        type Pipeline = Pipeline;
-    }
-
-    #[derive(Clone, Copy)]
-    pub struct Reader<'a> {
-        reader: ::capnp::private::layout::StructReader<'a>,
-    }
-
-    impl<'a> ::capnp::traits::HasTypeId for Reader<'a> {
-        #[inline]
-        fn type_id() -> u64 {
-            _private::TYPE_ID
-        }
-    }
-    impl<'a> ::capnp::traits::FromStructReader<'a> for Reader<'a> {
-        fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a> {
-            Reader { reader: reader }
-        }
-    }
-
-    impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> {
-        fn get_from_pointer(
-            reader: &::capnp::private::layout::PointerReader<'a>,
-        ) -> ::capnp::Result<Reader<'a>> {
-            ::std::result::Result::Ok(::capnp::traits::FromStructReader::new(
-                reader.get_struct(::std::ptr::null())?,
-            ))
-        }
-    }
-
-    impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> {
-        fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
-            self.reader
-        }
-    }
-
-    impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> {
-        fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
-            self.reader
-                .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
-        }
-    }
-
-    impl<'a> Reader<'a> {
-        pub fn reborrow(&self) -> Reader {
-            Reader { ..*self }
-        }
-
-        pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
-            self.reader.total_size()
-        }
-        #[inline]
-        pub fn get_sketch_method(
-            self,
-        ) -> ::std::result::Result<super::SketchMethod, ::capnp::NotInSchema> {
-            ::capnp::traits::FromU16::from_u16(self.reader.get_data_field::<u16>(0))
-        }
-        #[inline]
-        pub fn get_kmer_length(self) -> u8 {
-            self.reader.get_data_field::<u8>(2)
-        }
-        #[inline]
-        pub fn get_kmers_to_sketch(self) -> u64 {
-            self.reader.get_data_field::<u64>(1)
-        }
-        #[inline]
-        pub fn get_hash_seed(self) -> u64 {
-            self.reader.get_data_field::<u64>(2)
-        }
-        #[inline]
-        pub fn get_final_size(self) -> u64 {
-            self.reader.get_data_field::<u64>(3)
-        }
-        #[inline]
-        pub fn get_no_strict(self) -> bool {
-            self.reader.get_bool_field(24)
-        }
-        #[inline]
-        pub fn get_scale(self) -> f64 {
-            self.reader.get_data_field::<f64>(4)
-        }
-    }
-
-    pub struct Builder<'a> {
-        builder: ::capnp::private::layout::StructBuilder<'a>,
-    }
-    impl<'a> ::capnp::traits::HasStructSize for Builder<'a> {
-        #[inline]
-        fn struct_size() -> ::capnp::private::layout::StructSize {
-            _private::STRUCT_SIZE
-        }
-    }
-    impl<'a> ::capnp::traits::HasTypeId for Builder<'a> {
-        #[inline]
-        fn type_id() -> u64 {
-            _private::TYPE_ID
-        }
-    }
-    impl<'a> ::capnp::traits::FromStructBuilder<'a> for Builder<'a> {
-        fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a> {
-            Builder { builder: builder }
-        }
-    }
-
-    impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> {
-        fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
-            self.builder
-                .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
-        }
-    }
-
-    impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> {
-        fn init_pointer(
-            builder: ::capnp::private::layout::PointerBuilder<'a>,
-            _size: u32,
-        ) -> Builder<'a> {
-            ::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
-        }
-        fn get_from_pointer(
-            builder: ::capnp::private::layout::PointerBuilder<'a>,
-        ) -> ::capnp::Result<Builder<'a>> {
-            ::std::result::Result::Ok(::capnp::traits::FromStructBuilder::new(
-                builder.get_struct(_private::STRUCT_SIZE, ::std::ptr::null())?,
-            ))
-        }
-    }
-
-    impl<'a> ::capnp::traits::SetPointerBuilder<Builder<'a>> for Reader<'a> {
-        fn set_pointer_builder<'b>(
-            pointer: ::capnp::private::layout::PointerBuilder<'b>,
-            value: Reader<'a>,
-            canonicalize: bool,
-        ) -> ::capnp::Result<()> {
-            pointer.set_struct(&value.reader, canonicalize)
-        }
-    }
-
-    impl<'a> Builder<'a> {
-        #[deprecated(since = "0.9.2", note = "use into_reader()")]
-        pub fn as_reader(self) -> Reader<'a> {
-            self.into_reader()
-        }
-        pub fn into_reader(self) -> Reader<'a> {
-            ::capnp::traits::FromStructReader::new(self.builder.into_reader())
-        }
-        pub fn reborrow(&mut self) -> Builder {
-            Builder { ..*self }
-        }
-        pub fn reborrow_as_reader(&self) -> Reader {
-            ::capnp::traits::FromStructReader::new(self.builder.into_reader())
-        }
-
-        pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
-            self.builder.into_reader().total_size()
-        }
-        #[inline]
-        pub fn get_sketch_method(
-            self,
-        ) -> ::std::result::Result<super::SketchMethod, ::capnp::NotInSchema> {
-            ::capnp::traits::FromU16::from_u16(self.builder.get_data_field::<u16>(0))
-        }
-        #[inline]
-        pub fn set_sketch_method(&mut self, value: super::SketchMethod) {
-            self.builder.set_data_field::<u16>(0, value as u16)
-        }
-        #[inline]
-        pub fn get_kmer_length(self) -> u8 {
-            self.builder.get_data_field::<u8>(2)
-        }
-        #[inline]
-        pub fn set_kmer_length(&mut self, value: u8) {
-            self.builder.set_data_field::<u8>(2, value);
-        }
-        #[inline]
-        pub fn get_kmers_to_sketch(self) -> u64 {
-            self.builder.get_data_field::<u64>(1)
-        }
-        #[inline]
-        pub fn set_kmers_to_sketch(&mut self, value: u64) {
-            self.builder.set_data_field::<u64>(1, value);
-        }
-        #[inline]
-        pub fn get_hash_seed(self) -> u64 {
-            self.builder.get_data_field::<u64>(2)
-        }
-        #[inline]
-        pub fn set_hash_seed(&mut self, value: u64) {
-            self.builder.set_data_field::<u64>(2, value);
-        }
-        #[inline]
-        pub fn get_final_size(self) -> u64 {
-            self.builder.get_data_field::<u64>(3)
-        }
-        #[inline]
-        pub fn set_final_size(&mut self, value: u64) {
-            self.builder.set_data_field::<u64>(3, value);
-        }
-        #[inline]
-        pub fn get_no_strict(self) -> bool {
-            self.builder.get_bool_field(24)
-        }
-        #[inline]
-        pub fn set_no_strict(&mut self, value: bool) {
-            self.builder.set_bool_field(24, value);
-        }
-        #[inline]
-        pub fn get_scale(self) -> f64 {
-            self.builder.get_data_field::<f64>(4)
-        }
-        #[inline]
-        pub fn set_scale(&mut self, value: f64) {
-            self.builder.set_data_field::<f64>(4, value);
-        }
-    }
-
-    pub struct Pipeline {
-        _typeless: ::capnp::any_pointer::Pipeline,
-    }
-    impl ::capnp::capability::FromTypelessPipeline for Pipeline {
-        fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
-            Pipeline {
-                _typeless: typeless,
-            }
-        }
-    }
-    impl Pipeline {}
-    mod _private {
-        use capnp::private::layout;
-        pub const STRUCT_SIZE: layout::StructSize = layout::StructSize {
-            data: 5,
-            pointers: 0,
-        };
-        pub const TYPE_ID: u64 = 0xf3cd_d237_a53c_a546;
-    }
-}
-
-pub mod kmer_count {
-    #[derive(Copy, Clone)]
-    pub struct Owned;
-    impl<'a> ::capnp::traits::Owned<'a> for Owned {
-        type Reader = Reader<'a>;
-        type Builder = Builder<'a>;
-    }
-    impl<'a> ::capnp::traits::OwnedStruct<'a> for Owned {
-        type Reader = Reader<'a>;
-        type Builder = Builder<'a>;
-    }
-    impl ::capnp::traits::Pipelined for Owned {
-        type Pipeline = Pipeline;
-    }
-
-    #[derive(Clone, Copy)]
-    pub struct Reader<'a> {
-        reader: ::capnp::private::layout::StructReader<'a>,
-    }
-
-    impl<'a> ::capnp::traits::HasTypeId for Reader<'a> {
-        #[inline]
-        fn type_id() -> u64 {
-            _private::TYPE_ID
-        }
-    }
-    impl<'a> ::capnp::traits::FromStructReader<'a> for Reader<'a> {
-        fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a> {
-            Reader { reader: reader }
-        }
-    }
-
-    impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> {
-        fn get_from_pointer(
-            reader: &::capnp::private::layout::PointerReader<'a>,
-        ) -> ::capnp::Result<Reader<'a>> {
-            ::std::result::Result::Ok(::capnp::traits::FromStructReader::new(
-                reader.get_struct(::std::ptr::null())?,
-            ))
-        }
-    }
-
-    impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> {
-        fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
-            self.reader
-        }
-    }
-
-    impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> {
-        fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
-            self.reader
-                .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
-        }
-    }
-
-    impl<'a> Reader<'a> {
-        pub fn reborrow(&self) -> Reader {
-            Reader { ..*self }
-        }
-
-        pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
-            self.reader.total_size()
-        }
-        #[inline]
-        pub fn get_hash(self) -> u64 {
-            self.reader.get_data_field::<u64>(0)
-        }
-        #[inline]
-        pub fn get_kmer(self) -> ::capnp::Result<::capnp::data::Reader<'a>> {
-            self.reader
-                .get_pointer_field(0)
-                .get_data(::std::ptr::null(), 0)
-        }
-        pub fn has_kmer(&self) -> bool {
-            !self.reader.get_pointer_field(0).is_null()
-        }
-        #[inline]
-        pub fn get_count(self) -> u32 {
-            self.reader.get_data_field::<u32>(2)
-        }
-        #[inline]
-        pub fn get_extra_count(self) -> u32 {
-            self.reader.get_data_field::<u32>(3)
-        }
-        #[inline]
-        pub fn get_label(self) -> ::capnp::Result<::capnp::data::Reader<'a>> {
-            self.reader
-                .get_pointer_field(1)
-                .get_data(::std::ptr::null(), 0)
-        }
-        pub fn has_label(&self) -> bool {
-            !self.reader.get_pointer_field(1).is_null()
-        }
-    }
-
-    pub struct Builder<'a> {
-        builder: ::capnp::private::layout::StructBuilder<'a>,
-    }
-    impl<'a> ::capnp::traits::HasStructSize for Builder<'a> {
-        #[inline]
-        fn struct_size() -> ::capnp::private::layout::StructSize {
-            _private::STRUCT_SIZE
-        }
-    }
-    impl<'a> ::capnp::traits::HasTypeId for Builder<'a> {
-        #[inline]
-        fn type_id() -> u64 {
-            _private::TYPE_ID
-        }
-    }
-    impl<'a> ::capnp::traits::FromStructBuilder<'a> for Builder<'a> {
-        fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a> {
-            Builder { builder: builder }
-        }
-    }
-
-    impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> {
-        fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
-            self.builder
-                .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
-        }
-    }
-
-    impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> {
-        fn init_pointer(
-            builder: ::capnp::private::layout::PointerBuilder<'a>,
-            _size: u32,
-        ) -> Builder<'a> {
-            ::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
-        }
-        fn get_from_pointer(
-            builder: ::capnp::private::layout::PointerBuilder<'a>,
-        ) -> ::capnp::Result<Builder<'a>> {
-            ::std::result::Result::Ok(::capnp::traits::FromStructBuilder::new(
-                builder.get_struct(_private::STRUCT_SIZE, ::std::ptr::null())?,
-            ))
-        }
-    }
-
-    impl<'a> ::capnp::traits::SetPointerBuilder<Builder<'a>> for Reader<'a> {
-        fn set_pointer_builder<'b>(
-            pointer: ::capnp::private::layout::PointerBuilder<'b>,
-            value: Reader<'a>,
-            canonicalize: bool,
-        ) -> ::capnp::Result<()> {
-            pointer.set_struct(&value.reader, canonicalize)
-        }
-    }
-
-    impl<'a> Builder<'a> {
-        #[deprecated(since = "0.9.2", note = "use into_reader()")]
-        pub fn as_reader(self) -> Reader<'a> {
-            self.into_reader()
-        }
-        pub fn into_reader(self) -> Reader<'a> {
-            ::capnp::traits::FromStructReader::new(self.builder.into_reader())
-        }
-        pub fn reborrow(&mut self) -> Builder {
-            Builder { ..*self }
-        }
-        pub fn reborrow_as_reader(&self) -> Reader {
-            ::capnp::traits::FromStructReader::new(self.builder.into_reader())
-        }
-
-        pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
-            self.builder.into_reader().total_size()
-        }
-        #[inline]
-        pub fn get_hash(self) -> u64 {
-            self.builder.get_data_field::<u64>(0)
-        }
-        #[inline]
-        pub fn set_hash(&mut self, value: u64) {
-            self.builder.set_data_field::<u64>(0, value);
-        }
-        #[inline]
-        pub fn get_kmer(self) -> ::capnp::Result<::capnp::data::Builder<'a>> {
-            self.builder
-                .get_pointer_field(0)
-                .get_data(::std::ptr::null(), 0)
-        }
-        #[inline]
-        pub fn set_kmer(&mut self, value: ::capnp::data::Reader) {
-            self.builder.get_pointer_field(0).set_data(value);
-        }
-        #[inline]
-        pub fn init_kmer(self, size: u32) -> ::capnp::data::Builder<'a> {
-            self.builder.get_pointer_field(0).init_data(size)
-        }
-        pub fn has_kmer(&self) -> bool {
-            !self.builder.get_pointer_field(0).is_null()
-        }
-        #[inline]
-        pub fn get_count(self) -> u32 {
-            self.builder.get_data_field::<u32>(2)
-        }
-        #[inline]
-        pub fn set_count(&mut self, value: u32) {
-            self.builder.set_data_field::<u32>(2, value);
-        }
-        #[inline]
-        pub fn get_extra_count(self) -> u32 {
-            self.builder.get_data_field::<u32>(3)
-        }
-        #[inline]
-        pub fn set_extra_count(&mut self, value: u32) {
-            self.builder.set_data_field::<u32>(3, value);
-        }
-        #[inline]
-        pub fn get_label(self) -> ::capnp::Result<::capnp::data::Builder<'a>> {
-            self.builder
-                .get_pointer_field(1)
-                .get_data(::std::ptr::null(), 0)
-        }
-        #[inline]
-        pub fn set_label(&mut self, value: ::capnp::data::Reader) {
-            self.builder.get_pointer_field(1).set_data(value);
-        }
-        #[inline]
-        pub fn init_label(self, size: u32) -> ::capnp::data::Builder<'a> {
-            self.builder.get_pointer_field(1).init_data(size)
-        }
-        pub fn has_label(&self) -> bool {
-            !self.builder.get_pointer_field(1).is_null()
-        }
-    }
-
-    pub struct Pipeline {
-        _typeless: ::capnp::any_pointer::Pipeline,
-    }
-    impl ::capnp::capability::FromTypelessPipeline for Pipeline {
-        fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
-            Pipeline {
-                _typeless: typeless,
-            }
-        }
-    }
-    impl Pipeline {}
-    mod _private {
-        use capnp::private::layout;
-        pub const STRUCT_SIZE: layout::StructSize = layout::StructSize {
-            data: 2,
-            pointers: 2,
-        };
-        pub const TYPE_ID: u64 = 0x854e_abfe_76ab_932c;
-    }
-}
-
-pub mod sketch {
-    #[derive(Copy, Clone)]
-    pub struct Owned;
-    impl<'a> ::capnp::traits::Owned<'a> for Owned {
-        type Reader = Reader<'a>;
-        type Builder = Builder<'a>;
-    }
-    impl<'a> ::capnp::traits::OwnedStruct<'a> for Owned {
-        type Reader = Reader<'a>;
-        type Builder = Builder<'a>;
-    }
-    impl ::capnp::traits::Pipelined for Owned {
-        type Pipeline = Pipeline;
-    }
-
-    #[derive(Clone, Copy)]
-    pub struct Reader<'a> {
-        reader: ::capnp::private::layout::StructReader<'a>,
-    }
-
-    impl<'a> ::capnp::traits::HasTypeId for Reader<'a> {
-        #[inline]
-        fn type_id() -> u64 {
-            _private::TYPE_ID
-        }
-    }
-    impl<'a> ::capnp::traits::FromStructReader<'a> for Reader<'a> {
-        fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a> {
-            Reader { reader: reader }
-        }
-    }
-
-    impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> {
-        fn get_from_pointer(
-            reader: &::capnp::private::layout::PointerReader<'a>,
-        ) -> ::capnp::Result<Reader<'a>> {
-            ::std::result::Result::Ok(::capnp::traits::FromStructReader::new(
-                reader.get_struct(::std::ptr::null())?,
-            ))
-        }
-    }
-
-    impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> {
-        fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
-            self.reader
-        }
-    }
-
-    impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> {
-        fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
-            self.reader
-                .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
-        }
-    }
-
-    impl<'a> Reader<'a> {
-        pub fn reborrow(&self) -> Reader {
-            Reader { ..*self }
-        }
-
-        pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
-            self.reader.total_size()
-        }
-        #[inline]
-        pub fn get_name(self) -> ::capnp::Result<::capnp::text::Reader<'a>> {
-            self.reader
-                .get_pointer_field(0)
-                .get_text(::std::ptr::null(), 0)
-        }
-        pub fn has_name(&self) -> bool {
-            !self.reader.get_pointer_field(0).is_null()
-        }
-        #[inline]
-        pub fn get_seq_length(self) -> u64 {
-            self.reader.get_data_field::<u64>(0)
-        }
-        #[inline]
-        pub fn get_num_valid_kmers(self) -> u64 {
-            self.reader.get_data_field::<u64>(1)
-        }
-        #[inline]
-        pub fn get_comment(self) -> ::capnp::Result<::capnp::text::Reader<'a>> {
-            self.reader
-                .get_pointer_field(1)
-                .get_text(::std::ptr::null(), 0)
-        }
-        pub fn has_comment(&self) -> bool {
-            !self.reader.get_pointer_field(1).is_null()
-        }
-        #[inline]
-        pub fn get_hashes(
-            self,
-        ) -> ::capnp::Result<::capnp::struct_list::Reader<'a, super::kmer_count::Owned>> {
-            ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(2))
-        }
-        pub fn has_hashes(&self) -> bool {
-            !self.reader.get_pointer_field(2).is_null()
-        }
-        #[inline]
-        pub fn get_filter_params(self) -> ::capnp::Result<super::filter_params::Reader<'a>> {
-            ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(3))
-        }
-        pub fn has_filter_params(&self) -> bool {
-            !self.reader.get_pointer_field(3).is_null()
-        }
-        #[inline]
-        pub fn get_sketch_params(self) -> ::capnp::Result<super::sketch_params::Reader<'a>> {
-            ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(4))
-        }
-        pub fn has_sketch_params(&self) -> bool {
-            !self.reader.get_pointer_field(4).is_null()
-        }
-    }
-
-    pub struct Builder<'a> {
-        builder: ::capnp::private::layout::StructBuilder<'a>,
-    }
-    impl<'a> ::capnp::traits::HasStructSize for Builder<'a> {
-        #[inline]
-        fn struct_size() -> ::capnp::private::layout::StructSize {
-            _private::STRUCT_SIZE
-        }
-    }
-    impl<'a> ::capnp::traits::HasTypeId for Builder<'a> {
-        #[inline]
-        fn type_id() -> u64 {
-            _private::TYPE_ID
-        }
-    }
-    impl<'a> ::capnp::traits::FromStructBuilder<'a> for Builder<'a> {
-        fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a> {
-            Builder { builder: builder }
-        }
-    }
-
-    impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> {
-        fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
-            self.builder
-                .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
-        }
-    }
-
-    impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> {
-        fn init_pointer(
-            builder: ::capnp::private::layout::PointerBuilder<'a>,
-            _size: u32,
-        ) -> Builder<'a> {
-            ::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
-        }
-        fn get_from_pointer(
-            builder: ::capnp::private::layout::PointerBuilder<'a>,
-        ) -> ::capnp::Result<Builder<'a>> {
-            ::std::result::Result::Ok(::capnp::traits::FromStructBuilder::new(
-                builder.get_struct(_private::STRUCT_SIZE, ::std::ptr::null())?,
-            ))
-        }
-    }
-
-    impl<'a> ::capnp::traits::SetPointerBuilder<Builder<'a>> for Reader<'a> {
-        fn set_pointer_builder<'b>(
-            pointer: ::capnp::private::layout::PointerBuilder<'b>,
-            value: Reader<'a>,
-            canonicalize: bool,
-        ) -> ::capnp::Result<()> {
-            pointer.set_struct(&value.reader, canonicalize)
-        }
-    }
-
-    impl<'a> Builder<'a> {
-        #[deprecated(since = "0.9.2", note = "use into_reader()")]
-        pub fn as_reader(self) -> Reader<'a> {
-            self.into_reader()
-        }
-        pub fn into_reader(self) -> Reader<'a> {
-            ::capnp::traits::FromStructReader::new(self.builder.into_reader())
-        }
-        pub fn reborrow(&mut self) -> Builder {
-            Builder { ..*self }
-        }
-        pub fn reborrow_as_reader(&self) -> Reader {
-            ::capnp::traits::FromStructReader::new(self.builder.into_reader())
-        }
-
-        pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
-            self.builder.into_reader().total_size()
-        }
-        #[inline]
-        pub fn get_name(self) -> ::capnp::Result<::capnp::text::Builder<'a>> {
-            self.builder
-                .get_pointer_field(0)
-                .get_text(::std::ptr::null(), 0)
-        }
-        #[inline]
-        pub fn set_name(&mut self, value: ::capnp::text::Reader) {
-            self.builder.get_pointer_field(0).set_text(value);
-        }
-        #[inline]
-        pub fn init_name(self, size: u32) -> ::capnp::text::Builder<'a> {
-            self.builder.get_pointer_field(0).init_text(size)
-        }
-        pub fn has_name(&self) -> bool {
-            !self.builder.get_pointer_field(0).is_null()
-        }
-        #[inline]
-        pub fn get_seq_length(self) -> u64 {
-            self.builder.get_data_field::<u64>(0)
-        }
-        #[inline]
-        pub fn set_seq_length(&mut self, value: u64) {
-            self.builder.set_data_field::<u64>(0, value);
-        }
-        #[inline]
-        pub fn get_num_valid_kmers(self) -> u64 {
-            self.builder.get_data_field::<u64>(1)
-        }
-        #[inline]
-        pub fn set_num_valid_kmers(&mut self, value: u64) {
-            self.builder.set_data_field::<u64>(1, value);
-        }
-        #[inline]
-        pub fn get_comment(self) -> ::capnp::Result<::capnp::text::Builder<'a>> {
-            self.builder
-                .get_pointer_field(1)
-                .get_text(::std::ptr::null(), 0)
-        }
-        #[inline]
-        pub fn set_comment(&mut self, value: ::capnp::text::Reader) {
-            self.builder.get_pointer_field(1).set_text(value);
-        }
-        #[inline]
-        pub fn init_comment(self, size: u32) -> ::capnp::text::Builder<'a> {
-            self.builder.get_pointer_field(1).init_text(size)
-        }
-        pub fn has_comment(&self) -> bool {
-            !self.builder.get_pointer_field(1).is_null()
-        }
-        #[inline]
-        pub fn get_hashes(
-            self,
-        ) -> ::capnp::Result<::capnp::struct_list::Builder<'a, super::kmer_count::Owned>> {
-            ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(2))
-        }
-        #[inline]
-        pub fn set_hashes(
-            &mut self,
-            value: ::capnp::struct_list::Reader<'a, super::kmer_count::Owned>,
-        ) -> ::capnp::Result<()> {
-            ::capnp::traits::SetPointerBuilder::set_pointer_builder(
-                self.builder.get_pointer_field(2),
-                value,
-                false,
-            )
-        }
-        #[inline]
-        pub fn init_hashes(
-            self,
-            size: u32,
-        ) -> ::capnp::struct_list::Builder<'a, super::kmer_count::Owned> {
-            ::capnp::traits::FromPointerBuilder::init_pointer(
-                self.builder.get_pointer_field(2),
-                size,
-            )
-        }
-        pub fn has_hashes(&self) -> bool {
-            !self.builder.get_pointer_field(2).is_null()
-        }
-        #[inline]
-        pub fn get_filter_params(self) -> ::capnp::Result<super::filter_params::Builder<'a>> {
-            ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(3))
-        }
-        #[inline]
-        pub fn set_filter_params<'b>(
-            &mut self,
-            value: super::filter_params::Reader<'b>,
-        ) -> ::capnp::Result<()> {
-            ::capnp::traits::SetPointerBuilder::set_pointer_builder(
-                self.builder.get_pointer_field(3),
-                value,
-                false,
-            )
-        }
-        #[inline]
-        pub fn init_filter_params(self) -> super::filter_params::Builder<'a> {
-            ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(3), 0)
-        }
-        pub fn has_filter_params(&self) -> bool {
-            !self.builder.get_pointer_field(3).is_null()
-        }
-        #[inline]
-        pub fn get_sketch_params(self) -> ::capnp::Result<super::sketch_params::Builder<'a>> {
-            ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(4))
-        }
-        #[inline]
-        pub fn set_sketch_params<'b>(
-            &mut self,
-            value: super::sketch_params::Reader<'b>,
-        ) -> ::capnp::Result<()> {
-            ::capnp::traits::SetPointerBuilder::set_pointer_builder(
-                self.builder.get_pointer_field(4),
-                value,
-                false,
-            )
-        }
-        #[inline]
-        pub fn init_sketch_params(self) -> super::sketch_params::Builder<'a> {
-            ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(4), 0)
-        }
-        pub fn has_sketch_params(&self) -> bool {
-            !self.builder.get_pointer_field(4).is_null()
-        }
-    }
-
-    pub struct Pipeline {
-        _typeless: ::capnp::any_pointer::Pipeline,
-    }
-    impl ::capnp::capability::FromTypelessPipeline for Pipeline {
-        fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
-            Pipeline {
-                _typeless: typeless,
-            }
-        }
-    }
-    impl Pipeline {
-        pub fn get_filter_params(&self) -> super::filter_params::Pipeline {
-            ::capnp::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field(3))
-        }
-        pub fn get_sketch_params(&self) -> super::sketch_params::Pipeline {
-            ::capnp::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field(4))
-        }
-    }
-    mod _private {
-        use capnp::private::layout;
-        pub const STRUCT_SIZE: layout::StructSize = layout::StructSize {
-            data: 2,
-            pointers: 5,
-        };
-        pub const TYPE_ID: u64 = 0xb602_150b_6621_a020;
-    }
-}
-
-pub mod multisketch {
-    #[derive(Copy, Clone)]
-    pub struct Owned;
-    impl<'a> ::capnp::traits::Owned<'a> for Owned {
-        type Reader = Reader<'a>;
-        type Builder = Builder<'a>;
-    }
-    impl<'a> ::capnp::traits::OwnedStruct<'a> for Owned {
-        type Reader = Reader<'a>;
-        type Builder = Builder<'a>;
-    }
-    impl ::capnp::traits::Pipelined for Owned {
-        type Pipeline = Pipeline;
-    }
-
-    #[derive(Clone, Copy)]
-    pub struct Reader<'a> {
-        reader: ::capnp::private::layout::StructReader<'a>,
-    }
-
-    impl<'a> ::capnp::traits::HasTypeId for Reader<'a> {
-        #[inline]
-        fn type_id() -> u64 {
-            _private::TYPE_ID
-        }
-    }
-    impl<'a> ::capnp::traits::FromStructReader<'a> for Reader<'a> {
-        fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a> {
-            Reader { reader: reader }
-        }
-    }
-
-    impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> {
-        fn get_from_pointer(
-            reader: &::capnp::private::layout::PointerReader<'a>,
-        ) -> ::capnp::Result<Reader<'a>> {
-            ::std::result::Result::Ok(::capnp::traits::FromStructReader::new(
-                reader.get_struct(::std::ptr::null())?,
-            ))
-        }
-    }
-
-    impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> {
-        fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
-            self.reader
-        }
-    }
-
-    impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> {
-        fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
-            self.reader
-                .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
-        }
-    }
-
-    impl<'a> Reader<'a> {
-        pub fn reborrow(&self) -> Reader {
-            Reader { ..*self }
-        }
-
-        pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
-            self.reader.total_size()
-        }
-        #[inline]
-        pub fn get_sketches(
-            self,
-        ) -> ::capnp::Result<::capnp::struct_list::Reader<'a, super::sketch::Owned>> {
-            ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0))
-        }
-        pub fn has_sketches(&self) -> bool {
-            !self.reader.get_pointer_field(0).is_null()
-        }
-    }
-
-    pub struct Builder<'a> {
-        builder: ::capnp::private::layout::StructBuilder<'a>,
-    }
-    impl<'a> ::capnp::traits::HasStructSize for Builder<'a> {
-        #[inline]
-        fn struct_size() -> ::capnp::private::layout::StructSize {
-            _private::STRUCT_SIZE
-        }
-    }
-    impl<'a> ::capnp::traits::HasTypeId for Builder<'a> {
-        #[inline]
-        fn type_id() -> u64 {
-            _private::TYPE_ID
-        }
-    }
-    impl<'a> ::capnp::traits::FromStructBuilder<'a> for Builder<'a> {
-        fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a> {
-            Builder { builder: builder }
-        }
-    }
-
-    impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> {
-        fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
-            self.builder
-                .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
-        }
-    }
-
-    impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> {
-        fn init_pointer(
-            builder: ::capnp::private::layout::PointerBuilder<'a>,
-            _size: u32,
-        ) -> Builder<'a> {
-            ::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
-        }
-        fn get_from_pointer(
-            builder: ::capnp::private::layout::PointerBuilder<'a>,
-        ) -> ::capnp::Result<Builder<'a>> {
-            ::std::result::Result::Ok(::capnp::traits::FromStructBuilder::new(
-                builder.get_struct(_private::STRUCT_SIZE, ::std::ptr::null())?,
-            ))
-        }
-    }
-
-    impl<'a> ::capnp::traits::SetPointerBuilder<Builder<'a>> for Reader<'a> {
-        fn set_pointer_builder<'b>(
-            pointer: ::capnp::private::layout::PointerBuilder<'b>,
-            value: Reader<'a>,
-            canonicalize: bool,
-        ) -> ::capnp::Result<()> {
-            pointer.set_struct(&value.reader, canonicalize)
-        }
-    }
-
-    impl<'a> Builder<'a> {
-        #[deprecated(since = "0.9.2", note = "use into_reader()")]
-        pub fn as_reader(self) -> Reader<'a> {
-            self.into_reader()
-        }
-        pub fn into_reader(self) -> Reader<'a> {
-            ::capnp::traits::FromStructReader::new(self.builder.into_reader())
-        }
-        pub fn reborrow(&mut self) -> Builder {
-            Builder { ..*self }
-        }
-        pub fn reborrow_as_reader(&self) -> Reader {
-            ::capnp::traits::FromStructReader::new(self.builder.into_reader())
-        }
-
-        pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
-            self.builder.into_reader().total_size()
-        }
-        #[inline]
-        pub fn get_sketches(
-            self,
-        ) -> ::capnp::Result<::capnp::struct_list::Builder<'a, super::sketch::Owned>> {
-            ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0))
-        }
-        #[inline]
-        pub fn set_sketches(
-            &mut self,
-            value: ::capnp::struct_list::Reader<'a, super::sketch::Owned>,
-        ) -> ::capnp::Result<()> {
-            ::capnp::traits::SetPointerBuilder::set_pointer_builder(
-                self.builder.get_pointer_field(0),
-                value,
-                false,
-            )
-        }
-        #[inline]
-        pub fn init_sketches(
-            self,
-            size: u32,
-        ) -> ::capnp::struct_list::Builder<'a, super::sketch::Owned> {
-            ::capnp::traits::FromPointerBuilder::init_pointer(
-                self.builder.get_pointer_field(0),
-                size,
-            )
-        }
-        pub fn has_sketches(&self) -> bool {
-            !self.builder.get_pointer_field(0).is_null()
-        }
-    }
-
-    pub struct Pipeline {
-        _typeless: ::capnp::any_pointer::Pipeline,
-    }
-    impl ::capnp::capability::FromTypelessPipeline for Pipeline {
-        fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
-            Pipeline {
-                _typeless: typeless,
-            }
-        }
-    }
-    impl Pipeline {}
-    mod _private {
-        use capnp::private::layout;
-        pub const STRUCT_SIZE: layout::StructSize = layout::StructSize {
-            data: 0,
-            pointers: 1,
-        };
-        pub const TYPE_ID: u64 = 0xe71d_cbc8_f49e_581a;
-    }
-}
diff --git a/src/serialization/mash_capnp.rs b/src/serialization/mash_capnp.rs
deleted file mode 100644
index b166207..0000000
--- a/src/serialization/mash_capnp.rs
+++ /dev/null
@@ -1,1484 +0,0 @@
-// Generated by the capnpc-rust plugin to the Cap'n Proto schema compiler.
-// DO NOT EDIT.
-// source: mash.capnp
-
-#![allow(clippy::all)]
-#![allow(dead_code)]
-pub mod min_hash {
-    #[derive(Copy, Clone)]
-    pub struct Owned;
-    impl<'a> ::capnp::traits::Owned<'a> for Owned {
-        type Reader = Reader<'a>;
-        type Builder = Builder<'a>;
-    }
-    impl<'a> ::capnp::traits::OwnedStruct<'a> for Owned {
-        type Reader = Reader<'a>;
-        type Builder = Builder<'a>;
-    }
-    impl ::capnp::traits::Pipelined for Owned {
-        type Pipeline = Pipeline;
-    }
-
-    #[derive(Clone, Copy)]
-    pub struct Reader<'a> {
-        reader: ::capnp::private::layout::StructReader<'a>,
-    }
-
-    impl<'a> ::capnp::traits::HasTypeId for Reader<'a> {
-        #[inline]
-        fn type_id() -> u64 {
-            _private::TYPE_ID
-        }
-    }
-    impl<'a> ::capnp::traits::FromStructReader<'a> for Reader<'a> {
-        fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a> {
-            Reader { reader: reader }
-        }
-    }
-
-    impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> {
-        fn get_from_pointer(
-            reader: &::capnp::private::layout::PointerReader<'a>,
-        ) -> ::capnp::Result<Reader<'a>> {
-            ::std::result::Result::Ok(::capnp::traits::FromStructReader::new(
-                reader.get_struct(::std::ptr::null())?,
-            ))
-        }
-    }
-
-    impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> {
-        fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
-            self.reader
-        }
-    }
-
-    impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> {
-        fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
-            self.reader
-                .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
-        }
-    }
-
-    impl<'a> Reader<'a> {
-        pub fn reborrow(&self) -> Reader {
-            Reader { ..*self }
-        }
-
-        pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
-            self.reader.total_size()
-        }
-        #[inline]
-        pub fn get_kmer_size(self) -> u32 {
-            self.reader.get_data_field::<u32>(0)
-        }
-        #[inline]
-        pub fn get_window_size(self) -> u32 {
-            self.reader.get_data_field::<u32>(1)
-        }
-        #[inline]
-        pub fn get_min_hashes_per_window(self) -> u32 {
-            self.reader.get_data_field::<u32>(2)
-        }
-        #[inline]
-        pub fn get_concatenated(self) -> bool {
-            self.reader.get_bool_field(96)
-        }
-        #[inline]
-        pub fn get_reference_list_old(
-            self,
-        ) -> ::capnp::Result<crate::serialization::mash_capnp::min_hash::reference_list::Reader<'a>>
-        {
-            ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(0))
-        }
-        pub fn has_reference_list_old(&self) -> bool {
-            !self.reader.get_pointer_field(0).is_null()
-        }
-        #[inline]
-        pub fn get_locus_list(
-            self,
-        ) -> ::capnp::Result<crate::serialization::mash_capnp::min_hash::locus_list::Reader<'a>>
-        {
-            ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(1))
-        }
-        pub fn has_locus_list(&self) -> bool {
-            !self.reader.get_pointer_field(1).is_null()
-        }
-        #[inline]
-        pub fn get_error(self) -> f32 {
-            self.reader.get_data_field::<f32>(4)
-        }
-        #[inline]
-        pub fn get_noncanonical(self) -> bool {
-            self.reader.get_bool_field(97)
-        }
-        #[inline]
-        pub fn get_alphabet(self) -> ::capnp::Result<::capnp::text::Reader<'a>> {
-            self.reader
-                .get_pointer_field(2)
-                .get_text(::std::ptr::null(), 0)
-        }
-        pub fn has_alphabet(&self) -> bool {
-            !self.reader.get_pointer_field(2).is_null()
-        }
-        #[inline]
-        pub fn get_preserve_case(self) -> bool {
-            self.reader.get_bool_field(98)
-        }
-        #[inline]
-        pub fn get_hash_seed(self) -> u32 {
-            self.reader.get_data_field_mask::<u32>(5, 42)
-        }
-        #[inline]
-        pub fn get_reference_list(
-            self,
-        ) -> ::capnp::Result<crate::serialization::mash_capnp::min_hash::reference_list::Reader<'a>>
-        {
-            ::capnp::traits::FromPointerReader::get_from_pointer(&self.reader.get_pointer_field(3))
-        }
-        pub fn has_reference_list(&self) -> bool {
-            !self.reader.get_pointer_field(3).is_null()
-        }
-    }
-
-    pub struct Builder<'a> {
-        builder: ::capnp::private::layout::StructBuilder<'a>,
-    }
-    impl<'a> ::capnp::traits::HasStructSize for Builder<'a> {
-        #[inline]
-        fn struct_size() -> ::capnp::private::layout::StructSize {
-            _private::STRUCT_SIZE
-        }
-    }
-    impl<'a> ::capnp::traits::HasTypeId for Builder<'a> {
-        #[inline]
-        fn type_id() -> u64 {
-            _private::TYPE_ID
-        }
-    }
-    impl<'a> ::capnp::traits::FromStructBuilder<'a> for Builder<'a> {
-        fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a> {
-            Builder { builder: builder }
-        }
-    }
-
-    impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> {
-        fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
-            self.builder
-                .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
-        }
-    }
-
-    impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> {
-        fn init_pointer(
-            builder: ::capnp::private::layout::PointerBuilder<'a>,
-            _size: u32,
-        ) -> Builder<'a> {
-            ::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
-        }
-        fn get_from_pointer(
-            builder: ::capnp::private::layout::PointerBuilder<'a>,
-        ) -> ::capnp::Result<Builder<'a>> {
-            ::std::result::Result::Ok(::capnp::traits::FromStructBuilder::new(
-                builder.get_struct(_private::STRUCT_SIZE, ::std::ptr::null())?,
-            ))
-        }
-    }
-
-    impl<'a> ::capnp::traits::SetPointerBuilder<Builder<'a>> for Reader<'a> {
-        fn set_pointer_builder<'b>(
-            pointer: ::capnp::private::layout::PointerBuilder<'b>,
-            value: Reader<'a>,
-            canonicalize: bool,
-        ) -> ::capnp::Result<()> {
-            pointer.set_struct(&value.reader, canonicalize)
-        }
-    }
-
-    impl<'a> Builder<'a> {
-        #[deprecated(since = "0.9.2", note = "use into_reader()")]
-        pub fn as_reader(self) -> Reader<'a> {
-            self.into_reader()
-        }
-        pub fn into_reader(self) -> Reader<'a> {
-            ::capnp::traits::FromStructReader::new(self.builder.into_reader())
-        }
-        pub fn reborrow(&mut self) -> Builder {
-            Builder { ..*self }
-        }
-        pub fn reborrow_as_reader(&self) -> Reader {
-            ::capnp::traits::FromStructReader::new(self.builder.into_reader())
-        }
-
-        pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
-            self.builder.into_reader().total_size()
-        }
-        #[inline]
-        pub fn get_kmer_size(self) -> u32 {
-            self.builder.get_data_field::<u32>(0)
-        }
-        #[inline]
-        pub fn set_kmer_size(&mut self, value: u32) {
-            self.builder.set_data_field::<u32>(0, value);
-        }
-        #[inline]
-        pub fn get_window_size(self) -> u32 {
-            self.builder.get_data_field::<u32>(1)
-        }
-        #[inline]
-        pub fn set_window_size(&mut self, value: u32) {
-            self.builder.set_data_field::<u32>(1, value);
-        }
-        #[inline]
-        pub fn get_min_hashes_per_window(self) -> u32 {
-            self.builder.get_data_field::<u32>(2)
-        }
-        #[inline]
-        pub fn set_min_hashes_per_window(&mut self, value: u32) {
-            self.builder.set_data_field::<u32>(2, value);
-        }
-        #[inline]
-        pub fn get_concatenated(self) -> bool {
-            self.builder.get_bool_field(96)
-        }
-        #[inline]
-        pub fn set_concatenated(&mut self, value: bool) {
-            self.builder.set_bool_field(96, value);
-        }
-        #[inline]
-        pub fn get_reference_list_old(
-            self,
-        ) -> ::capnp::Result<crate::serialization::mash_capnp::min_hash::reference_list::Builder<'a>>
-        {
-            ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(0))
-        }
-        #[inline]
-        pub fn set_reference_list_old<'b>(
-            &mut self,
-            value: crate::serialization::mash_capnp::min_hash::reference_list::Reader<'b>,
-        ) -> ::capnp::Result<()> {
-            ::capnp::traits::SetPointerBuilder::set_pointer_builder(
-                self.builder.get_pointer_field(0),
-                value,
-                false,
-            )
-        }
-        #[inline]
-        pub fn init_reference_list_old(
-            self,
-        ) -> crate::serialization::mash_capnp::min_hash::reference_list::Builder<'a> {
-            ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(0), 0)
-        }
-        pub fn has_reference_list_old(&self) -> bool {
-            !self.builder.get_pointer_field(0).is_null()
-        }
-        #[inline]
-        pub fn get_locus_list(
-            self,
-        ) -> ::capnp::Result<crate::serialization::mash_capnp::min_hash::locus_list::Builder<'a>>
-        {
-            ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(1))
-        }
-        #[inline]
-        pub fn set_locus_list<'b>(
-            &mut self,
-            value: crate::serialization::mash_capnp::min_hash::locus_list::Reader<'b>,
-        ) -> ::capnp::Result<()> {
-            ::capnp::traits::SetPointerBuilder::set_pointer_builder(
-                self.builder.get_pointer_field(1),
-                value,
-                false,
-            )
-        }
-        #[inline]
-        pub fn init_locus_list(
-            self,
-        ) -> crate::serialization::mash_capnp::min_hash::locus_list::Builder<'a> {
-            ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(1), 0)
-        }
-        pub fn has_locus_list(&self) -> bool {
-            !self.builder.get_pointer_field(1).is_null()
-        }
-        #[inline]
-        pub fn get_error(self) -> f32 {
-            self.builder.get_data_field::<f32>(4)
-        }
-        #[inline]
-        pub fn set_error(&mut self, value: f32) {
-            self.builder.set_data_field::<f32>(4, value);
-        }
-        #[inline]
-        pub fn get_noncanonical(self) -> bool {
-            self.builder.get_bool_field(97)
-        }
-        #[inline]
-        pub fn set_noncanonical(&mut self, value: bool) {
-            self.builder.set_bool_field(97, value);
-        }
-        #[inline]
-        pub fn get_alphabet(self) -> ::capnp::Result<::capnp::text::Builder<'a>> {
-            self.builder
-                .get_pointer_field(2)
-                .get_text(::std::ptr::null(), 0)
-        }
-        #[inline]
-        pub fn set_alphabet(&mut self, value: ::capnp::text::Reader) {
-            self.builder.get_pointer_field(2).set_text(value);
-        }
-        #[inline]
-        pub fn init_alphabet(self, size: u32) -> ::capnp::text::Builder<'a> {
-            self.builder.get_pointer_field(2).init_text(size)
-        }
-        pub fn has_alphabet(&self) -> bool {
-            !self.builder.get_pointer_field(2).is_null()
-        }
-        #[inline]
-        pub fn get_preserve_case(self) -> bool {
-            self.builder.get_bool_field(98)
-        }
-        #[inline]
-        pub fn set_preserve_case(&mut self, value: bool) {
-            self.builder.set_bool_field(98, value);
-        }
-        #[inline]
-        pub fn get_hash_seed(self) -> u32 {
-            self.builder.get_data_field_mask::<u32>(5, 42)
-        }
-        #[inline]
-        pub fn set_hash_seed(&mut self, value: u32) {
-            self.builder.set_data_field_mask::<u32>(5, value, 42);
-        }
-        #[inline]
-        pub fn get_reference_list(
-            self,
-        ) -> ::capnp::Result<crate::serialization::mash_capnp::min_hash::reference_list::Builder<'a>>
-        {
-            ::capnp::traits::FromPointerBuilder::get_from_pointer(self.builder.get_pointer_field(3))
-        }
-        #[inline]
-        pub fn set_reference_list<'b>(
-            &mut self,
-            value: crate::serialization::mash_capnp::min_hash::reference_list::Reader<'b>,
-        ) -> ::capnp::Result<()> {
-            ::capnp::traits::SetPointerBuilder::set_pointer_builder(
-                self.builder.get_pointer_field(3),
-                value,
-                false,
-            )
-        }
-        #[inline]
-        pub fn init_reference_list(
-            self,
-        ) -> crate::serialization::mash_capnp::min_hash::reference_list::Builder<'a> {
-            ::capnp::traits::FromPointerBuilder::init_pointer(self.builder.get_pointer_field(3), 0)
-        }
-        pub fn has_reference_list(&self) -> bool {
-            !self.builder.get_pointer_field(3).is_null()
-        }
-    }
-
-    pub struct Pipeline {
-        _typeless: ::capnp::any_pointer::Pipeline,
-    }
-    impl ::capnp::capability::FromTypelessPipeline for Pipeline {
-        fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
-            Pipeline {
-                _typeless: typeless,
-            }
-        }
-    }
-    impl Pipeline {
-        pub fn get_reference_list_old(
-            &self,
-        ) -> crate::serialization::mash_capnp::min_hash::reference_list::Pipeline {
-            ::capnp::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field(0))
-        }
-        pub fn get_locus_list(
-            &self,
-        ) -> crate::serialization::mash_capnp::min_hash::locus_list::Pipeline {
-            ::capnp::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field(1))
-        }
-        pub fn get_reference_list(
-            &self,
-        ) -> crate::serialization::mash_capnp::min_hash::reference_list::Pipeline {
-            ::capnp::capability::FromTypelessPipeline::new(self._typeless.get_pointer_field(3))
-        }
-    }
-    mod _private {
-        use capnp::private::layout;
-        pub const STRUCT_SIZE: layout::StructSize = layout::StructSize {
-            data: 3,
-            pointers: 4,
-        };
-        pub const TYPE_ID: u64 = 0xd9d1_6806_af78_2606;
-    }
-
-    pub mod reference_list {
-        #[derive(Copy, Clone)]
-        pub struct Owned;
-        impl<'a> ::capnp::traits::Owned<'a> for Owned {
-            type Reader = Reader<'a>;
-            type Builder = Builder<'a>;
-        }
-        impl<'a> ::capnp::traits::OwnedStruct<'a> for Owned {
-            type Reader = Reader<'a>;
-            type Builder = Builder<'a>;
-        }
-        impl ::capnp::traits::Pipelined for Owned {
-            type Pipeline = Pipeline;
-        }
-
-        #[derive(Clone, Copy)]
-        pub struct Reader<'a> {
-            reader: ::capnp::private::layout::StructReader<'a>,
-        }
-
-        impl<'a> ::capnp::traits::HasTypeId for Reader<'a> {
-            #[inline]
-            fn type_id() -> u64 {
-                _private::TYPE_ID
-            }
-        }
-        impl<'a> ::capnp::traits::FromStructReader<'a> for Reader<'a> {
-            fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a> {
-                Reader { reader: reader }
-            }
-        }
-
-        impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> {
-            fn get_from_pointer(
-                reader: &::capnp::private::layout::PointerReader<'a>,
-            ) -> ::capnp::Result<Reader<'a>> {
-                ::std::result::Result::Ok(::capnp::traits::FromStructReader::new(
-                    reader.get_struct(::std::ptr::null())?,
-                ))
-            }
-        }
-
-        impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> {
-            fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
-                self.reader
-            }
-        }
-
-        impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> {
-            fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
-                self.reader
-                    .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
-            }
-        }
-
-        impl<'a> Reader<'a> {
-            pub fn reborrow(&self) -> Reader {
-                Reader { ..*self }
-            }
-
-            pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
-                self.reader.total_size()
-            }
-            #[inline]
-            pub fn get_references(
-                self,
-            ) -> ::capnp::Result<
-                ::capnp::struct_list::Reader<
-                    'a,
-                    crate::serialization::mash_capnp::min_hash::reference_list::reference::Owned,
-                >,
-            > {
-                ::capnp::traits::FromPointerReader::get_from_pointer(
-                    &self.reader.get_pointer_field(0),
-                )
-            }
-            pub fn has_references(&self) -> bool {
-                !self.reader.get_pointer_field(0).is_null()
-            }
-        }
-
-        pub struct Builder<'a> {
-            builder: ::capnp::private::layout::StructBuilder<'a>,
-        }
-        impl<'a> ::capnp::traits::HasStructSize for Builder<'a> {
-            #[inline]
-            fn struct_size() -> ::capnp::private::layout::StructSize {
-                _private::STRUCT_SIZE
-            }
-        }
-        impl<'a> ::capnp::traits::HasTypeId for Builder<'a> {
-            #[inline]
-            fn type_id() -> u64 {
-                _private::TYPE_ID
-            }
-        }
-        impl<'a> ::capnp::traits::FromStructBuilder<'a> for Builder<'a> {
-            fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a> {
-                Builder { builder: builder }
-            }
-        }
-
-        impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> {
-            fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
-                self.builder
-                    .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
-            }
-        }
-
-        impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> {
-            fn init_pointer(
-                builder: ::capnp::private::layout::PointerBuilder<'a>,
-                _size: u32,
-            ) -> Builder<'a> {
-                ::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
-            }
-            fn get_from_pointer(
-                builder: ::capnp::private::layout::PointerBuilder<'a>,
-            ) -> ::capnp::Result<Builder<'a>> {
-                ::std::result::Result::Ok(::capnp::traits::FromStructBuilder::new(
-                    builder.get_struct(_private::STRUCT_SIZE, ::std::ptr::null())?,
-                ))
-            }
-        }
-
-        impl<'a> ::capnp::traits::SetPointerBuilder<Builder<'a>> for Reader<'a> {
-            fn set_pointer_builder<'b>(
-                pointer: ::capnp::private::layout::PointerBuilder<'b>,
-                value: Reader<'a>,
-                canonicalize: bool,
-            ) -> ::capnp::Result<()> {
-                pointer.set_struct(&value.reader, canonicalize)
-            }
-        }
-
-        impl<'a> Builder<'a> {
-            #[deprecated(since = "0.9.2", note = "use into_reader()")]
-            pub fn as_reader(self) -> Reader<'a> {
-                self.into_reader()
-            }
-            pub fn into_reader(self) -> Reader<'a> {
-                ::capnp::traits::FromStructReader::new(self.builder.into_reader())
-            }
-            pub fn reborrow(&mut self) -> Builder {
-                Builder { ..*self }
-            }
-            pub fn reborrow_as_reader(&self) -> Reader {
-                ::capnp::traits::FromStructReader::new(self.builder.into_reader())
-            }
-
-            pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
-                self.builder.into_reader().total_size()
-            }
-            #[inline]
-            pub fn get_references(
-                self,
-            ) -> ::capnp::Result<
-                ::capnp::struct_list::Builder<
-                    'a,
-                    crate::serialization::mash_capnp::min_hash::reference_list::reference::Owned,
-                >,
-            > {
-                ::capnp::traits::FromPointerBuilder::get_from_pointer(
-                    self.builder.get_pointer_field(0),
-                )
-            }
-            #[inline]
-            pub fn set_references(
-                &mut self,
-                value: ::capnp::struct_list::Reader<
-                    'a,
-                    crate::serialization::mash_capnp::min_hash::reference_list::reference::Owned,
-                >,
-            ) -> ::capnp::Result<()> {
-                ::capnp::traits::SetPointerBuilder::set_pointer_builder(
-                    self.builder.get_pointer_field(0),
-                    value,
-                    false,
-                )
-            }
-            #[inline]
-            pub fn init_references(
-                self,
-                size: u32,
-            ) -> ::capnp::struct_list::Builder<
-                'a,
-                crate::serialization::mash_capnp::min_hash::reference_list::reference::Owned,
-            > {
-                ::capnp::traits::FromPointerBuilder::init_pointer(
-                    self.builder.get_pointer_field(0),
-                    size,
-                )
-            }
-            pub fn has_references(&self) -> bool {
-                !self.builder.get_pointer_field(0).is_null()
-            }
-        }
-
-        pub struct Pipeline {
-            _typeless: ::capnp::any_pointer::Pipeline,
-        }
-        impl ::capnp::capability::FromTypelessPipeline for Pipeline {
-            fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
-                Pipeline {
-                    _typeless: typeless,
-                }
-            }
-        }
-        impl Pipeline {}
-        mod _private {
-            use capnp::private::layout;
-            pub const STRUCT_SIZE: layout::StructSize = layout::StructSize {
-                data: 0,
-                pointers: 1,
-            };
-            pub const TYPE_ID: u64 = 0xcf71_219d_02db_7ad0;
-        }
-
-        pub mod reference {
-            #[derive(Copy, Clone)]
-            pub struct Owned;
-            impl<'a> ::capnp::traits::Owned<'a> for Owned {
-                type Reader = Reader<'a>;
-                type Builder = Builder<'a>;
-            }
-            impl<'a> ::capnp::traits::OwnedStruct<'a> for Owned {
-                type Reader = Reader<'a>;
-                type Builder = Builder<'a>;
-            }
-            impl ::capnp::traits::Pipelined for Owned {
-                type Pipeline = Pipeline;
-            }
-
-            #[derive(Clone, Copy)]
-            pub struct Reader<'a> {
-                reader: ::capnp::private::layout::StructReader<'a>,
-            }
-
-            impl<'a> ::capnp::traits::HasTypeId for Reader<'a> {
-                #[inline]
-                fn type_id() -> u64 {
-                    _private::TYPE_ID
-                }
-            }
-            impl<'a> ::capnp::traits::FromStructReader<'a> for Reader<'a> {
-                fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a> {
-                    Reader { reader: reader }
-                }
-            }
-
-            impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> {
-                fn get_from_pointer(
-                    reader: &::capnp::private::layout::PointerReader<'a>,
-                ) -> ::capnp::Result<Reader<'a>> {
-                    ::std::result::Result::Ok(::capnp::traits::FromStructReader::new(
-                        reader.get_struct(::std::ptr::null())?,
-                    ))
-                }
-            }
-
-            impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> {
-                fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
-                    self.reader
-                }
-            }
-
-            impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> {
-                fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
-                    self.reader
-                        .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
-                }
-            }
-
-            impl<'a> Reader<'a> {
-                pub fn reborrow(&self) -> Reader {
-                    Reader { ..*self }
-                }
-
-                pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
-                    self.reader.total_size()
-                }
-                #[inline]
-                pub fn get_sequence(self) -> ::capnp::Result<::capnp::text::Reader<'a>> {
-                    self.reader
-                        .get_pointer_field(0)
-                        .get_text(::std::ptr::null(), 0)
-                }
-                pub fn has_sequence(&self) -> bool {
-                    !self.reader.get_pointer_field(0).is_null()
-                }
-                #[inline]
-                pub fn get_quality(self) -> ::capnp::Result<::capnp::text::Reader<'a>> {
-                    self.reader
-                        .get_pointer_field(1)
-                        .get_text(::std::ptr::null(), 0)
-                }
-                pub fn has_quality(&self) -> bool {
-                    !self.reader.get_pointer_field(1).is_null()
-                }
-                #[inline]
-                pub fn get_length(self) -> u32 {
-                    self.reader.get_data_field::<u32>(0)
-                }
-                #[inline]
-                pub fn get_name(self) -> ::capnp::Result<::capnp::text::Reader<'a>> {
-                    self.reader
-                        .get_pointer_field(2)
-                        .get_text(::std::ptr::null(), 0)
-                }
-                pub fn has_name(&self) -> bool {
-                    !self.reader.get_pointer_field(2).is_null()
-                }
-                #[inline]
-                pub fn get_comment(self) -> ::capnp::Result<::capnp::text::Reader<'a>> {
-                    self.reader
-                        .get_pointer_field(3)
-                        .get_text(::std::ptr::null(), 0)
-                }
-                pub fn has_comment(&self) -> bool {
-                    !self.reader.get_pointer_field(3).is_null()
-                }
-                #[inline]
-                pub fn get_hashes32(
-                    self,
-                ) -> ::capnp::Result<::capnp::primitive_list::Reader<'a, u32>> {
-                    ::capnp::traits::FromPointerReader::get_from_pointer(
-                        &self.reader.get_pointer_field(4),
-                    )
-                }
-                pub fn has_hashes32(&self) -> bool {
-                    !self.reader.get_pointer_field(4).is_null()
-                }
-                #[inline]
-                pub fn get_hashes64(
-                    self,
-                ) -> ::capnp::Result<::capnp::primitive_list::Reader<'a, u64>> {
-                    ::capnp::traits::FromPointerReader::get_from_pointer(
-                        &self.reader.get_pointer_field(5),
-                    )
-                }
-                pub fn has_hashes64(&self) -> bool {
-                    !self.reader.get_pointer_field(5).is_null()
-                }
-                #[inline]
-                pub fn get_length64(self) -> u64 {
-                    self.reader.get_data_field::<u64>(1)
-                }
-                #[inline]
-                pub fn get_counts32(
-                    self,
-                ) -> ::capnp::Result<::capnp::primitive_list::Reader<'a, u32>> {
-                    ::capnp::traits::FromPointerReader::get_from_pointer(
-                        &self.reader.get_pointer_field(6),
-                    )
-                }
-                pub fn has_counts32(&self) -> bool {
-                    !self.reader.get_pointer_field(6).is_null()
-                }
-                #[inline]
-                pub fn get_num_valid_kmers(self) -> u64 {
-                    self.reader.get_data_field::<u64>(2)
-                }
-            }
-
-            pub struct Builder<'a> {
-                builder: ::capnp::private::layout::StructBuilder<'a>,
-            }
-            impl<'a> ::capnp::traits::HasStructSize for Builder<'a> {
-                #[inline]
-                fn struct_size() -> ::capnp::private::layout::StructSize {
-                    _private::STRUCT_SIZE
-                }
-            }
-            impl<'a> ::capnp::traits::HasTypeId for Builder<'a> {
-                #[inline]
-                fn type_id() -> u64 {
-                    _private::TYPE_ID
-                }
-            }
-            impl<'a> ::capnp::traits::FromStructBuilder<'a> for Builder<'a> {
-                fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a> {
-                    Builder { builder: builder }
-                }
-            }
-
-            impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> {
-                fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
-                    self.builder
-                        .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
-                }
-            }
-
-            impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> {
-                fn init_pointer(
-                    builder: ::capnp::private::layout::PointerBuilder<'a>,
-                    _size: u32,
-                ) -> Builder<'a> {
-                    ::capnp::traits::FromStructBuilder::new(
-                        builder.init_struct(_private::STRUCT_SIZE),
-                    )
-                }
-                fn get_from_pointer(
-                    builder: ::capnp::private::layout::PointerBuilder<'a>,
-                ) -> ::capnp::Result<Builder<'a>> {
-                    ::std::result::Result::Ok(::capnp::traits::FromStructBuilder::new(
-                        builder.get_struct(_private::STRUCT_SIZE, ::std::ptr::null())?,
-                    ))
-                }
-            }
-
-            impl<'a> ::capnp::traits::SetPointerBuilder<Builder<'a>> for Reader<'a> {
-                fn set_pointer_builder<'b>(
-                    pointer: ::capnp::private::layout::PointerBuilder<'b>,
-                    value: Reader<'a>,
-                    canonicalize: bool,
-                ) -> ::capnp::Result<()> {
-                    pointer.set_struct(&value.reader, canonicalize)
-                }
-            }
-
-            impl<'a> Builder<'a> {
-                #[deprecated(since = "0.9.2", note = "use into_reader()")]
-                pub fn as_reader(self) -> Reader<'a> {
-                    self.into_reader()
-                }
-                pub fn into_reader(self) -> Reader<'a> {
-                    ::capnp::traits::FromStructReader::new(self.builder.into_reader())
-                }
-                pub fn reborrow(&mut self) -> Builder {
-                    Builder { ..*self }
-                }
-                pub fn reborrow_as_reader(&self) -> Reader {
-                    ::capnp::traits::FromStructReader::new(self.builder.into_reader())
-                }
-
-                pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
-                    self.builder.into_reader().total_size()
-                }
-                #[inline]
-                pub fn get_sequence(self) -> ::capnp::Result<::capnp::text::Builder<'a>> {
-                    self.builder
-                        .get_pointer_field(0)
-                        .get_text(::std::ptr::null(), 0)
-                }
-                #[inline]
-                pub fn set_sequence(&mut self, value: ::capnp::text::Reader) {
-                    self.builder.get_pointer_field(0).set_text(value);
-                }
-                #[inline]
-                pub fn init_sequence(self, size: u32) -> ::capnp::text::Builder<'a> {
-                    self.builder.get_pointer_field(0).init_text(size)
-                }
-                pub fn has_sequence(&self) -> bool {
-                    !self.builder.get_pointer_field(0).is_null()
-                }
-                #[inline]
-                pub fn get_quality(self) -> ::capnp::Result<::capnp::text::Builder<'a>> {
-                    self.builder
-                        .get_pointer_field(1)
-                        .get_text(::std::ptr::null(), 0)
-                }
-                #[inline]
-                pub fn set_quality(&mut self, value: ::capnp::text::Reader) {
-                    self.builder.get_pointer_field(1).set_text(value);
-                }
-                #[inline]
-                pub fn init_quality(self, size: u32) -> ::capnp::text::Builder<'a> {
-                    self.builder.get_pointer_field(1).init_text(size)
-                }
-                pub fn has_quality(&self) -> bool {
-                    !self.builder.get_pointer_field(1).is_null()
-                }
-                #[inline]
-                pub fn get_length(self) -> u32 {
-                    self.builder.get_data_field::<u32>(0)
-                }
-                #[inline]
-                pub fn set_length(&mut self, value: u32) {
-                    self.builder.set_data_field::<u32>(0, value);
-                }
-                #[inline]
-                pub fn get_name(self) -> ::capnp::Result<::capnp::text::Builder<'a>> {
-                    self.builder
-                        .get_pointer_field(2)
-                        .get_text(::std::ptr::null(), 0)
-                }
-                #[inline]
-                pub fn set_name(&mut self, value: ::capnp::text::Reader) {
-                    self.builder.get_pointer_field(2).set_text(value);
-                }
-                #[inline]
-                pub fn init_name(self, size: u32) -> ::capnp::text::Builder<'a> {
-                    self.builder.get_pointer_field(2).init_text(size)
-                }
-                pub fn has_name(&self) -> bool {
-                    !self.builder.get_pointer_field(2).is_null()
-                }
-                #[inline]
-                pub fn get_comment(self) -> ::capnp::Result<::capnp::text::Builder<'a>> {
-                    self.builder
-                        .get_pointer_field(3)
-                        .get_text(::std::ptr::null(), 0)
-                }
-                #[inline]
-                pub fn set_comment(&mut self, value: ::capnp::text::Reader) {
-                    self.builder.get_pointer_field(3).set_text(value);
-                }
-                #[inline]
-                pub fn init_comment(self, size: u32) -> ::capnp::text::Builder<'a> {
-                    self.builder.get_pointer_field(3).init_text(size)
-                }
-                pub fn has_comment(&self) -> bool {
-                    !self.builder.get_pointer_field(3).is_null()
-                }
-                #[inline]
-                pub fn get_hashes32(
-                    self,
-                ) -> ::capnp::Result<::capnp::primitive_list::Builder<'a, u32>> {
-                    ::capnp::traits::FromPointerBuilder::get_from_pointer(
-                        self.builder.get_pointer_field(4),
-                    )
-                }
-                #[inline]
-                pub fn set_hashes32(
-                    &mut self,
-                    value: ::capnp::primitive_list::Reader<'a, u32>,
-                ) -> ::capnp::Result<()> {
-                    ::capnp::traits::SetPointerBuilder::set_pointer_builder(
-                        self.builder.get_pointer_field(4),
-                        value,
-                        false,
-                    )
-                }
-                #[inline]
-                pub fn init_hashes32(self, size: u32) -> ::capnp::primitive_list::Builder<'a, u32> {
-                    ::capnp::traits::FromPointerBuilder::init_pointer(
-                        self.builder.get_pointer_field(4),
-                        size,
-                    )
-                }
-                pub fn has_hashes32(&self) -> bool {
-                    !self.builder.get_pointer_field(4).is_null()
-                }
-                #[inline]
-                pub fn get_hashes64(
-                    self,
-                ) -> ::capnp::Result<::capnp::primitive_list::Builder<'a, u64>> {
-                    ::capnp::traits::FromPointerBuilder::get_from_pointer(
-                        self.builder.get_pointer_field(5),
-                    )
-                }
-                #[inline]
-                pub fn set_hashes64(
-                    &mut self,
-                    value: ::capnp::primitive_list::Reader<'a, u64>,
-                ) -> ::capnp::Result<()> {
-                    ::capnp::traits::SetPointerBuilder::set_pointer_builder(
-                        self.builder.get_pointer_field(5),
-                        value,
-                        false,
-                    )
-                }
-                #[inline]
-                pub fn init_hashes64(self, size: u32) -> ::capnp::primitive_list::Builder<'a, u64> {
-                    ::capnp::traits::FromPointerBuilder::init_pointer(
-                        self.builder.get_pointer_field(5),
-                        size,
-                    )
-                }
-                pub fn has_hashes64(&self) -> bool {
-                    !self.builder.get_pointer_field(5).is_null()
-                }
-                #[inline]
-                pub fn get_length64(self) -> u64 {
-                    self.builder.get_data_field::<u64>(1)
-                }
-                #[inline]
-                pub fn set_length64(&mut self, value: u64) {
-                    self.builder.set_data_field::<u64>(1, value);
-                }
-                #[inline]
-                pub fn get_counts32(
-                    self,
-                ) -> ::capnp::Result<::capnp::primitive_list::Builder<'a, u32>> {
-                    ::capnp::traits::FromPointerBuilder::get_from_pointer(
-                        self.builder.get_pointer_field(6),
-                    )
-                }
-                #[inline]
-                pub fn set_counts32(
-                    &mut self,
-                    value: ::capnp::primitive_list::Reader<'a, u32>,
-                ) -> ::capnp::Result<()> {
-                    ::capnp::traits::SetPointerBuilder::set_pointer_builder(
-                        self.builder.get_pointer_field(6),
-                        value,
-                        false,
-                    )
-                }
-                #[inline]
-                pub fn init_counts32(self, size: u32) -> ::capnp::primitive_list::Builder<'a, u32> {
-                    ::capnp::traits::FromPointerBuilder::init_pointer(
-                        self.builder.get_pointer_field(6),
-                        size,
-                    )
-                }
-                pub fn has_counts32(&self) -> bool {
-                    !self.builder.get_pointer_field(6).is_null()
-                }
-                #[inline]
-                pub fn get_num_valid_kmers(self) -> u64 {
-                    self.builder.get_data_field::<u64>(2)
-                }
-                #[inline]
-                pub fn set_num_valid_kmers(&mut self, value: u64) {
-                    self.builder.set_data_field::<u64>(2, value);
-                }
-            }
-
-            pub struct Pipeline {
-                _typeless: ::capnp::any_pointer::Pipeline,
-            }
-            impl ::capnp::capability::FromTypelessPipeline for Pipeline {
-                fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
-                    Pipeline {
-                        _typeless: typeless,
-                    }
-                }
-            }
-            impl Pipeline {}
-            mod _private {
-                use capnp::private::layout;
-                pub const STRUCT_SIZE: layout::StructSize = layout::StructSize {
-                    data: 3,
-                    pointers: 7,
-                };
-                pub const TYPE_ID: u64 = 0x96c3_ea4c_bfe1_43bf;
-            }
-        }
-    }
-
-    pub mod locus_list {
-        #[derive(Copy, Clone)]
-        pub struct Owned;
-        impl<'a> ::capnp::traits::Owned<'a> for Owned {
-            type Reader = Reader<'a>;
-            type Builder = Builder<'a>;
-        }
-        impl<'a> ::capnp::traits::OwnedStruct<'a> for Owned {
-            type Reader = Reader<'a>;
-            type Builder = Builder<'a>;
-        }
-        impl ::capnp::traits::Pipelined for Owned {
-            type Pipeline = Pipeline;
-        }
-
-        #[derive(Clone, Copy)]
-        pub struct Reader<'a> {
-            reader: ::capnp::private::layout::StructReader<'a>,
-        }
-
-        impl<'a> ::capnp::traits::HasTypeId for Reader<'a> {
-            #[inline]
-            fn type_id() -> u64 {
-                _private::TYPE_ID
-            }
-        }
-        impl<'a> ::capnp::traits::FromStructReader<'a> for Reader<'a> {
-            fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a> {
-                Reader { reader: reader }
-            }
-        }
-
-        impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> {
-            fn get_from_pointer(
-                reader: &::capnp::private::layout::PointerReader<'a>,
-            ) -> ::capnp::Result<Reader<'a>> {
-                ::std::result::Result::Ok(::capnp::traits::FromStructReader::new(
-                    reader.get_struct(::std::ptr::null())?,
-                ))
-            }
-        }
-
-        impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> {
-            fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
-                self.reader
-            }
-        }
-
-        impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> {
-            fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
-                self.reader
-                    .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
-            }
-        }
-
-        impl<'a> Reader<'a> {
-            pub fn reborrow(&self) -> Reader {
-                Reader { ..*self }
-            }
-
-            pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
-                self.reader.total_size()
-            }
-            #[inline]
-            pub fn get_loci(
-                self,
-            ) -> ::capnp::Result<
-                ::capnp::struct_list::Reader<
-                    'a,
-                    crate::serialization::mash_capnp::min_hash::locus_list::locus::Owned,
-                >,
-            > {
-                ::capnp::traits::FromPointerReader::get_from_pointer(
-                    &self.reader.get_pointer_field(0),
-                )
-            }
-            pub fn has_loci(&self) -> bool {
-                !self.reader.get_pointer_field(0).is_null()
-            }
-        }
-
-        pub struct Builder<'a> {
-            builder: ::capnp::private::layout::StructBuilder<'a>,
-        }
-        impl<'a> ::capnp::traits::HasStructSize for Builder<'a> {
-            #[inline]
-            fn struct_size() -> ::capnp::private::layout::StructSize {
-                _private::STRUCT_SIZE
-            }
-        }
-        impl<'a> ::capnp::traits::HasTypeId for Builder<'a> {
-            #[inline]
-            fn type_id() -> u64 {
-                _private::TYPE_ID
-            }
-        }
-        impl<'a> ::capnp::traits::FromStructBuilder<'a> for Builder<'a> {
-            fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a> {
-                Builder { builder: builder }
-            }
-        }
-
-        impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> {
-            fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
-                self.builder
-                    .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
-            }
-        }
-
-        impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> {
-            fn init_pointer(
-                builder: ::capnp::private::layout::PointerBuilder<'a>,
-                _size: u32,
-            ) -> Builder<'a> {
-                ::capnp::traits::FromStructBuilder::new(builder.init_struct(_private::STRUCT_SIZE))
-            }
-            fn get_from_pointer(
-                builder: ::capnp::private::layout::PointerBuilder<'a>,
-            ) -> ::capnp::Result<Builder<'a>> {
-                ::std::result::Result::Ok(::capnp::traits::FromStructBuilder::new(
-                    builder.get_struct(_private::STRUCT_SIZE, ::std::ptr::null())?,
-                ))
-            }
-        }
-
-        impl<'a> ::capnp::traits::SetPointerBuilder<Builder<'a>> for Reader<'a> {
-            fn set_pointer_builder<'b>(
-                pointer: ::capnp::private::layout::PointerBuilder<'b>,
-                value: Reader<'a>,
-                canonicalize: bool,
-            ) -> ::capnp::Result<()> {
-                pointer.set_struct(&value.reader, canonicalize)
-            }
-        }
-
-        impl<'a> Builder<'a> {
-            #[deprecated(since = "0.9.2", note = "use into_reader()")]
-            pub fn as_reader(self) -> Reader<'a> {
-                self.into_reader()
-            }
-            pub fn into_reader(self) -> Reader<'a> {
-                ::capnp::traits::FromStructReader::new(self.builder.into_reader())
-            }
-            pub fn reborrow(&mut self) -> Builder {
-                Builder { ..*self }
-            }
-            pub fn reborrow_as_reader(&self) -> Reader {
-                ::capnp::traits::FromStructReader::new(self.builder.into_reader())
-            }
-
-            pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
-                self.builder.into_reader().total_size()
-            }
-            #[inline]
-            pub fn get_loci(
-                self,
-            ) -> ::capnp::Result<
-                ::capnp::struct_list::Builder<
-                    'a,
-                    crate::serialization::mash_capnp::min_hash::locus_list::locus::Owned,
-                >,
-            > {
-                ::capnp::traits::FromPointerBuilder::get_from_pointer(
-                    self.builder.get_pointer_field(0),
-                )
-            }
-            #[inline]
-            pub fn set_loci(
-                &mut self,
-                value: ::capnp::struct_list::Reader<
-                    'a,
-                    crate::serialization::mash_capnp::min_hash::locus_list::locus::Owned,
-                >,
-            ) -> ::capnp::Result<()> {
-                ::capnp::traits::SetPointerBuilder::set_pointer_builder(
-                    self.builder.get_pointer_field(0),
-                    value,
-                    false,
-                )
-            }
-            #[inline]
-            pub fn init_loci(
-                self,
-                size: u32,
-            ) -> ::capnp::struct_list::Builder<
-                'a,
-                crate::serialization::mash_capnp::min_hash::locus_list::locus::Owned,
-            > {
-                ::capnp::traits::FromPointerBuilder::init_pointer(
-                    self.builder.get_pointer_field(0),
-                    size,
-                )
-            }
-            pub fn has_loci(&self) -> bool {
-                !self.builder.get_pointer_field(0).is_null()
-            }
-        }
-
-        pub struct Pipeline {
-            _typeless: ::capnp::any_pointer::Pipeline,
-        }
-        impl ::capnp::capability::FromTypelessPipeline for Pipeline {
-            fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
-                Pipeline {
-                    _typeless: typeless,
-                }
-            }
-        }
-        impl Pipeline {}
-        mod _private {
-            use capnp::private::layout;
-            pub const STRUCT_SIZE: layout::StructSize = layout::StructSize {
-                data: 0,
-                pointers: 1,
-            };
-            pub const TYPE_ID: u64 = 0xe1dd_f186_e2b3_59dd;
-        }
-
-        pub mod locus {
-            #[derive(Copy, Clone)]
-            pub struct Owned;
-            impl<'a> ::capnp::traits::Owned<'a> for Owned {
-                type Reader = Reader<'a>;
-                type Builder = Builder<'a>;
-            }
-            impl<'a> ::capnp::traits::OwnedStruct<'a> for Owned {
-                type Reader = Reader<'a>;
-                type Builder = Builder<'a>;
-            }
-            impl ::capnp::traits::Pipelined for Owned {
-                type Pipeline = Pipeline;
-            }
-
-            #[derive(Clone, Copy)]
-            pub struct Reader<'a> {
-                reader: ::capnp::private::layout::StructReader<'a>,
-            }
-
-            impl<'a> ::capnp::traits::HasTypeId for Reader<'a> {
-                #[inline]
-                fn type_id() -> u64 {
-                    _private::TYPE_ID
-                }
-            }
-            impl<'a> ::capnp::traits::FromStructReader<'a> for Reader<'a> {
-                fn new(reader: ::capnp::private::layout::StructReader<'a>) -> Reader<'a> {
-                    Reader { reader: reader }
-                }
-            }
-
-            impl<'a> ::capnp::traits::FromPointerReader<'a> for Reader<'a> {
-                fn get_from_pointer(
-                    reader: &::capnp::private::layout::PointerReader<'a>,
-                ) -> ::capnp::Result<Reader<'a>> {
-                    ::std::result::Result::Ok(::capnp::traits::FromStructReader::new(
-                        reader.get_struct(::std::ptr::null())?,
-                    ))
-                }
-            }
-
-            impl<'a> ::capnp::traits::IntoInternalStructReader<'a> for Reader<'a> {
-                fn into_internal_struct_reader(self) -> ::capnp::private::layout::StructReader<'a> {
-                    self.reader
-                }
-            }
-
-            impl<'a> ::capnp::traits::Imbue<'a> for Reader<'a> {
-                fn imbue(&mut self, cap_table: &'a ::capnp::private::layout::CapTable) {
-                    self.reader
-                        .imbue(::capnp::private::layout::CapTableReader::Plain(cap_table))
-                }
-            }
-
-            impl<'a> Reader<'a> {
-                pub fn reborrow(&self) -> Reader {
-                    Reader { ..*self }
-                }
-
-                pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
-                    self.reader.total_size()
-                }
-                #[inline]
-                pub fn get_sequence(self) -> u32 {
-                    self.reader.get_data_field::<u32>(0)
-                }
-                #[inline]
-                pub fn get_position(self) -> u32 {
-                    self.reader.get_data_field::<u32>(1)
-                }
-                #[inline]
-                pub fn get_hash32(self) -> u32 {
-                    self.reader.get_data_field::<u32>(2)
-                }
-                #[inline]
-                pub fn get_hash64(self) -> u64 {
-                    self.reader.get_data_field::<u64>(2)
-                }
-            }
-
-            pub struct Builder<'a> {
-                builder: ::capnp::private::layout::StructBuilder<'a>,
-            }
-            impl<'a> ::capnp::traits::HasStructSize for Builder<'a> {
-                #[inline]
-                fn struct_size() -> ::capnp::private::layout::StructSize {
-                    _private::STRUCT_SIZE
-                }
-            }
-            impl<'a> ::capnp::traits::HasTypeId for Builder<'a> {
-                #[inline]
-                fn type_id() -> u64 {
-                    _private::TYPE_ID
-                }
-            }
-            impl<'a> ::capnp::traits::FromStructBuilder<'a> for Builder<'a> {
-                fn new(builder: ::capnp::private::layout::StructBuilder<'a>) -> Builder<'a> {
-                    Builder { builder: builder }
-                }
-            }
-
-            impl<'a> ::capnp::traits::ImbueMut<'a> for Builder<'a> {
-                fn imbue_mut(&mut self, cap_table: &'a mut ::capnp::private::layout::CapTable) {
-                    self.builder
-                        .imbue(::capnp::private::layout::CapTableBuilder::Plain(cap_table))
-                }
-            }
-
-            impl<'a> ::capnp::traits::FromPointerBuilder<'a> for Builder<'a> {
-                fn init_pointer(
-                    builder: ::capnp::private::layout::PointerBuilder<'a>,
-                    _size: u32,
-                ) -> Builder<'a> {
-                    ::capnp::traits::FromStructBuilder::new(
-                        builder.init_struct(_private::STRUCT_SIZE),
-                    )
-                }
-                fn get_from_pointer(
-                    builder: ::capnp::private::layout::PointerBuilder<'a>,
-                ) -> ::capnp::Result<Builder<'a>> {
-                    ::std::result::Result::Ok(::capnp::traits::FromStructBuilder::new(
-                        builder.get_struct(_private::STRUCT_SIZE, ::std::ptr::null())?,
-                    ))
-                }
-            }
-
-            impl<'a> ::capnp::traits::SetPointerBuilder<Builder<'a>> for Reader<'a> {
-                fn set_pointer_builder<'b>(
-                    pointer: ::capnp::private::layout::PointerBuilder<'b>,
-                    value: Reader<'a>,
-                    canonicalize: bool,
-                ) -> ::capnp::Result<()> {
-                    pointer.set_struct(&value.reader, canonicalize)
-                }
-            }
-
-            impl<'a> Builder<'a> {
-                #[deprecated(since = "0.9.2", note = "use into_reader()")]
-                pub fn as_reader(self) -> Reader<'a> {
-                    self.into_reader()
-                }
-                pub fn into_reader(self) -> Reader<'a> {
-                    ::capnp::traits::FromStructReader::new(self.builder.into_reader())
-                }
-                pub fn reborrow(&mut self) -> Builder {
-                    Builder { ..*self }
-                }
-                pub fn reborrow_as_reader(&self) -> Reader {
-                    ::capnp::traits::FromStructReader::new(self.builder.into_reader())
-                }
-
-                pub fn total_size(&self) -> ::capnp::Result<::capnp::MessageSize> {
-                    self.builder.into_reader().total_size()
-                }
-                #[inline]
-                pub fn get_sequence(self) -> u32 {
-                    self.builder.get_data_field::<u32>(0)
-                }
-                #[inline]
-                pub fn set_sequence(&mut self, value: u32) {
-                    self.builder.set_data_field::<u32>(0, value);
-                }
-                #[inline]
-                pub fn get_position(self) -> u32 {
-                    self.builder.get_data_field::<u32>(1)
-                }
-                #[inline]
-                pub fn set_position(&mut self, value: u32) {
-                    self.builder.set_data_field::<u32>(1, value);
-                }
-                #[inline]
-                pub fn get_hash32(self) -> u32 {
-                    self.builder.get_data_field::<u32>(2)
-                }
-                #[inline]
-                pub fn set_hash32(&mut self, value: u32) {
-                    self.builder.set_data_field::<u32>(2, value);
-                }
-                #[inline]
-                pub fn get_hash64(self) -> u64 {
-                    self.builder.get_data_field::<u64>(2)
-                }
-                #[inline]
-                pub fn set_hash64(&mut self, value: u64) {
-                    self.builder.set_data_field::<u64>(2, value);
-                }
-            }
-
-            pub struct Pipeline {
-                _typeless: ::capnp::any_pointer::Pipeline,
-            }
-            impl ::capnp::capability::FromTypelessPipeline for Pipeline {
-                fn new(typeless: ::capnp::any_pointer::Pipeline) -> Pipeline {
-                    Pipeline {
-                        _typeless: typeless,
-                    }
-                }
-            }
-            impl Pipeline {}
-            mod _private {
-                use capnp::private::layout;
-                pub const STRUCT_SIZE: layout::StructSize = layout::StructSize {
-                    data: 3,
-                    pointers: 0,
-                };
-                pub const TYPE_ID: u64 = 0xa648_d718_8f22_59f6;
-            }
-        }
-    }
-}


Test patch:
diff --git a/tests/data/query.fa b/cli/tests/data/query.fa
similarity index 100%
rename from tests/data/query.fa
rename to cli/tests/data/query.fa
diff --git a/tests/test_cli.rs b/cli/tests/test_cli.rs
similarity index 100%
rename from tests/test_cli.rs
rename to cli/tests/test_cli.rs