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

@devrik-tools/claude-gates

v1.2.1

Published

49 installable, deterministic gates (hooks) for Claude Code: block destructive commands and protected paths, enforce delegation/spec/quality/research rules, and track tasks that only close with verified evidence. Configurable per project.

Readme

claude-gates

Installable, deterministic gates (hooks) for Claude Code. They run automatically before Claude executes a tool and block or warn when something breaks a rule: a destructive command, a write to a protected file, a delegation with no brief, and more. Everything is configurable per project and can be turned on/off whenever you want.

The core idea: instead of trusting the model to remember the rules, a deterministic hook enforces them. A git reset --hard does not run because the model chose to behave — it is blocked because a gate intercepts it.

🇪🇸 Léelo en español


Install

Two steps. The plugin wires the hooks into Claude Code; the CLI picks which gates run and with what configuration.

# 1. Register the marketplace and install the plugin (wires the hooks)
claude plugin marketplace add https://github.com/DevRik99/claude-gates
claude plugin install gates@claude-gates

# 2. Choose which gates to adopt (interactive menu) — or use npx without cloning
npx @devrik-tools/claude-gates init

Restart the Claude Code session (or run /plugin) so the hooks load.

Why two things? The plugin always ships all 50 gates; the config decides which ones run. So you can turn one on without reinstalling — it is one line in a JSON file.


How it works (the model in 30 seconds)

Claude is about to use a tool (Write, Bash, Agent…)
        │
        ▼
Claude Code fires the PreToolUse hooks in parallel
        │
        ▼
Each gate that applies (by its "matcher") runs in its own process:
   · reads the payload       · reads its project config
   · if off → exits          · if the rule is broken → DENY (block) or WARN (advise)
        │
        ▼
If any gate blocks, the tool does not run.
  • DENY: the action is deterministically wrong → it is blocked.
  • WARN: the action needs judgment → the gate injects a note and lets it proceed.
  • Silence: the common path. A gate never nags when there is nothing to object to.

Every DENY/WARN message is prefixed [configKey] — the exact key name to look up (or turn off/tune) under "gates" in .ai/config.json, e.g. [blockPathsOutsideRootWhitelist] '...' is not on the whitelist. means the setting is blockPathsOutsideRootWhitelist in the table below, not some other name you'd have to guess or map from a short gate id.

Every gate is self-contained (Node built-ins only, no runtime dependencies), so it works even if you install one on its own.


The gates (50, in 11 families)

[on] = enabled by default; [off] = enable it if you want it.

🔒 Security — hard blocks on destructive actions

| Gate | | What it does | | ---------------------- | --- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | bash-commands | on | Blocks git reset --hard, rm -rf over protected areas, force push, and killing processes by name. | | block-remote-publish | on | Blocks git push, gh pr merge, gh release create without authorization. Set blockRemotePublish: false to let the agent publish on its own. | | protected-paths | on | Blocks writes to .env, lockfiles and the harness itself. | | root-whitelist | on | Blocks new root-level files/folders outside a whitelist. | | no-blocking | off | Blocks sleep, tail -f, polling loops and foreground servers. | | require-monitor | on | Blocks a background command (run_in_background: true) that does not declare its monitor with a MONITOR-PLANNED: marker, and blocks further execution while an unmonitored background command is still pending. |

🤝 Delegation — requirements on the brief when delegating to a subagent

| Gate | | What it does | | ----------------------- | --- | ---------------------------------------------------------------------------------------------------------------------- | | brief-before-delegate | off | Requires goal, steps and done-when criteria in the prompt. | | intent-flow | off | Requires IN SCOPE / OUT OF SCOPE / EDGE CASES sections. | | risk-level | off | Requires a declared level (QUESTION/MICRO/STANDARD/HIGH-RISK). | | circuit-breaker | off | Cuts the same delegation retried without real changes. | | no-memory-dependency | off | Blocks a brief that relies on the subagent "remembering" the chat (add memory-not-needed to allow a false positive). | | force-parallel | on | Blocks the Nth consecutive sequential delegation inside a time window: independent delegations must be launched together in one message (add SEQUENTIAL-JUSTIFIED when the second one really depends on the first). |

📋 Spec-driven flow — only relevant if the project adopted spec-driven development

| Gate | | What it does | | ------------------------- | --- | -------------------------------------------------------------------- | | feature-catalog | on | A single feature in progress; closing requires asserts and review. | | sdd-specs | off | Requires non-empty requirements/design/tasks before implementing. | | brief-approved | on | Requires a recorded user approval (status: approved + quote) on the cited feature's brief before implementing. | | implementation-pipeline | off | Requires declaring definition → writing → validation → QA → closure. | | mandatory-flow | off | Requires an active task with a contract before implementing. | | test-matrix | off | Requires a test matrix (the types the requirement makes mandatory). |

✨ Quality — code hygiene, diagnosis and language

| Gate | | What it does | | --------------------------- | --- | -------------------------------------------------------------------------------------------------------------- | | dependency-skills | on | Blocks a new direct dependency with no matching skill (declare it in depsWithoutOwnApi if it needs none). | | root-cause-first | off | Requires an origin→symptom diagnosis before a patch. | | never-assume | off | Flags unverified assumptions in briefs and code. | | rule-skill-autodiscovery | off | Loads gates the project declares in its rules/ and skills/. | | recurrence-lock | on | A second occurrence of a defect class requires its deterministic block. | | test-after-implementation | off | Blocks a test written after its paired implementation (add test-after-impl:allow for a regression test). | | adversarial-tests | off | Blocks a test file with no checkable adversarial evidence: an ATTACK MATRIX row per category (boundary, invalid input, missing/empty, invalid state, dependency failure, idempotency/order, invariant, security), a case in the file backing each COVERED row, and the mutations the suite kills. requiredCategories adds three more rows the gate can corroborate but does not demand by default: decision-table, metamorphic, partial-write. claude-gates tests [paths…] re-runs the same check over files already on disk. Add adversarial-tests:allow in a comment for a deliberate exception. | | no-reconfirm | on | Never re-ask what you already answered. | | neutral-spanish | on | Blocks voseo or regional lexicon in written text (add neutral-spanish:allow for a deliberate quote/fixture). | | diagnosis-before-patch | on | Warns when timeouts/retries change without evidence. | | lint-commit | off | Blocks git commit while the project's lint script fails (autodetects npm run lint; silent if none). | | staged-lint | off | Blocks git commit when the staged files fail lint — lints only what you staged, so your change can't add new lint debt while pre-existing debt in untouched files never blocks you. Add [skip-lint] for a deliberate exception. | | atomic-commit | off | Blocks a git commit that is not atomic — one mixing more than N natures of change (code/tests/deps/config…) or staging more reviewable files than a commit should carry. Docs/assets/generated aren't counted. Add [wip] for a deliberately broad commit. | | no-coauthor | on | Blocks a git commit carrying an AI/agent attribution trailer (Co-Authored-By, Generated with, a session trailer). Add [allow-coauthor] for one legitimate co-author. | | no-lint-suppression | on | Blocks a write that silences the linter/type-checker (eslint-disable, @ts-ignore, a rule set to off) instead of fixing the code. Add lint-ok: <reason> on the same line for a documented false positive. | | no-explanatory-comments | on | Blocks a code write that adds comments narrating what the code does. Only decision comments (why, trade-off, limitation), tool directives, TODO/FIXME and typed JSDoc tags pass. Judges only new comments (diff against disk). Add comment-ok: <reason> for a documented exception. | | no-trivial-scripts | on | Blocks an inline interpreter script that does a file operation the Edit/Write tool handles directly (node -e with writeFileSync, python -c with open(…, 'w'), sed -i, perl -i, Set-Content/Add-Content). Inline scripts that only compute are not caught. |

🔎 Tool discovery — don't reinvent the wheel

| Gate | | What it does | | -------------------- | --- | ------------------------------------------------------------------------------------------------------------ | | reuse-before-build | on | Before building a tool, consults the project tool map; blocks if you did not audit (local → Context7 → web). | | tool-map | off | Records discovered tools in .ai/tool-map.json so exploration is not repeated. | | skill-first | off | Blocks a write/command/delegation an available skill plausibly covers until the question was asked: load the skill, or say why it does not fit (no skill covers this / using the <name> skill). Reads the same catalog capability-map injects. |

🧠 Research flow — memory first, never guess a library

| Gate | | What it does | | -------------- | --- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | engram-first | on | Blocks WebSearch, WebFetch and context7 until a mem_search ran in the session (engram is the first source); blocks the Stop event while research happened with no later mem_save; at session start warns once when engram cloud is configured but the project is not enrolled. | | library-docs | on | Blocks a write that imports a package the project does not use anywhere yet unless this session looked it up: an engram hit about it, or context7 docs followed by a mem_save. Never guess a library API. |

🏭 Forge pipeline — enforces the forge workflow

| Gate | | What it does | | ------------ | --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | forge-flow | off | In a project that adopted forge, blocks editing/running unless an active forge run exists. Closes the hole the MCP cannot: it forces you through the pipeline. |

🤖 Autonomy — let an unattended run decide instead of asking

| Gate | | What it does | | ------------------ | --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | autonomous-mode | off | With autonomous mode on, blocks AskUserQuestion and blocks a turn that ends only to wait: it re-injects, once per cycle, the instruction to decide and proceed, leaving pending only what genuinely needs the user. |

⏹️ Completion — a turn does not end with work still open

| Gate | | What it does | | -------------------- | --- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | stop-pending | on | Blocks the Stop event while this project has active tasks (open/in_forge); lists them and how to close them with verified evidence or abandon them. blocked tasks don't hold the turn by default. | | require-task-split | on | Blocks writes and execution while an active task larger than small has no sub-tasks registered: split it into independently verifiable pieces first (task add --parent <id>). |

🗂️ Task tracking — the tasks plugin

| Gate | | What it does | | ----------------------------- | --- | ---------------------------------------------------------------------------------------------------------- | | remind-open-tasks | on | Makes the assistant classify and register new work via the CLI, and recites the active tasks every N messages. | | list-tasks-on-session-start | on | Lists this project's active tasks when a session opens. Silent when there are none. |

🩺 Session & context — startup checks and capability injection

| Gate | | What it does | | ---------------- | --- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | doctor | on | On session start, runs the environment validator and only speaks on failure. | | ask-adoption | on | In a project that never answered, makes the assistant ask what to adopt. | | wiring-check | on | Warns when a registered hook is missing or a script is orphaned. | | capability-map | on | Every injectEveryMessages messages (default 10; always on the first run and whenever a capability is added/removed), injects the project's capability catalog — skills, agents/subagents, commands — as compact data, and persists it to .ai/capability-map.json (like the tool map). Autosynced from disk. Never blocks. |


Configuration: turn gates on, off, and tune them

Everything lives in one file. Project overrides global:

  • Project: <root>/.ai/config.json
  • Global (fallback): ~/.claude/claude-gates/config.json

init writes the selection there and materializes each gate's default values, so you see and edit every knob:

{
  "adopted": "partial",
  "gateVersion": "3.1.0",
  "gates": {
    "blockDestructiveShellCommands": {
      "enabled": true,
      "rmRfProtectedAreas": ["/", "*", "src", "tests"],
      "denyPatterns": ["git reset --hard", "…"]
    },
    "blockRemotePublish": { "enabled": false },
    "warnNonNeutralSpanish": {
      "enabled": true,
      "regionalMarkers": ["tenés", "podés", "…"],
      "escapeHatch": "neutral-spanish:allow"
    },
    "requireBriefBeforeDelegating": { "enabled": false }
  }
}
  • Turn a gate off: "enabled": false. Off instantly, no reinstall. Or from the CLI: claude-gates disable <gate> / claude-gates enable <gate> (gate ids, config keys, family ids or all; --project or --global), and claude-gates status to see what is on for the current directory and where each value comes from.
  • Re-running init merges, never overwrites. A gate already in the file only changes when you name it (--gates, --families, --all, --none) and, when its enabled would flip, you confirm it gate by gate. With --yes (no TTY) the existing values are kept and reported; pass --force to apply them without asking.
  • A wrong-typed param never breaks a gate. A string where a list is expected, or a malformed regex, falls back to the built-in default and is reported once per session in the gate's own message (and in the decision log).
  • Tune its behavior: edit its parameters (the whitelist, the patterns, the thresholds). What the project declares replaces the gate's default.
  • A gate absent from the config uses its catalog default. Keys you already had in the file (e.g. autoCommit) are kept intact.
  • Let the agent push: set "blockRemotePublish": { "enabled": false }. Nothing is hardcoded — every gate, remote publish included, obeys this flag.
  • Escape hatches: a few gates block (deny) but accept an explicit opt-out marker in the content/prompt for a legitimate case: neutral-spanish:allow (a deliberate regional quote), test-after-impl:allow (a regression test), memory-not-needed (a non-memory phrase), [allow-coauthor] (one legitimate co-author on a commit), lint-ok: <reason> (a documented linter false positive), [skip-lint] (skip the staged-lint check for one commit), [wip] (allow one deliberately broad, non-atomic commit), comment-ok: <reason> (one explanatory comment that must stay), SEQUENTIAL-JUSTIFIED (a delegation that genuinely depends on the previous one), MONITOR-PLANNED: (the background command declares how it will be monitored). dependency-skills opts out via its depsWithoutOwnApi list. skill-first clears on one sentence in the content/prompt: no skill covers this, or using the <name> skill.
  • Capability injection: capability-map (on by default) is fully tunable — pick which kinds to surface ("kinds": ["skills", "agents", "commands"]), cap each blurb (maxClauseChars, default 120), add extra roots per kind, throttle how often the full catalog is re-injected (injectEveryMessages, default 10 — the persisted map file itself still refreshes every message; the catalog is ALSO re-injected mid-throttle whenever the prompt's kind of work changes, e.g. debugging → releasing, which you can turn off with "reinjectOnWorkNatureChange": false), or turn off persistence ("persist": false) and point the map file elsewhere (mapFile). Skills are also scanned by default under ~/.agents/skills, <project>/.agents/skills, ~/.ai/skills and <project>/.ai/skills (skill-only roots some installers use besides .claude/skills — no config needed), in addition to any extraSkillsDirs the project declares. A description too long to fit maxClauseChars falls back to mechanical word-boundary truncation, but you can hand-write a better one-line summary per capability in ~/.claude/blurb-overrides.json (global) or <project>/<blurbOverridesFile> (default .ai/blurb-overrides.json, project wins per key) — a { "skill-name": "short summary" } map, used verbatim instead of the mechanical cut. A capability's re-scan is skipped (its blurb reused verbatim) whenever disk is unchanged since the last scan (same set of source files, same mtimes); removing a skill/agent/command drops its entry from the map on the very next run.

Generated artifacts

Everything an agent produces that is not source code — a deterministic check it wrote so you can see whether something works, an audit of what already exists, a note explaining what it did — has one shape and one home, so it can be found by convention and validated in CI instead of landing wherever the model felt like.

claude-gates new check my-claim --title "..." --source "what asked for this"

| Kind | Lives in | For | | ------- | ------------- | ------------------------------------------------------------------ | | check | .ai/checks/ | One verifiable claim: the command, what it must print, the evidence it actually printed. | | audit | .ai/audits/ | Looking before building: searched / exists / missing / decision. | | note | .ai/notes/ | Reasoning that would otherwise live only in a chat log. |

When the same thing goes wrong twice, the record is data rather than a document: register the defect class in .ai/reincidencias.json, which recurrence-lock reads to block mutating work until the class is closed at the root.

The contract is cli/artifacts.mjs; the full rules are in .ai/README.md. Two tests keep it honest — one covers the module, the other walks this repo's own .ai/ tree and fails on any artifact that drifted (missing front matter, wrong directory, a missing section, or a check marked passed whose evidence is still the generated placeholder).


Decision log

Every deny, warn and Stop-block is appended as one JSON line to <root>/.ai/gates-log.jsonl (timestamp, gate, config key, tool, a one-line summary of the action, the reason, the session). Read it with:

claude-gates log                      # last 30 decisions for this project
claude-gates log --deny --gate bash-commands --tail 100
claude-gates log --since 2026-09-01T00:00:00Z --json

The file rotates once at 5 MB (gates-log.1.jsonl). Set CLAUDE_GATES_LOG=0 to disable it.


Tasks: registered with a criterion, closed with verified evidence

A task carries its verification criterion from the moment it is created — task add refuses a task nobody can prove done — and task close refuses free text: it is done only when the check actually passes.

# Register: the criterion is mandatory (--verify-command or --verify-path)
claude-gates task add "migrate the config loader" \
  --size medium --verify-command "npm test" --verify-expect "fail 0"
claude-gates task add "write the migration guide" \
  --parent <id> --verify-path docs/migration.md --verify-contains "## Upgrading"

claude-gates task list [--all]        # active tasks (or the whole history)

# Close: with no --check/--exists, the task's own verify criterion is re-run
claude-gates task close <id>
claude-gates task close <id> --check "npm test" --expect "fail 0" --note "suite green"
claude-gates task close <id> --exists dist/report.html --contains "All green"
claude-gates task abandon <id> --reason "obsolete"
claude-gates task promote <id> <runId>   # link the task to a forge run

The verified result (command, exit code, output tail, timestamp) is stored with the task. Two gates lean on this store: require-task-split blocks implementing a task bigger than small that has no sub-tasks, and stop-pending blocks the turn from ending while tasks are still open.


CLI commands

# Interactive menu: pick plugins, families or gates, per project or global, and install.
npx @devrik-tools/claude-gates init

# Non-interactive (for CI or scripts):
claude-gates init --project|--global  --defaults|--all|--none|--families a,b|--gates x,y  --yes  --dry-run
claude-gates init --new               # ONLY gates this config never decided about — upgrade
                                      # without re-answering or changing anything already set
claude-gates init --no-install        # write the config but do not install the plugin
claude-gates init --force             # apply changes to gates already in the file without asking

# Toggle and inspect what runs here:
claude-gates enable <gate|family|all> [--project|--global]
claude-gates disable <gate|family|all> [--project|--global]
claude-gates status                   # effective on/off per gate and its source (project/global/default)
claude-gates log [--tail N] [--deny] [--gate id] [--since iso] [--json]
claude-gates doctor                   # is Claude Code running THIS package version of the plugins?

# Tasks (the store the completion gates read):
claude-gates task add <title> --size <size> --verify-command <cmd>|--verify-path <path> [--parent <id>]
claude-gates task list [--all]
claude-gates task close <id> [--check <cmd> --expect <text>] [--exists <path> --contains <text>]
claude-gates task abandon <id> --reason <text>
claude-gates task promote <id> <runId>

# Inspect the catalog:
claude-gates registry --list          # list families and gates
claude-gates registry --check         # validate registry.json and that hooks.json is in sync
claude-gates registry --sync-hooks    # regenerate each plugin's hooks.json from the registry

# Verify the gates actually react (not just that they are wired):
claude-gates smoke                    # feed each gate a known violation; exits non-zero if any does not block/warn

# Verify the tests themselves were written to break the code, not to watch it work:
claude-gates tests [paths...]         # the adversarial-tests check over files already on disk; exits non-zero on any without evidence

smoke is the behavioral check registry --check (structure) and the doctor hook (files exist) do not do: it feeds every gate a known violation and confirms it really denies/warns. Gates whose violation needs seeded state (a db, a git repo, cross-call state) report skip, never a false pass. Run it after install, or in CI, to catch a gate that is wired but silently allows.


Repository layout

registry.json                     Catalog: families → gates (id, configKey, default, tools, params).
                                  The single source of truth; the menu and the hooks derive from it.
cli/                              The npm CLI (commander + @clack/prompts + zod).
  registry.mjs · selection.mjs    Load/validate the catalog; turn a selection into config.
  config.mjs · materialize.mjs    Where config lives, merge, and dump each gate's defaults.
  init.mjs · install.mjs          Interactive flow + install the plugin.
plugins/gates/                    The gates plugin.
  .claude-plugin/plugin.json
  hooks/hooks.json                Generated from registry.json (`registry --sync-hooks`). Loaded by Claude Code.
  hooks/lib/                      Shared hook code (Node built-ins only).
  hooks/gates/<id>/               One gate per folder: index.mjs (the rule) + test.mjs (its test).
plugins/tasks/                    The tasks plugin: persists per-project tasks, reminds of the open ones
                                  and lists them on session start.
.claude-plugin/marketplace.json   Lists the marketplace plugins.

Adding a gate = one folder in plugins/gates/hooks/gates/<id>/ (with index.mjs and test.mjs) + one entry in registry.json, then claude-gates registry --sync-hooks. Gates share hooks/lib/ (payload readers, git normalization, session state, delegation vocabulary, the decision log, the test harness): a gate file is only its rule.


Development

npm test                  # run all tests (node --test)
npm run registry:check    # validate the catalog
npm run lint              # eslint (boundaries, no-magic-numbers, sonarjs, cspell…)

Each gate is tested in isolation: node --test plugins/gates/hooks/gates/<id>/test.mjs (name the test files: a glob that also matches index.mjs hangs, because a gate waits on stdin).

This repo ships its own .ai/config.json that locally disables the gates that would false-positive when editing the gates themselves (e.g. reuse-before-build thinks you are "building a tool" when you are really editing an existing gate). It is versioned so the repo behaves the same on any machine.

Requirements

Node ≥ 22.5 (the forge-flow gate uses node:sqlite, available from that version).

License

MIT.