A from-scratch package manager whose interesting half is the resolver: a readable PubGrub version solver that pins every dependency, or proves in plain English why it can't. Try it live below.
Two boxes. On the left, what your project asks for. On the right, every package version that exists and what each one needs. Hit Resolve and the real PubGrub algorithm runs in your browser. It either pins one version of everything, or explains in plain English why no combination works. New here? Tap a preset below to load a ready-made example.
^1.0 compatible updates
~1.2 patch updates only
>=1.0, <2.0 a range
1.0.0 that exact version
* any version
The left box is your project's direct requirements, one per line: a package name and a version range (web ^1.0). The right box is the registry, every package version that exists, with each version's own dependencies indented beneath it.
Tap a preset chip to load a ready-made example, then press Resolve. If a valid combination exists you get one pinned version per package plus a dependency tree; if not, you get the numbered proof of exactly which two requirements collide. Edit either box and resolve again to experiment.
Every build-your-own package manager hand-waves resolution and every real one explains failures badly. Quartermaster is built around exactly those two things.
Picking one version of every package so all constraints hold is NP-hard. Quartermaster uses PubGrub, the same conflict-driven algorithm as Dart's pub and uv: unit propagation, learned incompatibilities, and backjumping. Not a greedy toy.
When npm or pip can't resolve, they dump version numbers. Quartermaster hands back the derivation path in English, ending at the exact two requirements that collide, so a person or an AI agent knows what to change.
Two moves alternate over a growing set of incompatibilities, combinations of versions that cannot coexist.
When an incompatibility has all but one term already forced by earlier choices, the last term's negation becomes a new derived fact. When every term is forced, that's a conflict.
Pick a required package, take its highest allowed version, add its dependencies. On a conflict, resolve it against its cause into a new incompatibility and jump straight back to where that becomes decisive, never re-treading dead branches.
# the version algebra is boundary-exact: ranges are interval sets ^1.2.3 → >=1.2.3, <2.0.0 ~1.2.0 → >=1.2.0, <1.3.0 1 || 3 → >=1.0.0,<2.0.0 or >=3.0.0,<4.0.0 # intersection, union, and complement are total and exact, # so the solver reasons correctly instead of string-matching versions.
The browser demo above is a faithful port of the Rust engine. Here is the real binary running against the example registry that ships in the repo.
$ qm resolve examples/app.qm --registry examples/registry.qm resolved myapp 0.1.0 (4 packages): bytes 1.1.5 http 1.3.0 json 1.3.0 web 1.1.0 $ qm tree examples/app.qm --registry examples/registry.qm myapp 0.1.0 ├─ json 1.3.0 │ └─ bytes 1.1.5 └─ web 1.1.0 ├─ http 1.3.0 │ └─ bytes 1.1.5 (*) └─ json 1.3.0 (*)
(*) marks a shared dependency already printed above, so it is shown once.
Zero dependencies, pure Rust standard library. Point qm at a manifest and a registry and pick what you want back.
Runs the PubGrub solver and prints one exact version for the project and every transitive dependency, or the reason none exists.
The resolved set as a dependency tree, with shared packages marked (*) so each one is printed a single time.
Emit a lockfile of the resolved versions, so the same set is reproduced on the next install.
When there is no solution, render the derivation as a numbered proof that ends at the exact two requirements that collide.
# build, then run any subcommand cargo build ./target/debug/qm resolve examples/app.qm --registry examples/registry.qm ./target/debug/qm tree examples/app.qm --registry examples/registry.qm ./target/debug/qm lock examples/app.qm --registry examples/registry.qm ./target/debug/qm explain examples/conflict.qm --registry examples/registry.qm