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

@endermalkoc/cusp

v0.12.0

Published

Keep a spec corpus tidy, uniform, and traceable — lint preset + trace scanner + generated views for markdown specs. No database, no server.

Readme

cusp

Keep a markdown spec corpus tidy, uniform, and traceable — so humans and coding agents get complete, cheap, trustworthy answers from plain files.

cusp is a lint preset + trace scanner + generated views for repositories where requirements live as markdown and are worked on by people and LLM agents together. Markdown stays the single source of truth. There is no database, no server, and no query language to learn — cusp adds only checks on your authored files and derived artifacts built from them, the way eslint or tsc do.

npx @endermalkoc/cusp check .

Why it exists

When a requirement is referenced many different ways — a bare id here, the spec's title in prose there, a vague allusion somewhere else — an agent asked "what does changing X affect?" has to run several different searches, blows its output budget reconciling them, and then answers incompletely while reporting the answer as complete. That failure is silent, which makes it the dangerous kind.

The predecessor project measured it: on a 700k-token corpus, an agent recovered a complete 1,365-item blast radius for ~$2 when the corpus used one uniform reference form, and 17% of it for ~$4.43 — claiming completeness when the same facts were rendered free-form. Twelve pre-registered experiments tried databases, graph queries, and enforcement gates on top of capable agents; every one of those lost to plain markdown plus agent diligence. The single mechanism that won was the uniform rendering. cusp is that mechanism, packaged: it keeps the corpus uniform so the cheap-and-complete path is the only path.

The full evidence ledger — every claim, its pre-registered kill-test, and the honest results (including a weak one) — is in docs/EVAL.md.


Install

cusp is a single npm package with a small, boring dependency set (unified/remark for markdown parsing, yaml). It runs on Node 18+.

# one-off, no install
npx @endermalkoc/cusp check .

# or as a dev dependency (recommended — pins behavior, enables the fast local hook path)
npm  install -D @endermalkoc/cusp
pnpm add     -D @endermalkoc/cusp

Then, optionally, scaffold the convenience files (all optional — zero-config cusp check works without any of them):

npx cusp init .

init is idempotent and never touches existing content. On a repo it recognizes as using Claude Code, it also wires an edit-time hook (see Agent integration).


The house grammar (what "uniform" means)

cusp enforces one grammar so the corpus stays greppable. The whole grammar is in docs/GRAMMAR.md; the load-bearing parts:

One ID namespace. Requirements are PREFIX-FR-NNN (an optional single-letter variant suffix is allowed, e.g. ADDR-FR-006a). Specs, test plans, and test runs share the namespace.

Two ways to declare a requirement, and no third:

### ASGL-FR-002 — privilege-gated column        (block form: statement + prose below)
The system MUST hide the column from unprivileged users.

- **ASGL-FR-002**: The system MUST hide the column from unprivileged users.   (list form)

Exactly one way to reference one, from anywhere:

[ASGL-FR-002](../staffing/assignment-list.md)

The link text is the bare id; the target is the spec file. Everything else — a bare id in prose, a spec's title dropped into a sentence, a registered alias of a title — is a lint violation (ref-canonical / no-allusion). Those are precisely the reference forms that caused the measured recall cliff, so cusp treats them as errors and can auto-fix them into canonical links.

Citations are the only authored trace link. Code and tests cite the ids they implement/verify — in a test name (frTest(["ASGL-FR-002"], …), it("ASGL-FR-002: …")) or an @fr ASGL-FR-002 comment. Whether a requirement is implemented, tested, or orphaned is then computed from those citations, never hand-maintained.


Commands

Each command is a build step: it reads files and writes files. None runs at application runtime.

| command | what it does | |---|---| | cusp check [.] | Lint the corpus against the house grammar and run policy checks. Exit 1 on lint findings or a failing policy. --json for machine output; --now DATE to fix "today" for staleness rules. | | cusp scan [.] | Compute the trace and write docs/specs/index.md (the generated id index) + trace.json (the full FR ↔ code ↔ tests ↔ plans ↔ runs join). --check verifies the index is fresh without writing (exit 1 if stale). | | cusp report [.] | Render cusp-report.md — the ten-second per-FR coverage view over the trace. | | cusp fix --intake [.] | Deterministically adopt a messy existing corpus: normalize frontmatter, rewrite unambiguous bare ids to canonical links, regenerate the index. Never guesses; everything it can't safely handle is reported in intake-report.json, never silently dropped. | | cusp fix --allusions [--llm] [.] | Resolve prose allusions (title/alias mentions) into canonical markers, preserving the prose. With --llm, a classifier first decides referential-vs-incidental; its verdicts persist to cusp-allusions.yml (reviewed like code) so they are never re-computed. | | cusp fix --migrate [.] | Upgrade a corpus to the current grammar version, applying the ordered, idempotent, meaning-preserving migration steps and stamping grammar: in the config. cusp check refuses a grammar newer than the installed package and notes one that is stale. | | cusp init [.] | Scaffold the convenience files + a starter corpus. Idempotent; never overwrites existing content. | | cusp upgrade [.] | After bumping the dependency, refresh cusp-owned artifacts (hook command, version pins, the AGENTS.md section) to the running version. Anything you've customized is reported, never touched. | | cusp hook / cusp hooks | The edit-time hook, and the command that wires it into .claude/settings.json. See below. |

Typical CI job:

npx cusp check . --json > cusp-check.json || (cat cusp-check.json; exit 1)
npx cusp scan  . --check          # fail if the committed index is stale

How it works

Five small components, one data flow, no runtime. Everything is either a check on authored files or a derived artifact — see docs/ARCHITECTURE.md for the full diagram.

  1. Lint preset — markdownlint (hygiene) plus a remark plugin carrying the house rules (ref-canonical, no-allusion, frontmatter-schema, id-integrity, index-fresh, …). Each rule is invariant-shaped and cites its grammar section. The allusion detector is shared verbatim with the fixer, so the linter and the auto-fixer can never disagree.
  2. Scanner — one stateless pass over the corpus + src/** and tests/** citations produces the generated index and trace.json. Test-vs-code is classified by file convention (.test./.spec., __tests__/e2e directories, _test.go, test_*.py), so tests interleaved under src/ in a monorepo are attributed correctly. A citation is counted only in its structured form (an id in a test-launcher title/id-array or after @fr); a bare id token in a comment or prose is recorded as a loose mention, never miscounted as coverage. "The graph is a grep": no state, re-runnable from scratch in seconds.
  3. Policy checks — deterministic assertions over the trace (orphan citation, untested FR in an active milestone, stale run, …), warn-first by default and promotable to CI-failing per corpus. Policies gate only on computed facts, never on model judgment.
  4. Fixer — a deterministic tier (formatting, bare-id → link, index regeneration, intake) and an optional LLM tier (allusion classification). The LLM only proposes; every proposal must pass the full lint suite before it lands. LLMs propose, deterministic checks dispose.
  5. Report — generated markdown views over the trace: the read surface, never hand-edited.

Configuration

All optional. cusp.config.yml at the corpus root; every value shown is the default:

grammar: 1                   # the grammar version this corpus targets (`cusp fix --migrate` to upgrade)

policy:
  staleDays: 90              # run-staleness threshold for policy checks
  fail: []                   # promote policy rules to CI-failing, e.g. [orphan-citation]

llm:                         # classifier for `cusp fix --allusions --llm`
  command: claude -p         # ANY headless agent CLI: prompt on stdin, JSON array on stdout
  batch: 40                  # allusions per call
  concurrency: 4             # concurrent calls
  timeout: 120000            # ms/call; a failed or timed-out call degrades to "skip", never converts

citations:
  exclude: []                # globs for files that are never citations (fixtures, generated output)
  tests:   []                # extra globs that mark a path as a test (beyond the built-in conventions)

The llm.command being any headless CLI is deliberate: cusp handles no API keys and bundles no model SDK. Auth is the CLI's problem.


Agent integration

cusp is built for repos where coding agents edit specs. Two touch points, both plain files:

  • AGENTS.md / CLAUDE.md sectioninit adds a short marker-delimited block describing the grammar and the commands. It is documentation, not a framework.
  • Edit-time hookcusp hooks wires a PostToolUse hook into .claude/settings.json. After an agent edits a spec, the hook lints just that file and feeds any violation straight back into the agent's context, so drift is corrected in the same turn rather than caught later in CI. The hook is format-only, quiet on files it didn't touch, and runs in ~20 ms via the locally installed package (falling back to npx). In a controlled benchmark this held an actively-edited corpus at zero drift across six rounds while a norms-only arm accumulated monotonically.

Project documents

| doc | what it pins down | |---|---| | docs/VISION.md | the one job, and what cusp is not | | docs/CONSTITUTION.md | binding design constraints, each citing the experiment that paid for it | | docs/GRAMMAR.md | the full house grammar: layout, reference form, ID namespace, sidecar + run-log schemas | | docs/ARCHITECTURE.md | the five components and the data flow | | docs/DISTRIBUTION.md | one npm package, npx cusp init, versioned grammar | | docs/EVAL.md | the claim ledger: every capability's pre-registered kill-test and honest result | | ROADMAP.md | what is built, what is left, and what is deliberately never coming |


Design commitments

cusp is bound by a constitution written from the predecessor's evidence. The load-bearing ones: prose is the source of truth (I); authored intent and derived facts are separate artifact kinds (II); uniformity is the product (III); the graph is a grep — no stored index of record (IV); LLMs propose, deterministic checks dispose (V); no runtime (VII); boring dependencies (VIII); every capability ships with a pre-registered kill-test (IX); and a standing list of non-goals — no database, no server, no query CLI (X). npm test re-runs all 16 kill-tests.

Development

npm test        # run every pre-registered kill-test (~seconds)

The benchmark harness that produced the founding claims lives in bench/ and is still runnable; the findings are in research/.

License

MIT.