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

@promptvet/hook

v0.1.3

Published

Diary-mode hook: scans prompts with promptvet-core in the background and records results to local history. Not a gate.

Readme

PromptVet Hook

Every prompt scored in the background. Nothing blocked, nothing slowed down.

A Claude Code hook (PreToolUse and UserPromptSubmit) that gives you a local, queryable prompt history and audit trail — observability for your AI agent, backed by SQLite, without touching enforcement.

npm License: MIT Node Diary mode TDD Built

Wires promptvet-core's scan into Claude Code's hook system, so every prompt you (or Claude) submit gets scored automatically — and you can look back at the history any time.


What It Is

@promptvet/hook is a diary, not a gate. It listens on Claude Code's hook events, scans each prompt in the background with promptvet-core, and records the result to a local history database. It never blocks, never denies, never adds latency to what you were doing — check always exits 0, no matter what it finds.

If you want prompt quality enforcement (deny on critical issues before a tool fires), that's a separate, not-yet-built mode — see the Roadmap section of promptvet-core's README. This package is the observability half: know what you've been sending, after the fact, without lifting a finger.


Quick Start

npm install --save-dev @promptvet/hook

Register it in .claude/settings.local.json for both hook events it supports:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "node /path/to/node_modules/@promptvet/hook/dist/cli/index.js check --adapter claude-code --store-raw-prompt"
          }
        ]
      }
    ],
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "node /path/to/node_modules/@promptvet/hook/dist/cli/index.js check --adapter claude-code --store-raw-prompt"
          }
        ]
      }
    ]
  }
}

That's it — every prompt you type, and every prompt Claude hands to a subagent, now gets scanned and recorded automatically.

promptvet-hook report

How It Works

┌──────────────────────────────────────────────────────────────┐
│  UserPromptSubmit  →  your own typed prompt, before Claude    │
│  PreToolUse        →  Claude's own Task/Agent subagent calls  │
└───────────────────────────┬────────────────────────────────────┘
                             │  stdin: hook event JSON
                             ▼
┌──────────────────────────────────────────────────────────────┐
│  check --adapter claude-code                                  │
│  Extracts the real prompt text, spawns a detached background  │
│  worker, and exits 0 immediately — the calling hook never     │
│  waits on a scan.                                              │
└───────────────────────────┬────────────────────────────────────┘
                             │  (background, detached)
                             ▼
┌──────────────────────────────────────────────────────────────┐
│  worker.js → scans with promptvet-core, writes one row to     │
│  ~/.promptvet/history.db (SQLite, created on first use)        │
└──────────────────────────────────────────────────────────────┘

Two event types, one adapter. UserPromptSubmit fires on your own typed prompts — its payload carries prompt at the top level. PreToolUse fires on Claude's own outgoing tool calls — it only carries a genuine natural-language prompt when Claude is dispatching a Task/Agent subagent (tool_input.prompt); every other tool call (Bash, Read, Write, …) is correctly ignored, since a shell command or file path isn't a prompt to critique. Both shapes are handled by the same claude-code adapter, branching on hook_event_name.

Not using Claude Code? A generic --field-path adapter pulls the prompt from any dotted path in arbitrary JSON — useful for wiring in another tool's hook system once you've confirmed its payload shape. (Don't guess the shape — capture a real payload first, the same way this package's own Claude Code fixtures were built.)


Commands

check — fired by the hook, not run by hand

promptvet-hook check --adapter claude-code [--store-raw-prompt]
promptvet-hook check --field-path payload.text [--store-raw-prompt]

| Flag | Meaning | |---|---| | --adapter claude-code | Handles both PreToolUse and UserPromptSubmit Claude Code payload shapes | | --field-path <path> | Generic dotted-path extraction for other JSON payloads | | --store-raw-prompt | Store the actual prompt text, not just its hash (see report --verbose below) |

Without --store-raw-prompt, only a hash of the prompt is stored — the history still tracks scores/verdicts/issues over time, just without the original text.

report — the aggregate summary (default)

promptvet-hook report
promptvet-hook report --json
PromptVet Hook Report
─────────────────────
Total checks: 42

Verdicts:
  Pass:  35
  Fail:  5
  Error: 2

Average score: 81.4

Top issue categories:
  1. HEDGE_DETECTED           12
  2. MISSING_FRAMEWORK        8
  3. NO_ACTIONABLE_INTENT     5

report --verbose — individual rows

promptvet-hook report --verbose
promptvet-hook report --verbose --recent 20
promptvet-hook report --verbose --json

Lists each check individually — timestamp, score, verdict, issue categories, and the prompt text itself — instead of the aggregate summary:

PromptVet Hook Report (verbose)
────────────────────────────────

1. 2026-07-04T12:05:00.000Z  score: 90.0  verdict: pass
   issues: (none)
   prompt: Write Vitest tests for the tax calculator in src/tax.ts

2. 2026-07-04T12:00:00.000Z  score: 40.0  verdict: fail
   issues: NO_ACTIONABLE_INTENT
   prompt: fix it

| Flag | Meaning | |---|---| | --recent N | Cap output to the N most recent checks (ignored without --verbose) | | --json | Full, untruncated row data as a JSON array — for scripts/tooling |

Two display rules worth knowing:

  • No stored prompt? If --store-raw-prompt wasn't set for a row, the prompt column shows [hash-only, no raw prompt stored] — never the hash itself, since a hash isn't human-readable and would just be noise.
  • Giant or multi-line prompt? The human-readable view truncates to the first line / first 200 characters, with a [truncated, N chars total] marker — so pasting a full terminal transcript as a prompt doesn't dump the whole thing back at you on every report call. --json is never truncated; it always returns the full text, for anything that needs to process it programmatically.

History Storage

A local SQLite database at ~/.promptvet/history.db, created automatically on first check. Nothing leaves your machine — same zero-network philosophy as promptvet-core's scan.

| Column | Notes | |---|---| | timestamp, source, cwd | When, via which adapter, and from where | | prompt_hash | Always recorded | | raw_prompt | Only when --store-raw-prompt was passed; NULL otherwise | | score, verdict, issue_categories | From promptvet-core's scan |


Architecture

| | | |---|---| | 🗒️ Diary, not a gate | check always exits 0 — a bad prompt is recorded, never blocked | | 🚫 Never blocks the calling hook | The scan + write happen in a detached background process; the hook returns instantly | | 🔒 Local-first | SQLite on disk, promptvet-core's scan runs locally — nothing leaves your machine | | 🧪 TDD-built | Adapter fixtures are real captured payloads, not guessed shapes | | 📘 TypeScript strict, Node 22, ESM only | |


Contributing

Read CLAUDE.md in the repo root first — same TDD contract as promptvet-core, plus this package's own rules (the diary-safety guarantee, the system-role/role-capture rule doesn't apply here but the "verify real payloads, don't guess" discipline very much does).


MIT Licensed · Part of the PromptVet family.