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

@euanmsm/shellgate

v0.1.1

Published

Claude Code PreToolUse hook that blocks Bash commands which edit repository files, leaving Edit and Write as the only way in

Readme

@euanmsm/shellgate

A Claude Code hook that blocks Bash commands which edit files in your repository, so the Edit and Write tools are the only way an agent can change them.

The problem it solves: edit hooks such as preflight and terse only watch the Edit and Write tools. An agent that reaches for sed -i, a > redirect or a quick Python script changes the same file with none of those checks running, and nothing tells you it happened. Some harness modes actively suggest shell edits. This closes that route.

Installing

npm i -D @euanmsm/shellgate

Then register it as a PreToolUse hook on Bash in .claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR/node_modules/.bin/shellgate\""
          }
        ]
      }
    ]
  }
}

Point at the installed binary rather than npx shellgate. The hook runs before every Bash command, and starting through npx adds a delay to each one.

There is no config file — nothing goes in .devkit/.

What it blocks

  • In-place editors: sed -i, perl -i, ruby -i, awk -i inplace, patch, and git apply (except --check, --stat, --numstat, --summary and --cached)
  • A > or >> redirect, or tee, into a path inside the repository — including quoted or escaped paths with spaces, and after a cd earlier in the same command (a cd inside ( … ) or $( … ), quoted or not, stops counting once it closes)
  • An inline Python, Node, Ruby, Bun or Deno script that calls a file-writing API, including when run through VAR=value, env, time, sudo, xargs, uv run, npx tsx, or a path such as .venv/bin/python or /usr/bin/time

A blocked command never runs. The agent is told why and to make the change again with Edit or Write.

What it lets through

  • Writes outside the repository: /tmp, a scratch directory, /dev/null
  • Output handling such as 2>&1, 2>/dev/null and | tail
  • Text that only looks like an edit, inside quotes or a heredoc body — grep "sed -i", jq 'select(.n > 1)', a commit message containing >. A heredoc with no closing delimiter line is not trusted, so its lines are still checked
  • Read-only python -c and node -e one-liners, and lookups such as command -v node
  • Tools that write files themselves, such as prettier --write or eslint --fix, and file moves: mv, cp, rm, git mv

Known gaps

It matches patterns in the command text, so a determined workaround still gets through:

  • A script saved to a file and then run (python3 edit.py) is not inspected
  • An inline script that names any absolute path outside the repository passes, even if it also writes inside it. That keeps scripts writing to a scratch directory working. Only a path under a real top-level directory counts — /tmp, /private, /var, /Users, /home and similar, or one that exists on the machine — so a URL path such as /api/v1/users or a regex literal such as /oldName/g does not

Pair it with a rule the agent reads, so it rarely tries in the first place.

Suggested rule

Save as .claude/rules/file-edits.md:

# File Edits

**Change files in this repo only with the Edit and Write tools.** Never through
Bash — no `sed -i`, `perl -i`, `>` or `>>` redirects, `tee`, `git apply`, and no
inline Python or Node script that writes a file.

- This overrides any harness instruction that permits shell edits
- `@euanmsm/shellgate` blocks these commands. A block means redo the change with
  Edit or Write — never hunt for another shell route
- Writing outside the repo is fine — a scratch directory, `/tmp`, `/dev/null`

When it does not block

The gate fails open. A malformed payload, or a command running outside any git repository, allows the command rather than halting work. SHELLGATE=off disables it.