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

@parker-brown-family/craft-commit

v0.2.0

Published

Lint git commit messages for the narrative doctrine: a subject sentence and three why-focused paragraphs, no Conventional-Commits prefix, no 50/72 cap, no AI attribution. Written for the agent who reads the history next.

Readme

craft-commit

A deterministic, LLM-free commit-message linter that enforces a narrative doctrine — so the agent reconstructing your repository six months from now can read why it is the shape it is, not just what changed.

No LLM calls. No network. Pure parser. Exit code is the contract.


What it checks

A conforming message, in the default narrative style:

A subject line that is a sentence saying what happened

The state this commit selected — what the repository now is, in plain terms.

The problem underlying it — what was wrong, missing, or about to go wrong.
This is the paragraph that survives; a diff shows the change and never the reason.

How it was addressed — the approach taken, the numbers and files that mattered,
and what was deliberately not done.
  • The subject is a sentence, not a tag: no feat: / fix: prefix, no 50/72 cap, no trailing period.
  • A non-trivial body is three blank-line-separated paragraphs.
  • A trivial commit (a typo, a rename, a lockfile) is a subject line and nothing more.
  • No commit credits an AI as author or contributor.

The tool guarantees the form. It cannot judge the substance — whether the second paragraph truly states the problem, whether a rejected alternative is named, whether the prose reads well. Three empty-but-well-shaped paragraphs pass the shell. The words are still yours to get right; this catches only the structure a machine can see.

Why this, and not Conventional Commits

The 50/72-character subject convention was a Linux-kernel norm popularized in 2008 (tpope) for git log --oneline on an 80-column terminal. The reader is no longer on that terminal. It is a web UI that soft-wraps, or an agent with no column budget at all — so hard-wrapping at 72 mangles the one artifact that outlives every Slack thread and ticket a change references, and the 50-char subject cap truncates exactly the sentence that carries the meaning.

Conventional Commits (feat: / fix: prefixes) optimizes for changelog automation, and there is a live backlash that it makes the type prominent when the why is what matters (Evans, "Stop Using Conventional Commits"; HN; Lobsters). The enduring advice underneath the debate is older and unanimous: use the body to explain what and why, not how (Beams).

The agent-era case is sharper still. Stetsenko's Lore (arXiv:2603.15566) names the Decision Shadow: the reasoning behind a change — the constraints, the rejected alternatives — that the diff discards, turning working code into legacy code the moment it merges. A message that says only refactor: clean up utils transmits almost nothing to the next agent. A narrative that names the problem and what was deliberately not done transmits the shadow.

This doctrine is machine-global for its author, recorded in ~/.config/agents/AGENTS.md. craft-commit is its enforcer.

What a dumb linter can and cannot enforce

Enforced, deterministically (no LLM):

  • no Conventional-Commits prefix on the subject;
  • subject shape — capitalized, no trailing period, a soft length warning only;
  • a blank line after the subject;
  • three blank-line-separated paragraphs for a non-trivial body;
  • a body that is present when the commit is not trivial;
  • trailer hygiene — no Co-authored-by: / Generated with line crediting an AI.

Left to review or an LLM pass, because a parser cannot see it: whether the paragraphs carry the right content, whether the numbers and files that mattered are cited, whether a departure from a plan is explained. The tool says so rather than pretending, because a check that rewards filler is worse than no check.

gitlint is the conceptual kin here — it lints prose structure. commitlint is not — its whole model assumes the prefix grammar this doctrine drops.


Install & use

a) Agentic — integrate craft-commit into an agent harness

Primary use case. Paste this block into your agent's rules file — CLAUDE.md, AGENTS.md, .cursorrules, whatever your harness reads on startup:

## Commit messages — narrative doctrine (enforced by craft-commit)

Before running `git commit`, write the message to a file and lint it:

    npx -y @parker-brown-family/craft-commit <path-to-msg-file>

If the exit code is non-zero, rewrite the message until it passes. Every
non-trivial commit is:

1. A subject line that is a sentence — no feat:/fix: prefix, no length cap,
   no trailing period.
2. A blank line.
3. Three paragraphs: the state this commit selected; the problem underlying
   it; how it was addressed, and what was deliberately not done.

A trivial commit (typo, rename, lockfile) is a subject line and nothing more.
Never credit an AI as author or contributor. Never pass --lenient to bypass.

Then install the hook in every repo you want enforced:

cd your-repo
npx -y @parker-brown-family/craft-commit install-hook

From that point the agent's commits are machine-checked on every git commit. Failed messages print the specific issues and the agent self-corrects without revisiting this README.

b) Conventional — you're a human dev (maybe with light agent assist)

npm install --save-dev @parker-brown-family/craft-commit
npx craft-commit install-hook

Now git commit rejects any message that doesn't satisfy the doctrine. To bypass temporarily (e.g. during a git revert), run with --no-verify.


Reference

CLI

craft-commit <path-to-commit-msg-file>   # exit 0 valid, 1 invalid, 2 error
craft-commit                              # read from stdin
craft-commit --labeled <file>             # enforce the earlier labeled form
craft-commit --sections A,B,C <file>      # labeled form with custom labels
craft-commit --json <file>                # machine output
craft-commit --lenient <file>             # downgrade errors to warnings
craft-commit --no-color <file>            # disable ANSI color
craft-commit install-hook [path]          # drop .git/hooks/commit-msg
craft-commit --help                       # usage summary

Library

import { validate, formatHuman } from "@parker-brown-family/craft-commit";

const result = validate(fs.readFileSync(".git/COMMIT_EDITMSG", "utf8"));
if (!result.valid) {
  console.error(formatHuman(result));
  process.exit(1);
}

Options

| Option | Default | Effect | |---|---|---| | style | "narrative" | "narrative" or "labeled" | | maxSubjectLength | 100 narrative / 72 labeled | over it warns (narrative) or errors (labeled) | | minParagraphs | 3 | narrative: paragraphs a non-trivial body must have | | minParagraphWords | 3 | a shorter paragraph/section body warns | | lenient | false | downgrade all errors to warnings | | requiredSections | ["Selected State", "Underlying Problem", "How Addressed"] | labeled labels; passing it selects labeled style | | allowAiAttribution | false | permit AI-crediting trailers (don't) |

Issue codes

| Code | Severity | Meaning | |---|---|---| | subject.missing | error | commit has no subject line | | subject.conventional_prefix | error | subject uses a feat: / fix: prefix | | subject.too_long | warning (narrative) / error (labeled) | subject over the cap | | subject.trailing_period | warning | subject ends with . | | subject.lowercase_start | warning | subject begins lowercase | | body.missing_blank_after_subject | error | no blank line between subject and body | | body.too_few_paragraphs | error | non-trivial body has fewer than minParagraphs | | paragraph.too_short | warning | a narrative paragraph is thin | | trailer.ai_attribution | error | commit credits an AI as author/contributor | | section.missing / section.empty / section.too_short / section.out_of_order | error / error / warning / error | labeled-style section checks |

Provenance

The doctrine is recorded in ~/.config/agents/AGENTS.md ("Commit messages are narrative, and written for the agent who reads them next"). This linter is a standalone enforcer — no external dependency, no coupling beyond the pattern itself.

License

MIT