ideas.
October 11, 2026 3 min read clidev-toolsproductivity

Find out why it works on your machine

A CLI that fingerprints a dev environment into one canonical file, then diffs yours against a teammate's or CI's to find the difference.

The idea

A single-binary CLI — call it envdiff — that walks the machine it runs on and writes a canonical fingerprint of everything that can plausibly change program behaviour: kernel and libc versions, CPU features, locale and timezone, shell, resolved toolchain versions, the contents of language lockfiles, relevant environment variables, and the dynamic libraries each project binary actually links against. The output is one deterministic JSON file. The second command, envdiff compare mine.json ci.json, prints a ranked list of differences with the noise collapsed, so "works on my machine" becomes a diff you can read in ten seconds.

Why build this

Every team loses hours a month to a build or test that passes in one place and fails in another, and the hunt is almost always manual: paste node -v into Slack, discover someone's on glibc 2.35, find the stray NODE_OPTIONS in a shell profile, notice CI runs in UTC while the failing developer is on Europe/Berlin. The information needed to settle it is cheap to collect and nobody collects it, because collecting it by hand is tedious and the output is unreadable without something to compare it to.

Two things make now a reasonable time. Toolchains have become version-pinned and introspectable — rustup, uv, mise, asdf, Corepack and the rest all report resolved versions in machine-readable form, so a fingerprint no longer means scraping --version strings. And nearly every CI provider will upload a JSON artifact for free, which gives you the other half of the diff without asking anyone to install anything.

Stack sketch

  • Rust, distributed as a static binary via cargo-dist — the tool has to run on a broken machine, so no runtime dependency.
  • sysinfo for host facts, os_release parsing for the distro, nix for locale and resource limits.
  • goblin to read ELF and Mach-O headers and list required shared libraries and their versions, rather than shelling out to ldd/otool.
  • Lockfile parsers for the common ecosystems: cargo_metadata, plus plain serde structs for package-lock.json, uv.lock, poetry.lock, go.sum.
  • RFC 8785 JSON canonicalization so the same machine always produces byte-identical output and fingerprints can be hashed and cached.
  • similar for the structural diff, ratatui for an optional interactive view of a large one.
  • A GitHub Action wrapper that runs envdiff capture and uploads the result as an artifact, so CI fingerprints exist without per-repo work.

Scope for v1

  • envdiff capture and envdiff compare, Linux and macOS only.
  • A rule file that marks fields as significant, informational, or ignored, with sensible defaults — paths and hostnames should never show up as differences.
  • Secret redaction on environment variables: allowlist by name, drop everything else, no heuristic sniffing.
  • Deliberately out of v1: Windows, remote fetching of a peer's fingerprint, any server component, any attempt to say which difference caused the failure.

Where it could go

The obvious next step is bisection across environments instead of commits. If a repository accumulates fingerprints from passing and failing runs, the tool can rank candidate fields by how well they separate the two sets — not causation, but a far better starting point than a flat diff. That turns a debugging aid into something closer to a flake triage tool.

After that, the fingerprint becomes a contract. A committed env.expected file lets the tool fail a developer's first build with "your glibc is older than this project supports" instead of letting a confusing linker error happen twenty minutes later. The same file is a genuinely useful input to a Nix flake or devcontainer definition for teams that eventually want full reproducibility but can't start there.

Watch out for

Environment variables are where the secrets live, so redaction has to be allowlist-only and obvious in the output — one leaked token in a CI artifact ends the tool's credibility. The other risk is diff noise: if the default rules surface fifty meaningless differences, nobody reads the fifty-first.