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

@frycz/dfa

v0.2.0

Published

Scaffold and maintain a doc index (INDEX.json/INDEX.md over frontmatter-tagged docs) for AI coding agents, wired into Claude Code, Cursor, and other agent adapters.

Readme

dfa — docs for AI

Scaffold and maintain a doc index for AI coding agents: a flat .dfa/index.json + docs/_index.md over a tree of frontmatter-tagged docs, wired into whichever agent(s) your project uses (Claude Code, Cursor, AGENTS.md, or a custom instructions file). Design rationale is in cli.md; the build plan is in implementation-plan.md.

Install

# try it without installing
npx @frycz/dfa init

# for regular use — installs the `dfa` command
npm i -g @frycz/dfa

Quickstart

# interactive: pick which agent(s) to wire up
dfa init

# scaffold a new doc with frontmatter pre-filled
dfa new auth/api.md

# regenerate docs/_index.md + .dfa/*.json
dfa index

# validate + drift-check; exit 1 on problems (CI)
dfa check

init writes:

<project root>/
  dfa.config.json          agent selection + doc/notes dir names
  CLAUDE.md                 if `claude` selected (marker-block managed)
  .cursor/rules/dfa.mdc     if `cursor` selected
  AGENTS.md                 if `agents-md` selected
  .dfa/
    index.json               every doc root's docs + nested projects, for tooling
    diagrams.json            diagram registry; populated as Mermaid diagrams appear
  docs/                      one doc root (add more with --docs-dir)
    _index.md                the index agents read first
    _style.md                authoring spec agents must read before writing docs
    overview.md              starter doc
                             (add _section.md to a subdirectory to give it its own index)
  notes/
    .gitkeep

Re-running init (or sync) is always safe: it never overwrites existing doc content, and every file it injects into keeps any content you added outside its <!-- dfa:start -->…<!-- dfa:end --> markers. (dfa index makes one narrow exception, pruning a related entry whose target was deleted — see Doc frontmatter.)

Multiple doc roots

A project can own several doc roots — useful in a monorepo where docs sit beside the code they describe:

dfa init --agent claude --docs-dir "docs,packages/api/docs"

dfa.config.json stores them as docsDirs: ["docs", "packages/api/docs"]. One project, one .dfa/index.json, one dfa check. Each root gets its own _index.md (listing only that root's docs, with pointers to the others) and its own _style.md, so an agent working in a root finds its index and conventions next to the docs. In index.json, each entry carries the docsDir it came from and a path relative to that root, so two roots can hold same-named docs without colliding. A related entry resolves inside its own root — a pointer that crossed roots would make one root's validity depend on another's contents.

dfa new packages/api/docs/auth.md infers the root from the path; --docs-dir names it explicitly; otherwise the first configured root wins.

The legacy single docsDir: "docs" config is still read and normalized to a one-element docsDirs.

Sections

When one subtree of a doc root grows big enough to crowd out everything else, give it its own index. A directory becomes a section by holding an authored _section.md:

# scaffolds the marker
dfa new docs/api/_section.md
dfa index
---
title: HTTP API reference
summary: Per-endpoint reference for the public HTTP API — auth, pagination, error codes.
tags: [api, http, reference]
---

Those three fields become the section's row in docs/_index.md, in place of every row its docs would have taken:

## Sections

| Section | Title | Summary | Tags | Index |
|---|---|---|---|---|
| `api/` | HTTP API reference | Per-endpoint reference… | api, http | `docs/api/_index.md` (42 docs) |

dfa index generates docs/api/_index.md alongside the marker, listing the subtree's docs and linking back to the doc root's index and _style.md. Sections nest: the nearest enclosing _section.md owns a doc.

Unlike a nested project, a section is not a boundary — it only splits the markdown. Its docs stay in one .dfa/index.json (each tagged with the section that owns it), in one dfa check, and related still points across sections freely. Every path in every index under docs/ stays relative to docs/, so there is one path convention per doc root, not one per index.

Deleting the _section.md folds the subtree back into the root index; the next dfa index sweeps up the generated _index.md it leaves behind, and dfa check fails until you run it. A _index.md dfa did not write is never touched.

Nested projects

A directory with its own dfa.config.json is a separate project, not part of the parent. Every tree walk stops at that boundary, so the parent never indexes, validates, or lists a child's docs — and the child is fully operational from its own root, with its own index, style guide, and dfa check.

The parent still sees it. dfa index records nested projects in .dfa/index.json and adds a Nested projects section to each _index.md pointing at the child's index — so an agent reading the parent index knows the child exists and can follow into it only if the task is there.

$ dfa list
docs/overview.md           — Overview
packages/api/docs/auth.md  — Auth
packages/web/              — project (1 doc) — run dfa there, or -r

-r, --recursive extends list, tree, index, check, and grams into every nested project (recursively). Writes always stay per-project: index -r makes each project write its own files, never a merged one, and check -r fails if any project fails. grams -r qualifies a child's diagram ids (packages/api#1), since ids are per-project counters.

What the parent records about a child is identity only — its root and doc roots, never a doc count. A count would make the parent's index go stale every time a child added a doc, which is exactly the coupling these boundaries exist to prevent.

Layout

Two kinds of file, split by who reads them:

  • docs/_section.md is the one file here a project authors rather than reads: dropping it into a directory turns that subtree into a section (see above). Only its frontmatter is read.
  • docs/_index.md and docs/_style.md live with the docs, because agents read them as markdown. The leading _ marks them as not-a-doc: they carry no frontmatter, sort to the top of a listing, and every command that walks the tree skips them. That prefix is a general rule, so docs/_draft.md is likewise ignored by index, check, tree, and grams.
  • .dfa/index.json and .dfa/diagrams.json live in a hidden directory at the project root, next to dfa.config.json. Nothing reads them as prose — they're machine state — so they stay out of the doc tree entirely.

Every _index.md and both JSON files are generated; never hand-edit them. dfa index rewrites them all.

docs/_style.md

init scaffolds an authoring spec at docs/_style.md, and the block injected into CLAUDE.md / AGENTS.md / .cursor/rules/dfa.mdc tells the agent to read it before creating or editing any doc. It covers what each frontmatter field must contain (especially summary, which is the routing signal in _index.md), one-subject-per-doc, writing for retrieval rather than for end-to-end reading, where Mermaid fences go so their anchors resolve, and what never belongs in a doc.

It is scaffolded once and never overwritten — edit it to match your project's conventions and init/sync will leave your version alone.

Commands

| Command | What it does | |---|---| | dfa init [dir] | Scaffold docs/, notes/, the index files, and the chosen agent config file(s). | | dfa new <path> | Scaffold a new doc under docsDir with the frontmatter template pre-filled — or, for <dir>/_section.md, the marker that makes that subtree a section. | | dfa index | Regenerate every _index.md (doc roots and sections), .dfa/index.json, and .dfa/diagrams.json from frontmatter. | | dfa check | Validate frontmatter and drift-check the generated files; exits 1 on problems — wire into CI. | | dfa agents | List supported agent adapters and which are configured/detected in this project. | | dfa sync | Reapply the managed config block to every configured agent's file(s). | | dfa list | List every doc as a project-root-relative path with its title, one per line, in tree order. | | dfa tree | Print the doc tree — authored docs only, with their titles; generated files are left out. |

Both take -d, --depth <n> to limit how deep they go: dfa list -d 1 shows only the docs directly in docsDir, and dfa tree -d 1 collapses each subdirectory to a single line with a count of the docs beneath it. | dfa grams | List the Mermaid diagrams found across the docs, with their stable ids and anchors. | | dfa root | Print the project root — the nearest ancestor directory holding dfa.config.json. |

init covers first-time setup; sync re-runs the same injection logic later — after editing docs, changing the agent list, or upgrading dfa.

Every command except init finds the project itself: it walks up from the current directory to the nearest dfa.config.json, the way git and npm locate their roots. So they work from anywhere inside the project — no path argument to pass or get wrong. dfa init [dir] still takes a directory, since that is what creates the config in the first place.

init flags

  • --agent <ids> — comma-separated agent ids, or all. Skips the interactive picker (needed for non-interactive/CI use).

Doc frontmatter

Every doc under docsDir needs:

---
title: Some Title
summary: One or two sentences an agent can match against a task.
module: some-module
tags: [a, b, c]
related: [path/to/doc.md, other/doc.md]
---

dfa check fails the build if a required field is missing or a related path doesn't resolve to a real doc.

dfa index treats those two differently, because index heals and check gates. Frontmatter it cannot turn into an index row — missing or unparseable fields — stops the write entirely, since an index silently missing a doc is worse than one that is visibly stale.

A dangling related is repaired instead. It is what deleting a doc leaves behind, so dfa index drops the entries whose target is gone and says which:

$ rm docs/auth/tokens.md && dfa index
Pruned from docs/auth/api.md: auth/tokens.md (no such doc)
Wrote docs/_index.md, .dfa/index.json (12 docs, 1 diagram).

This is the only case where dfa writes into a doc you authored, so it edits as little as it can: just the dead entries, leaving key order, quoting, and the body byte-identical. A related list it cannot read with certainty — one split across several lines, say — is reported and left alone for you to fix, and dfa check keeps failing until you do.

Agent adapters

| id | file(s) written | |---|---| | claude | CLAUDE.md | | cursor | .cursor/rules/dfa.mdc | | agents-md | AGENTS.md | | generic | a path you set as genericTarget in dfa.config.json |

The notes/ boundary is an instruction in the injected block, the same for every adapter. dfa no longer writes a permission deny rule into .claude/settings.json — permissions are the user's file to own, and a rule dfa installs on their behalf is a surprise in the one file where surprises are expensive. sync removes the rules older versions wrote, leaving any others intact.

Why this pattern

Long specs read fully by an agent burn context on parts that don't matter to the task at hand. dfa implements a flat index — path | title | summary | tags — that an agent reads first and uses to pick only the docs it actually needs, instead of loading everything. See cli.md for the design and its idea.md/docs-spec.md references (in the sibling doc-index repo this tool grew out of) for the full pattern writeup and doc-authoring conventions.

Development

npm install
npm run typecheck
npm test
npm run build

Link package locally

npm run build && npm link

src/core/ holds the framework-agnostic logic (frontmatter scanning, index/diagram-registry generation, marker-block injection); src/adapters/ holds one file per supported agent; src/commands/ wires both into the CLI defined in src/cli.ts.

Publishing

The package is on npm as @frycz/dfa — public despite the scope, because publishConfig.access says so, which is why no --access flag appears below. Releases are cut by hand from a clean main; CI runs the tests but never publishes.

# once per machine — check with `npm whoami`
npm login

git switch main && git pull

# bumps package.json, commits, tags vX.Y.Z
npm version minor

# prepublishOnly runs typecheck + test + build first
npm publish

# push the release commit and its tag
git push --follow-tags

Two guards make a broken release take deliberate effort: npm version refuses to run on a dirty tree, and prepublishOnly refuses to publish code that doesn't typecheck, test, and build.

Choosing the bump

| bump | when | |---|---| | patch | fixes that change no flag, no generated file, and no library signature | | minor | new commands or flags, new generated files, additive exports from src/index.ts | | major | anything that breaks an existing project: a renamed flag, a changed file layout, a changed library signature |

dfa writes into other people's repos, so weigh a release by what it does to a project that upgrades and re-runs dfa index, not by how the CLI's surface looks. A change to what init scaffolds or what index generates reaches every project that upgrades, even when every command and flag stayed the same.

Before you publish

files: ["dist"] limits the tarball to the build output; npm always adds README.md, LICENSE, and package.json. To see exactly what would go out — and run the full prepublishOnly chain against it — without uploading anything:

npm publish --dry-run

It ends with the file list, the total size, and the line Publishing to https://registry.npmjs.org/ with tag latest and public access (dry-run). No npm login is needed for that.

After you publish

npm view @frycz/dfa version

# runs the published bits, not your working tree
npx -y @frycz/dfa@latest --version

# a real smoke test, away from this repo
mkdir /tmp/dfa-smoke && cd /tmp/dfa-smoke
npx -y @frycz/dfa@latest init --agent claude && npx -y @frycz/dfa@latest check

If a release turns out to be broken, prefer publishing a fixed patch version and npm deprecate @frycz/[email protected] "use X.Y.Z+1" over npm unpublish. Unpublishing breaks anyone who already installed that version, and npm will not let you reuse the version number afterwards.