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

dspec

v0.7.0

Published

Your coding agent answers from what your product is, not from what it can grep. dspec keeps a map of your codebase in .ds/ — what each feature is, where it lives, what it does, and what a change must not break — read by Claude Code, Codex and Cursor.

Readme

npm i -g dspec
dspec init

Then, in Claude Code, Codex or Cursor:

/ds-bootstrap

That's it. That's the whole tool.


The problem

You ask your agent a question about your own code. It has no idea what your product is, so it goes looking for one:

Grep "discount"            → 47 hits across 23 files
Glob "src/**/*.ts"         → 312 files
Read src/checkout/index.ts
Read src/checkout/cart.ts
Read src/pricing/rules.ts
Read 6 more files…

Every one of those files mentions the word. None of them says which one is the feature, and a search can't tell the difference — so the agent picks, reads, and assembles an answer out of whatever happened to share a word with your question.

Then it answers — fluently, in the same confident voice whether a sentence came from the file that implements the feature or from one that only mentioned it. Nothing in the answer tells you which.

That's the real bill. Not the tokens: the fact that you now have to go read the code yourself to work out which sentence to believe.

CLAUDE.md was supposed to fix this. It usually doesn't: someone writes it once, the code moves on, and nothing tells you it's now wrong.

What dspec does

/ds-bootstrap reads your codebase once — or, in a large one, a part at a time — and writes down what it found:

.ds/
  index.md         every feature: what it is, where it starts, what it depends on
  features/*.md    one file per feature — what it does, where it lives, the rules it enforces
  product.md       what the product is, and the rules that apply everywhere

Starting from a file instead of a question? Search .ds/features/ for its path — every feature lists the files it lives in, so the search names its owner.

dspec init adds a short instruction block to CLAUDE.md / AGENTS.md — the file your agent already reads at the start of every session — telling it to use that map first.

Now the same question goes:

Read .ds/index.md                     → "Apply discount" lives in src/pricing/discount.ts
Read .ds/features/apply-discount.md   → what it does, and when it refuses a second code
Read src/pricing/discount.ts          → the actual code

Three reads. No search. The session that wrote that file had read every file the feature lives in, and put down what they do: the rules the code enforces, the cases it refuses, the order its checks run in — each with the name you can search for, so the next read lands on the line.

What your agent does with it

Answering is the first use, not the only one. The same instruction block tells your agent to reach for the map whenever it is about to act on your code:

  • It answers from the feature, not from every file that happens to share a word with your question.
  • It plans with the blast radius in view. Before proposing a change it names the features the change touches and the ones that depend on them, and carries their rules into the plan — so the constraint turns up in the plan, not in a failing test or a reviewer's comment.
  • It knows what a change must not break. Before it edits a file it looks up the feature that owns it and reads the rules that feature's code enforces — and after the edit, it updates that feature so the next session reads what the code now does.
  • It reviews a diff by feature. Changed files are looked up to the features they belong to, and those features' rules are what the diff is checked against.

None of this is a command or a step you take. It is what an agent does when the file it reads at the start of every session tells it where the knowledge is.

Measured, honestly, on the same demo repository: three lookup questions with answer keys taken from the code, three runs each, graded blind. With and without the map, every session found the answer — fifteen files is small enough to read whole, so there was nothing for the map to save it from. On the question a feature file answers directly the map was a little faster; on the one that traces callers through the code it cost about twice the context. The tasks, rubrics, raw answers and one grading error are in demo/eval. What it does not measure is the case the map is for: a repository too large to read in a session.

Why you can believe the answer

A map that guesses is worse than no map, because every later session will trust it. So the instructions dspec installs are built to stop that happening, in four specific ways.

Nothing is claimed from a name. Where a feature lives and what it depends on are recorded from reading the files — never inferred from an import list, a directory name, or a word two files happen to share. The kind of connection a grep would have offered is exactly the kind that isn't allowed in.

Nothing is described unread. Every sentence in the map is something the agent read in the code — never what it expects the code to do, and never why somebody might have written it that way:

Never describe what you did not read.

That is the one failure that compounds: a confident sentence about code nobody read gets inherited by every session afterwards, each one equally sure.

The map checks itself. Once written, every path is verified to exist, every dependency to name a feature that exists, every name it points you at to still be findable, and no file of consequence to be left unclaimed — anything unclaimed is either misfiled or a feature that was missed. A map of a large repository that is still being built says which parts it doesn't cover yet, so an absence in it is never mistaken for an answer.

The code always wins.

If .ds/ and the code disagree, the code wins.

Your agent updates the feature file for whatever it just changed, as part of the work, not as a ceremony afterwards. After a big refactor — or a stretch of work by someone who wasn't using this — /ds-bootstrap rebuilds the whole thing. And because .ds/ is plain markdown committed to your repo, a wrong belief surfaces in code review like anything else, before it becomes the thing every future session is certain about.

There's one more thing the map carries: your words. The terms your team actually uses, and what each one means in this repository. Ask about "the discount" and your agent resolves the word to the feature you meant — not to all 47 files that spell it.

And it's cheaper, too

The map is written once and read many times. A feature file is a few hundred tokens; the search it replaces is tens of thousands — on every question, in every new session, for every person on your team.

The recording above, measured. One question — why does checkout reject my second discount code? — put to Claude Code twice, in the same repository, once with .ds/ committed and once without:

| | answered in | tokens through the context | cost | |---|---|---|---| | without dspec | 45s | 127,814 | $0.32 | | with dspec | 29s | 67,436 | $0.19 |

One run each, on the 15-file demo repository in demo/shop — clone it and check.

What that table measures is time, tokens and cost. Correctness isn't a number here; what stands in for it is the line above the table — which files each session chose to open. The cost gap grows with the repository, too: the map stays a few thousand tokens while the search it replaces grows with every file you add.

One person sets it up; the team gets it

.ds/ and the instruction block are committed, like any other file. So the developer who runs /ds-bootstrap isn't the one who benefits from it — everyone who pulls does, in their very next session, without installing anything or being told.

That's also how the map stays honest across a team. Nobody has to remember to update it: whoever touches the code has an agent that was already told to fix the feature file it just invalidated.

dspec is not a workflow

No spec to write. No plan to approve. No gate to pass. No process to adopt.

dspec doesn't change how you work — it makes your agent better informed at whatever you already do. .ds/ is just knowledge: what each feature is, and where it lives.

It sits between the tools you may already use rather than replacing any of them. Search and indexing tools find where code is. Spec tools agree what to change next. dspec is what the code already is, where each part of it lives, and what a change must not break — the part neither of the others keeps, and the part both of them work better with.

The two surfaces

| Where | What | |---|---| | Terminal | dspec init — installs the command into every agent it supports, and writes the instruction block | | Your agent | /ds-bootstrap — builds the map, or brings it up to date |

It asks nothing. One dspec init sets up all three:

| Agent | Command lands at | Reads | |---|---|---| | Claude Code | .claude/commands/ds-bootstrap.md | CLAUDE.md | | Codex CLI | ~/.codex/prompts/ds-bootstrap.md | AGENTS.md | | Cursor | .agents/skills/ds-bootstrap/SKILL.md | AGENTS.md |

Installing an agent you never open costs you one markdown file. Not installing the one you do open costs you a session where /ds-bootstrap isn't there and nothing says why — so dspec makes the cheap mistake, and you don't have to predict which agent you or a teammate will reach for.

Codex only reads prompts from your home directory, so its command isn't shared when a teammate clones the repo — they run dspec init once themselves.

Want fewer? dspec init --agent claude installs only that one. Anything you leave out is left exactly as it is — --agent adds, it never uninstalls.

A large repository, or a monorepo? Map it a part at a time: /ds-bootstrap services/billing, then the next app or service in another session. Each run writes as it reads, so one that stops half way leaves a map that is true as far as it goes. Until every part is done, the map names the parts it doesn't cover yet, and your agent searches those as it always did.

What it won't do

  • Call the network. Ever. No server, no account, no token, no telemetry, not even a version check. Upgrading is npm's job.
  • Install dependencies. Node 20+, and nothing else.
  • Touch a file it didn't write. Every file dspec installs is marked; dspec init deletes only marked files before writing them again. In CLAUDE.md / AGENTS.md it owns only the block between <!-- ds:begin --> and <!-- ds:end --> — every other byte is yours.
  • Read your codebase. dspec init installs files and nothing more. Deciding what your features are takes judgement, and that's your agent's job, not a CLI's.

Upgrading

npm i -g dspec@latest
dspec init          # rebuilds what dspec installed, from the new version

Start a new agent session afterwards so it picks up the rebuilt command.

0.2.0 removed everything that made dspec a workflow: the /ds and /ds-update commands, the session hooks, and the dspec sync | spec | accept | update verbs, along with code fingerprints, drift detection and the linter.

One dspec init removes every trace of them, including the hook entries the old version left in .claude/settings.json. Your existing .ds/ still reads fine — run /ds-bootstrap when convenient to bring it to the simpler format. Full detail in the changelog.

Feedback wanted

dspec rests on one bet: the map is prose an agent writes about its own repository, and no schema and no fingerprint validate it. There is one check, and it is deliberately cheap — a feature points you at a name and not just at a file, so a name that stops being findable says the code moved under the description. It tells you where to read, never what is now wrong. The rest is held up by the code wins and nothing is described unread.

If you think that isn't enough, that's the conversation I want: is a map an agent writes about its own repo trustworthy? Disagreement is more useful here than agreement.

Contributing

See CONTRIBUTING.md. The whole program is about a thousand lines, and it does one thing.

License

MIT