npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@hansenexus/mechanics

v0.2.0

Published

Behaviour specs with a coverage ratchet: one markdown file per behaviour, a committed manifest, CI-gated against drift, verified per wave. Ships a stdio MCP server and the docket/1 run protocol.

Readme

mechanics

mechanics.hansenexus.dev — docs, and a live coverage report.

npm ci licence

Behaviour specs with a coverage ratchet.

Every user-observable behaviour is one markdown file with labelled acceptance criteria. A committed manifest is compiled from them and gated against drift in CI. Every surface the project ships — route, endpoint, CLI command, scheduled job, whatever your adapters declare — must be claimed by a behaviour or explicitly ignored; anything else is a gap the build can be made to fail on.

The question it answers is "did we keep every behaviour?" during a rewrite or a redesign, and the reason it works is that the answer is checkable rather than asserted.

mechanics scan                     # every repo here, its stack, whether it is onboarded
mechanics init                     # set a repo up: config, corpus skeleton, CI, MCP
mechanics check --all              # corpus + waves + coverage
mechanics build --all --check      # drift gate
mechanics coverage --app=<slug>    # the table, the gaps, wave rollups
mechanics gaps --app=<slug>        # what is missing, split into fix / ask
mechanics report --html            # one self-contained page
mechanics mcp                      # serve the corpus to an agent over stdio
mechanics agents                   # which agent providers are reachable from here
mechanics run list                 # the docket/1 board
mechanics tui                      # leave it open: drift, gaps, runs, updates

What it looks like

Coverage is the whole idea: every surface the app ships, against every surface the corpus claims. What is left over is a gap with a name.

mechanics coverage — six surface kinds, four unclaimed surfaces named, and an open wave

The gate is what stops the corpus rotting. Edit a mechanic without rebuilding the manifest and CI says so; validation names every gap rather than totalling them.

the drift gate rejecting a stale manifest, and check naming each unclaimed surface

mechanics report --html is the same data as one self-contained page — no build step, no server, no external request. Attach it to a PR, or open it from file:// six months later.

the HTML coverage report: surface coverage bars, wave rollup with failures, and all 25 behaviours

Every one of those is generated from examples/perch by bun run docs:shots, so they are the real CLI's real output on a real corpus.

Any agent, not just one

The pipeline — scan, gaps, propose, fix — runs on whatever this machine actually has. mechanics agents probes and says which:

mechanics agents                                   # what is reachable
mechanics gaps --app=<slug> --agent=claude         # a harness edits the tree itself
mechanics gaps --app=<slug> --agent=ollama --model=qwen2.5-coder:7b
mechanics gaps --app=<slug> --agent=?              # pick from what responded

Two provider shapes. A harnessclaude, codex, qwen — is already an agent: hand it a brief in a worktree and it edits with its own tools. A modelollama, lmstudio, any OpenAI-compatible endpoint — is text in, text out and cannot open a file, so it answers in a small edit protocol that mechanics validates, applies, and rolls back as one unit if the result does not build. The protocol is exact-substring rather than a diff on purpose: a patch needs the model to count context lines, and a hunk that lands at the wrong offset still parses.

A provider may write mechanics, write specs, restructure app code — full reach over the tree. Four moves are refused whatever the provider: editing a wave file, promoting a draft to active, touching coverage.ignore, and flipping coverage.enforce. Those are not work, they are claims that the work is good.

Leaving it open

mechanics tui

A dashboard rather than a command: apps and their gaps, the issues worth acting on ordered by how quietly they fail, runs in flight, proposals waiting on you, and whether a newer release is out. It watches the corpus and .docket/, so it reacts to an edit rather than to a refresh.

It never writes. The manifest is diffed with check, and the fix and scan keys print the command instead of running it — a keystroke that mutates the repo behind a full-screen redraw leaves you no diff and nowhere for the output to go.

Onboarding more than one repo

mechanics scan inventories the checkouts under a directory and says which could be onboarded — stack, detected adapters, monorepo layout, and whether a config is already there. It collapses linked worktrees into their primary checkout, which is the difference between an honest count and a list that reports one monorepo eleven times.

mechanics scan --root=~/repos              # the inventory
mechanics scan --adopt=<repo>              # what init would write — nothing yet
mechanics scan --adopt=<repo> --yes        # write it

There is no adopt-all, and no prompt: naming the repo is half the confirmation and --yes is the other half, so the command behaves the same in a script as in a terminal.

Start here

npm i -D @hansenexus/mechanics && npx mechanics init      # single-app repo
npx mechanics init --app=<slug>                           # monorepo: apps/<slug>

Init is idempotent (every file is skip-if-exists) and writes the repo config, a corpus skeleton, the CI gate matched to your package manager and detected adapters, the .mcp.json registration, the .docket/ directory, and the committed manifest. --dry-run shows the plan; --no-ci, --no-mcp, --no-docket opt out. Then replace the starter mechanic with real behaviours — mechanics scaffold --app=<slug> drafts a stub per unclaimed surface.

Two worked examples ship with the package, and they show opposite ends of a corpus's life:

  • template/ — what init gives you, and the starting point for a fork: small, fully claimed, green. It ships no routes and no Convex functions on purpose, so generic-glob carries the whole inventory and nothing works by accident of the built-in adapters.
  • examples/perch — a corpus part-way through its life: 25 behaviours over three areas, both built-in adapters plus a glob-declared kind, four deliberately unclaimed surfaces, and a redesign wave in flight with failures and a blocker on it. It is what the screenshots above are pictures of, and a test asserts its gaps stay exactly the four it means to have.

What is in the box

| | | |---|---| | Core | parser, schema, manifest, coverage, waves, verify, CLI | | Adapters | nextjs-app-router, convex, generic-glob — plus the SurfaceAdapter seam, so a stack nobody wrote an adapter for declares its surfaces in config instead of forking | | MCP | six read tools over stdio: list, get, coverage, wave status, diff impact, decisions | | Report | --html: one file, no build step, no external request | | TUI | mechanics tui — the always-open view: drift, issues, runs, proposals, updates | | Agents | claude, codex, qwen, ollama, lmstudio — harnesses edit directly, models edit through a validated protocol | | Gaps | the five gap classes as predicates, each tagged auto (one correct answer) or propose (a judgment) — gaps --fix applies the first kind and refuses the rest in code | | Decisions | .docket/decisions/ — ADRs retrievable by the file you are about to touch; an accepted record whose affects.paths matches nothing fails check, and two open runs deciding about one subsystem get flagged | | docket/1 | the run protocol — work orders with checkable exit criteria and an append-only event log, with executable conformance vectors | | Plugin | three Claude Code skills: init, verify, gaps |

The two things it refuses to do

Record a verdict without evidence. pass requires an evidence string, at write time and again at read time. A hand-edited log cannot slip one through.

Let a model mark its own work green. The MCP server is read-only, and a test asserts no write-shaped tool name is advertised. Verdicts go through mechanics verify, which runs the specs, or verify --set, which is a deliberate human action. The same line runs through the agent loop: an agent may fix what has one correct answer, and may raise or reject a proposal, but mechanics run accept refuses any actor that is not human — accepting asserts a suggestion was right, which is the same act as marking work green. Both of those refusals are the whole value of the format; a convenient way around them would be a way of destroying it.

Stated plainly, because the alternative is overclaiming: the actor check infers human from the absence of an agent session variable, so a process that unsets it is indistinguishable from a person. It removes the default path and nothing more. The durable boundary is that proposals and their resolutions are committed files somebody reviews.

Runtime

The mechanics bin is a bundled Node build (dist/cli.js), so both npx mechanics and bunx mechanics work with no Bun requirement at use time. The package also ships its TypeScript source, importable directly under Bun (≥ 1.2), which is what development and the test suite run on.

Releases are published from CI over npm Trusted Publishing, so the tarball on npm carries a signed attestation tying it to this repository and the commit it was built from. repository in a package.json is a claim anyone can make; the attestation is the part that can be checked. There is no publish token to leak or rotate — npm verifies the workflow's OIDC identity directly.

Licence

MIT. The protocol specification in spec/ is additionally available under CC BY 4.0, so another implementation may reuse its wording with attribution. See LICENSE.