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

ste-guard

v0.6.1

Published

Keeps agent replies in Simplified Technical English. Ships for pi, Claude Code, and Codex from one rule engine.

Readme

ste-guard

A Claude Code plugin that keeps Claude's replies in Simplified Technical English.

Claude talks too much. This makes it talk less.

What it does

  1. A SessionStart hook injects a short rule card one time.
  2. A Stop hook checks each reply. When a rule fails, the hook blocks once and returns the violations. Claude rewrites and sends the clean version.
  3. A UserPromptSubmit hook injects the full rule text with the exact banned strings. In the default lazy mode this hook stays silent until the Stop hook blocks once.
  4. A PreToolUse hook checks the markdown a Write or an Edit puts on disk. When a rule fails, the hook denies the call and returns the violations. It reads markdown only.
  5. A ste-check command lets Claude lint a draft before it sends the draft.

The rules come from ASD-STE100, adapted for chat. This is not certified conformance. The ASD licenses the official approved dictionary, so this repository does not carry it.

Why the injection is lazy

An always-on rule injection costs about 1,000 tokens per turn. A 50-turn session pays 50,000 tokens to repeat rules that Claude read at the start.

The lazy mode pays once at session start, then nothing. When Claude breaks a rule, the hook arms itself and injects the full contract for the rest of the session. A clean session pays nothing beyond the opening card.

Set injection to always when you prefer the predictable cost.

Install

claude plugin marketplace add https://github.com/ofrusch/ste-guard.git
claude plugin install ste-guard@ste-guard

The owner/repo shorthand also works, but Claude Code clones that form over SSH. The full HTTPS URL above clones over HTTPS instead, so it works without an SSH key. To keep the shorthand and still clone over HTTPS, set CLAUDE_CODE_PLUGIN_PREFER_HTTPS=1.

Optionally set the output style to STE with /output-style. The hooks work without it.

Install for Codex

Codex reads the same marketplace file, so the first two steps match.

codex plugin marketplace add https://github.com/ofrusch/ste-guard.git
codex plugin add ste-guard@ste-guard
python3 ~/.codex/plugins/cache/ste-guard/ste-guard/<version>/scripts/codex-install.py

The third step exists because Codex v0.147 installs a plugin's skills but does not load the hooks the plugin ships. The script writes the four hook entries into ~/.codex/hooks.json by absolute path. It backs the file up first, it leaves your other hooks alone, and it never stacks duplicates. Run it again after a plugin update, because the version sits in the path.

Codex asks you to trust each new hook command on the next interactive run. Until you approve them, Codex skips the hooks without a warning. Run codex once and accept the four prompts.

Remove the entries with --uninstall.

What differs on Codex

  • A Codex Stop hook that blocks does not reject the reply. Codex continues the turn with the violations as a new prompt, so the first draft stays in the transcript.
  • The ste skill loads from the plugin with no extra step.

Install for pi

pi install npm:ste-guard

The package carries the extension and the skill. pi loads the TypeScript through jiti, so no build step runs. Install from a checkout with pi install ./ste-guard, or try it for one session with pi -e ./extensions/ste-guard.ts.

What differs on pi

  • pi has no block primitive on an assistant message. The extension asks for a rewrite through a follow-up user message instead. The model regenerates, and both the first draft and the correction stay in the transcript.
  • pi streams the reply before the check runs, so you see the first draft appear.
  • The extension holds no rules of its own. It runs the same Python checker the other two agents run.

Pick your features

Run the setup script for the questions. It writes ~/.claude/ste-guard.json, and it backs up the file it replaces.

python3 ~/.claude/plugins/ste-guard/scripts/ste-setup.py

Inside a session, run /ste-setup instead. Claude asks the questions and runs the script.

| Flag | Effect | | :-- | :-- | | --show | Prints the current config | | --profile default\|peer-eng | The register to extend | | --write-guard deny\|warn\|off | What the write guard does with a failing file | | --injection lazy\|always\|never | When the hook injects the full rule text | | --telemetry on\|off | Records one line per turn, with no message text | | --rules-off a,b | Turns named rules off | | --rules-on a,b | Turns named rules on | | --write-suffixes .md,.mdx | The file types the write guard reads | | --reset | Deletes the config and falls back to the bundled default |

STE_GUARD_PROFILE wins over this file. Unset it before you run the setup script.

Configuration

ste-guard resolves the active profile in this order:

  1. The STE_GUARD_PROFILE environment variable, read as a bundled profile name or a file path.
  2. The file at ~/.claude/ste-guard.json.
  3. The bundled profiles/default.json.

A user profile does not need to restate the whole schema. Name a parent with extends, then override only the keys you want.

Profile schema

| Key | Type | Meaning | | :-- | :-- | :-- | | extends | string | A bundled profile name to inherit from | | injection | string | lazy, always, or never. off is an alias for never | | min_words_to_lint | number | Replies shorter than this are never checked | | soft_block_threshold | number | Soft violations needed to block on their own | | max_blocks_per_message | number | Blocks allowed against one message digest | | max_blocks_per_chain | number | Consecutive blocks before the hook gives up | | budget.words | number or null | Word ceiling per reply. null removes the cap | | budget.sentence_words | number or null | Word ceiling per sentence | | budget.uncapped_on_heading | boolean | A markdown heading lifts the word ceiling | | rules.* | boolean | One switch per rule. See the table below | | lists.* | array | Replaces a phrase list | | lists_add.* | array | Appends to a phrase list | | lists_remove.* | array | Removes entries from a phrase list | | autofix_adjectives | array | Extra words the --fix pass may delete before a noun | | write_guard.enabled | boolean | The write guard switch | | write_guard.mode | string | deny blocks the write. warn reports and lets it land | | write_guard.profile | string | The profile the write guard lints with | | write_guard.suffixes | array | The file types the write guard reads |

Rule switches

| Switch | What it catches | | :-- | :-- | | openers | Filler openers such as a warm-up compliment | | closers | Hollow sign-offs | | puffery | Marketing adjectives | | not_just | The "not just X, it is Y" construction | | asides | Mid-sentence parenthetical and em-dash interruptions | | gerund | A sentence that opens with an -ing form | | passive | Passive voice | | narration | Process narration, which reports the search instead of the finding | | flourish | Wordplay and rhetorical symmetry | | prose_wall | A long reply with dense paragraphs and no bullets |

Bundled profiles

  • default — the ASD-STE100 chat subset with a 250-word ceiling. Grammar only, no voice.
  • peer-eng — a blunt senior-engineer register. A 130-word ceiling, bullets by default, every rule on.
  • docs — full STE for a file on disk. No word ceiling, every phrase rule on. The write guard always runs this profile, whatever the session runs.

Example

Write ~/.claude/ste-guard.json to keep the grammar rules and drop the word ceiling:

{
  "extends": "default",
  "budget": { "words": null },
  "lists_add": { "puffery": ["ecosystem", "journey"] }
}

Fix the reflex failures without a rewrite

ste-check --fix draft.md
echo "$DRAFT" | ste-check --fix

The fixer deletes a filler opener, a hollow closing sentence, and a puffery adjective that stands before a noun. It never rewrites a sentence. It reports every fix on stderr, and it lists what still needs a person.

The fixer is deliberately timid. It leaves a predicate use such as "the parser is robust" alone, because a deletion there breaks the sentence. It leaves a hyphenated entry alone, because the phrase list holds stems.

Two rules keep the fixer from deleting meaning:

  • It deletes a known adjective only. A word that also reads as a noun or a verb stays, so "the leverage ratio" never becomes "the ratio". Name your own safe words with autofix_adjectives in a profile.
  • It deletes a closing sentence only when the rest of that sentence is filler. A sentence that also carries a number, a path, or an imperative verb stays whole.

Measure the rules

Telemetry is off by default. Turn it on with "telemetry": true in your profile, or with STE_GUARD_TELEMETRY=1. Each turn appends one line to telemetry.jsonl in the state directory. The line holds counts and rule numbers only. It never holds your message text.

scripts/ste-stats.py

The reader prints the block rate, the mean words per turn, the violations per 100 words, and the share each rule contributes. Use it to find the rules that only nag, then switch them off in your profile.

Quoted text is exempt

The checker blanks any run inside double quotes before it applies the phrase lists. Claude can therefore name a banned phrase when it explains the phrase to you. Claude cannot use one. Inline code, fenced code, block quotes, links, and file paths are also exempt.

Environment variables

| Variable | Effect | | :-- | :-- | | STE_GUARD_OFF=1 | Disables every hook | | STE_GUARD_WRITE_OFF=1 | Disables the write guard, and leaves the reply guard on | | STE_GUARD_DEBUG=1 | Writes the hard and soft counts to stderr | | STE_GUARD_PROFILE | Selects a bundled profile by name, or a profile file by path | | STE_GUARD_TELEMETRY=1 | Records one line per turn, without the message text | | STE_GUARD_STATE_DIR | Moves the block counters and the telemetry log |

Limits

  • No Claude Code hook rewrites a reply in place. The Stop hook can only block and hand back the violations. A rewrite therefore costs a second generation.
  • The word ceiling and the bullets rule need judgment, so a regular expression cannot fix them. Only a rewrite can.
  • The checker matches fixed strings. A model that invents a new filler phrase gets through until you add the phrase to a list.
  • The write guard reads .md, .markdown, and .mdx only. A comment in a source file, a commit message, and a PR body all pass with no check.
  • The write guard reconstructs the file the tool is about to write, then reports only the violations that call introduces. A defect already on disk never blocks an unrelated edit.
  • The write guard reads the tool names Write, Edit, and MultiEdit. Another agent that edits a file under a different tool name gets through.

Tests

Both suites use only what the runtime ships, so neither needs an install step.

python3 -m unittest discover -s tests -v
node --test tests/extension.test.ts

Four of the tests run the plugin's own documentation through the checker, so the docs cannot drift out of conformance without a red build.

Related work

ste-guard differs in one way. It gates the reply, not the file write.

License

MIT