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

@punchsoftware/groom

v0.9.0

Published

A markdown-native project roadmap that lives in your repo

Readme

groom

A project roadmap that lives in your repo as markdown files.

Roadmaps rot. They live in a doc nobody opens, drift from what's actually being built, and get rewritten from scratch every quarter. groom puts the roadmap next to the code, computes progress instead of asking you to type it, and tells you where it has stopped matching reality.

groom
2 outcomes · 12 projects · 19/24 done

◆ Activation is something users hit on day one       ██████████ 100%  2026-07-20 → 2026-09-30
  ├─ ● P-1  Frictionless sign-up                     ██████████ 100%  2026-07-20 → 2026-07-22
  │   ├─ ● P-5  OAuth flow
  │   └─ ● P-6  Session management
  └─ ● P-2  Local web UI                             ██████████ 100%  2026-07-25 → 2026-08-05
◆ groom is something people can install and trust    ░░░░░░░░░░   0%  2026-08-01 → 2026-11-30
  ├─ ○ P-3  Packaging and distribution               ░░░░░░░░░░   0%  2026-08-01 → 2026-09-15
  └─ ○ P-4  Docs and onboarding                      ░░░░░░░░░░   0%  2026-08-15 → 2026-10-15

The idea

Two altitudes:

  • Outcome — a customer or business capability you want, with a metric. Not a feature.
  • Project — a bounded body of work that materially advances that outcome. Projects nest: a project can sit under an outcome or under a parent project, to whatever depth the work needs.

Only leaf projects report truth. A leaf project — one with no sub-projects — is either done or it isn't; every parent above it (a project with sub-projects, or an outcome) is the weighted mean of its children. There is no field anywhere to type "80% complete" — that number is the single most common lie in project tracking, and groom simply doesn't offer it. Started work earns no partial credit. If you want a number to move, close a leaf project.

Install

groom runs on Node 20 or newer:

npm install -g @punchsoftware/groom

Or from source:

npm install
npm run build                # → dist/groom.js

Getting started

groom init "Acme Platform"

groom outcome add "Grow activation 20%" --metric "12% → 20%" --target 2026-12-31
groom project add "Auth revamp" --parent O-1 --start 2026-06-01 --target 2026-09-30
groom project add "OAuth flow" --parent P-1 --status done
groom project add "Session mgmt" --parent P-1

groom              # the outcome tree
groom timeline     # a Gantt chart of dated work
groom drift        # where the roadmap disagrees with reality
groom outlook      # overdue work, the next 30 days, and undated active work
groom archive --done-before 90d --dry-run  # preview cleanup of old finished work

Everything is a file:

roadmap/
  config.yml
  outcomes/    O-1 - Grow activation 20%.md
  projects/    P-1 - Auth revamp.md
--- # projects/P-1 - Auth revamp.md
id: P-1
title: Auth revamp
parent: O-1
status: in-progress
start: 2026-06-01
target: 2026-09-30
owner: brdsmth
---

## Why
Sign-up drop-off is concentrated on the password step.

A project's parent is an outcome or another project — that's all nesting is. Edit these files in your editor, commit them with your code, review them in a PR. groom reads whatever is on disk.

Autocommit

If you'd rather never think about committing the roadmap — especially when agents are the ones editing it — set autocommit: true in roadmap/config.yml (or start with groom init --autocommit). Every change groom makes is then committed to the host repo on the spot, and the log reads like a changelog:

chore(roadmap): update P-1 (status in-progress → done)
chore(roadmap): create O-2 "Reduce churn"

A batch of edits — an agent's burst of tool calls, a drag-reorder in the web UI — lands as a single commit. Commits are scoped to roadmap/, so whatever else you have staged stays staged and untouched, and git trouble (no repo yet, no identity configured) never blocks the edit itself: the file is written, the commit is skipped with a warning. groom never pushes.

Drift

The failure mode of every roadmap is quiet rot. groom drift names it:

| Rule | Fires when | |---|---| | slipping | Past its target date and still open | | at-risk | More schedule spent than work done | | stalled | A project marked in progress, but every project under it is still planned | | childless | An outcome with no projects | | orphaned | A project serving no outcome | | stale | Untouched longer than staleAfterDays | | upstream-closed | A linked GitHub issue closed while the project stayed open |

Every finding carries a remedy, not just a complaint. groom drift --strict exits non-zero, so roadmap hygiene can gate CI.

Known findings can be acknowledged through a review date without deleting the underlying commitment:

groom drift ack P-12 slipping --until 2026-10-15 --note "pending October planning"
groom drift --all                 # includes active acknowledgements, marked acked
groom drift unack P-12 slipping

The acknowledgement is stored in the entity's drift frontmatter list. It is suppressed from drift reports and summaries until the date passes; expired entries fire again and validation suggests extending or removing them.

staleAfterDays (default 30) controls stale findings and when old stalled or orphaned work escalates to high severity. slippingHighAfterDays (default 14) controls when a missed target escalates to high severity.

Slack delivery can add shared thread links and resolve owners without putting delivery logic in the caller:

links:
  roadmap: https://roadmap.example.com
  outlook: https://roadmap.example.com/outlook
  drift: https://roadmap.example.com/drift
owners:
  bradley: { slack: U012345, name: Bradley }
backlogOutcome: O-19
maxBodyLines: 120

Owner keys match frontmatter case-insensitively with surrounding whitespace trimmed. backlogOutcome excludes that outcome from schedule risk and the Gantt. maxBodyLines controls the body-oversized validation warning so roadmap files do not become notebooks. A non-empty owners map makes unknown owners a validation warning. It also defines the People filter and owner suggestions in the web UI, including people with no assigned work. Historical owners outside that roster remain on their items but do not become options. Slack user mentions appear only on attention and overdue lines; other sections use the configured display name.

Planning, not just tracking

Keep outcome, project, and milestone titles succinct, professional, and explicit. Use a short phrase in sentence case that names the capability, deliverable, or gate. For example, use Add invoice downloads to billing history instead of Billing improvements. Avoid filler, hype, and owner or status notes; put implementation details and acceptance criteria in the body. The same guidance applies when renaming items and is included in groom guide, the web Guide, and the MCP workflow and tool instructions.

Hierarchy and rollup are not enough for an agent to decompose work well. Left alone, an agent turns every checkpoint in a plan into a project, because the create call accepts any title under any parent. groom now carries the structure the decision needs, and pushes back at the moment it matters.

| Command | What it answers | |---|---| | groom next | Which leaf projects are executable now, and what the rest wait on | | groom outlook [--days 30] | What is overdue, promised next, blocked, or active without a date | | groom critical-path [id] | The longest chain of dependent open work | | groom validate --strict --json | Everything structurally wrong with the files, with a stable code each | | groom project classify "<title>" --parent P-1 | Is this a project, a milestone, a step, or a duplicate? | | groom project decomposition P-1 | Has this parent been split well? | | groom lanes [id] / groom collisions | What can safely run at once, and what must not | | groom context P-7 | Everything needed to execute one project, in one packet | | groom task plan P-1 | Proposed waves and bundles for handing a program out | | groom project complete P-7 --commit <sha> --test "npm test=passed" | Close with evidence, and see what it unblocked |

The data behind them lives in project frontmatter and is optional throughout:

dependsOn:                 # execution order; parent is hierarchy only
  - id: P-4
    reason: contracts must be frozen first
milestones:                # gates inside the project — never in the rollup
  - id: shadow-green
    dependsOn: [behavior-frozen]
    approvalRequired: true
execution:                 # what must not run alongside this
  lane: invoice
  mode: serial
  resources: [invoice-ingestion]
implementation:            # the seams, so collisions are caught before merges
  owns: [invoice-ingestion]
  touches: [shared-document-outcomes]
  relevantFiles: [server/invoiceOps.ts]
executionPlan:             # on a parent: waves its sub-projects run in
  - { mode: serial, projects: [P-5, P-6] }
  - { mode: parallel, projects: [P-7, P-8] }
completion:                # recorded when it closed
  commit: 00cbb245
  tests: [{ command: npm test, result: passed }]
  acceptance: { "Processing is idempotent": passed }

Creating a project runs an overlap and decomposition check first. A title that duplicates open work, is phase-shaped ("Phase 3"), restates its parent, names a stage of it ("Testing", "Rollout"), or extends a strict chain of sibling checkpoints is refused with a recommendation — add a milestone, put it in the parent's body, update the existing project. --force or a stored creationReason overrides it, on the record.

Every entity carries a revision; pass it back with --if-revision (or ifRevision over MCP) and an edit fails with a conflict instead of overwriting a change made since you read. Edits always patch over the freshest copy on disk, so two agents changing different fields both land. groom project claim P-7 --by <name> tells other agents a project is taken.

Three config keys tune the structural checks: maxActiveChildren (default 8), maxProjectDepth (default 2), and requireCompletionEvidence (default false, which makes a done-without-evidence a note rather than a warning).

Ratcheting existing validation debt

A roadmap with known validation issues can still gate CI without accepting new ones. Capture the current issue identities, then run strict validation against that baseline:

groom validate --write-baseline roadmap/.validate-baseline.json
groom validate --strict --baseline

--baseline with no path uses roadmap/.validate-baseline.json; an explicit path is also accepted. The baseline keys issues by stable check code and entity id, so wording changes do not create false failures. Fixed entries are printed under "can be pruned" and do not fail the run. Use --prune to remove them.

Sharing it

groom export -o roadmap.html            # static: no scripts, no fonts, no CDN
groom export --interactive -o team.html # one read-only file with the full app
groom export --format md                # narrow enough to paste into a PR or email
groom gantt --format svg                # large-type timeline for an image post
groom gantt --format html               # self-contained page for Chromium screenshots

The static export is the roadmap as a document: the outcomes, the timeline, the board, and the needs-attention list, with <details> for collapsing and not a line of script. --interactive is how you hand the roadmap to someone who doesn't run groom: the same five views as groom web, the inspector included, with the snapshot inlined and editing removed. It makes no network requests and needs no server. Both render from the same snapshot the web UI uses, so an export never disagrees with the live view about a bar or a card. --no-drift omits drift findings from the export.

gantt defaults to 60 days before today and 45 after it. Use --days-before, --days-after, --max-projects, --width, and --theme light|dark to tune the image. It shows undated active work explicitly rather than inventing dates, and omits the outcome configured as backlogOutcome.

The web UI

groom web --open

Five views over one snapshot, with a slide-over inspector:

  • Timeline (the default) — one row per project, grouped by outcome in priority order. Choose This week, This month, or This quarter in the horizon strip to zoom the timeline; it stays a timeline, and remembers the range. The window begins on Monday of this week and ends at the selected horizon (quarter by default). Short windows show daily ticks. Bars end on the target date; a project with no start fades in from the left, one whose dates come from its sub-projects is dashed, and one past its target runs to today with a red cap. A project with no target gets no bar — it's listed under No target date instead. Dates are never invented.
  • Board — Backlog (the backlog outcome, later targets, no target) at the far left, then Next (due this quarter), Now (due this month, or in progress), and Shipped (closed in the last 30 days, dated from git). Every column uses the same level: projects directly under outcomes, plus unattached projects. Each card labels the project and the outcome it supports; parent cards show their sub-project count and computed progress. Open a card for its sub-projects, or use View all items for the full hierarchy. Completed sub-projects remain inside their parent rather than appearing as separate Shipped cards.
  • This week — what's due in the window, what's in progress, and what's ready to start next (the same rule as groom next), with key dates and owner load alongside.
  • All items — every outcome and project in an expanded, indented hierarchy, including undated, completed, and unattached work. Search by title, ID, owner, or tag; filter by kind or status. Matching items keep their ancestors visible for context. Check one or more items (or select all matching) to move them to a project or outcome, detach them, or permanently delete them. Selected parents keep their children nested when moved. Delete confirms the full list of affected items, including children. Selections persist across filters; the selection count calls out hidden selections. Drift findings remain in each item's inspector. Right-click a project (or use its ⋯ button) to move that project directly to an outcome. The menu marks its current parent; children keep their nesting. Keyboard users can press Shift+F10, navigate with arrow keys, and press Enter to move or Escape to dismiss. Drag a project's title onto an outcome or project to move it; drag a checked project to move the selected projects together. Drop on Unattached to remove their parent. Children keep their nesting, and self/descendant drops are blocked. Drag outcomes above or below one another to reorder them. Hover an outcome to reveal + beside its title and create a project under it directly. The button also appears on keyboard focus and stays visible on touch.
  • Changes — a change log read from git for the last 7 or 30 days: created, status changed, closed, re-targeted, re-parented, retitled, archived, deleted. Filter by kind or search.

The horizon strip under the title shows This week, This month, and This quarter with explicit dates, rolled forward when the current period is nearly over (fewer than 3 working days, 7 days, or 14 days left). The owner filter persists across the planning views; All items has its own filters. Views deep-link as #timeline, #board, #items, #week, #changes, and an entity as #P-12.

Clicking any row, bar, or card opens the inspector. Status and owner are menus, dates and the title are fields, and every edit is written immediately with a revision check — if someone else changed the file first, you get a toast and a reload, never a silent overwrite. Notes are editable markdown. Add comma-separated Tags in the New dialog or edit them in the inspector; clear the field to remove all tags. Tags appear below titles in All items and can be found through its search. The Tags dropdown filters All items, Timeline, Board, and This week by an exact tag or Untagged. The choice follows you between these views and combines with their other filters; All tags clears it. Matching nested items keep their ancestor context. Drag a project onto an outcome or another project to re-parent it; drag an outcome above or below another to rank it, which persists as priority. Binds to localhost only.

Linking to GitHub

A project can point at an issue or PR:

groom project edit P-1 --ref gh:owner/repo#412
groom sync            # report what closed upstream
groom sync --apply    # write it

Auth comes from the gh CLI, so there are no tokens for groom to store or leak.

Pulling summaries into another app

If you already have crons and a Slack bot, groom doesn't need its own. It produces the content and you deliver it:

groom summary --format slack     # blocks ready for chat.postMessage
groom summary --delta            # only changes since the lookback point
groom summary --cadence weekly   # seven-day deltas plus a 14-day outlook
groom summary --format json      # structured, format it yourself
groom summary --format markdown  # for a PR comment or email

The daily Slack shape is image-first: upload a PNG rendered from groom gantt --format html with summary text as its message, then post each array in thread as a reply. The complete Landed, Newly at risk, Resolved, Status changes, and In progress lists live in the thread without caps.

Or over HTTP, if groom web is already running:

GET /api/summary?format=slack&hours=24
GET /api/outlook?days=30&format=json

Check isEmpty before posting — it's true when nothing landed, nothing is in progress, and nothing needs attention. landed is read from git history, so it needs committed roadmap changes and a full clone.

Delta summaries compare the current roadmap with the commit at or before --hours ago. Their structured data adds since, every statusChanges transition, newFindings, resolvedFindings, and per-outcome outcomeDeltas. Outside Git history or in a shallow clone these arrays are empty and since is absent, so scheduled integrations degrade quietly.

--cadence daily|weekly defaults to daily. Weekly cadence uses a 168-hour lookback unless --hours is explicit, leads its Slack layout with outcome progress deltas, then shows the next 14 days, landed work, and attention.

Finished leaves can be moved out of the live roadmap in bulk with groom archive --done-before <duration|date>. The cutoff accepts values such as 90d or 2026-06-01; --dry-run lists the exact ids first. Completion age comes from the last Git status transition, falling back to file mtime when history is unavailable. Empty project parents follow their children. Any live parent or dependsOn reference refuses that entity and names the referrer.

Full contract, including failure modes and a worked example: docs/INTEGRATION.md.

Working with agents

claude mcp add groom -- groom mcp start

Twenty-five tools over the same core the CLI uses, plus groom://workflow/overview — one authoritative description of how to groom a roadmap, served to the agent rather than copied into instruction files that go stale. It encodes the rules that keep the data worth reading: never invent a target date, never close a parent to make a number look right, close the leaf projects instead — and the creation decision: classify proposed work before creating it, and default to updating or combining.

The tools an agent reaches for most, in the order it uses them: classify_proposed_work and find_related_projects before creating anything; get_ready_projects to choose work; get_project_context before starting it; project_claim so other agents see it is taken; reconcile_project_after_merge to close it with evidence and learn what it unblocked; validate_roadmap after a batch of edits; propose_execution_bundles to hand a program out.

Every read command takes --json with a versioned envelope, so scripts and agents that prefer the CLI get a stable contract too.

Prompts that work

Copy-pasteable starting points. They exist because each one encodes something groom cares about that an agent won't infer on its own.

Turn an idea into roadmap structure

Read the groom roadmap, then break this into projects: . Attach everything to an existing outcome if one fits — don't create a parallel structure. Split a project into sub-projects only along code-ownership lines — one per module or surface an agent can own end to end — never into sequential phases. Each leaf must be executable on its own. Don't set target dates; I'll add them.

The middle lines matter because agents over-split: they turn one body of work into "design / implement / test" checkpoints that can't run in parallel and never quite get closed. The last line matters because agents will happily invent a Q3 deadline you never agreed to, and once it's written down someone will hold you to it.

Keep the roadmap current as you work

Before you start, get the groom context for the project covering this, claim it, and set it to in-progress. When the code is merged, reconcile the project in the same turn with the commit, the tests you ran, and each acceptance criterion marked passed or failed. If no project covers this work, classify it first — create one only if groom says it is a project.

"In the same turn" is the whole trick. A roadmap updated later is a roadmap updated never, and a done with no evidence is a claim nobody can check.

Hand a program out to several agents

Run groom task plan on and show me the waves and bundles. Don't create one task per sub-project. If two bundles collide on a resource or the grouping looks wrong, fix the dependencies or resources and re-plan before assigning anything.

Clean up after a work session

Run groom drift. Fix what you can without guessing: attach orphans to the right parent, close projects whose work is merged, drop work we've abandoned. For anything needing a decision — a slipping target, an outcome with no projects — list it and stop.

Write up a project

Fill in the notes for : why it matters, the approach, and acceptance criteria as a checklist. Read the surrounding code first — I want the real constraints, not a generic plan.

Weekly review

Give me the groom summary for the last 7 days, then tell me which outcome moved least and why. Check whether its projects have work underneath them at all.

Development

npm test          # the suite
npm run check     # biome
npm run dev       # run the CLI from source (Node 22.18+ runs TypeScript directly)

groom's own roadmap lives in roadmap/. If planning groom in groom ever feels awkward, that's a bug in the model.

Prior art

The file-as-database shape, the ID - Title.md convention, and the CLI + TUI + web + MCP surface are borrowed from Backlog.md, which does the same thing one altitude lower, for tickets. Use it if tickets are what you need; use groom if the question is what the work is for.

License

MIT