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

defend-cli

v0.8.0

Published

Never ship code you can't defend. Automated whiteboard defense for AI-assisted code: a fresh Claude Code or Codex session interviews the author about the change and verifies the answers against the repository.

Readme

Defend

Never ship code you can't defend.

AI can write the code. Defend checks whether you can defend it.

Before a change ships, Defend starts a fresh reviewer session (Claude Code or Codex), reads the diff and the surrounding repository, and interviews the author the way a good engineering manager would at a whiteboard:

Why did you go with a new NotificationQueue here? We already have OutboxPublisher in services/outbox that does retries. What does the new one do that it doesn't?

You type the answer. Defend verifies your claims against the code, asks a follow-up when something doesn't add up, and writes an attestation bound to the exact diff. No per-developer scores, no leaderboards: per-change assurance and a private knowledge map.

Inspired by Mitchell Hashimoto's whiteboard defense.

Install

npm install -g defend-cli

Requirements on the machine that runs the defense:

  • Node.js 20+
  • a logged-in Claude Code CLI (claude) or Codex CLI (codex). Defend uses whichever you pick; it has no backend and no API key of its own. Inference is billed to your existing subscription.

Your source code never leaves the machine. The reviewer runs locally with read-only tools.

Quick start

cd your-repo
defend init          # personal mode: config + skills, excluded from git, nothing to commit
git add -A
defend               # defends the staged diff
defend --base main   # defends the whole branch since it diverged from main

defend init is optional; defend works with no files in the repository at all. Personal mode keeps everything it writes (defend.yml, the skills, .defend/) out of git status through .git/info/exclude. When a team wants shared config and CI enforcement, defend init --team makes the same files committable and --github adds the workflow.

A defense looks like this:

🛡 Defend  never ship code you can't defend

Files changed:      14
Lines:              +842 / -126

Risk:                HIGH
Primary concern:    state lifecycle
Blast radius:        HIGH

You introduced a `processing` state between `pending` and `complete` for vendor jobs, and the
worker now claims jobs by moving them into it.

Before shipping, demonstrate that you understand it.
4 questions · ~4 min

────────────────────────────────────────────────────────────
1/4  State · blocking

Which parts of the system assume a job moves straight from pending to complete, and why does the
new state not break them?

> the worker only selects pending jobs, so processing stops double pickup.
  the frontend only cares whether it is complete.

⚠ Follow-up
The worker matches your answer (worker/claimJob.ts:41). But BillingService treats every
non-complete job as a billable pending job (billing/BillingService.ts:118). What happens while a
job is processing?

Answers are typed. Pasting is rejected by default (input.paste: deny), because the point is to reconstruct your own mental model, not to relay one from another chat window.

Commands

| Command | What it does | |---|---| | defend | Run the defense for the staged diff (default command). | | defend --base <ref> | Run it for everything on the branch since <ref>. | | defend doctor | Checks git, the reviewer CLI, its login (with a sub-cent round trip), the signing key and the config. Run it first. | | defend check | Files, diff hash, deterministic risk signals and matched rules. No AI. | | defend map [path] | Who can defend this code: per-file coverage from passing defenses, with knowledge decay. --all across repositories. | | defend status | Is there a passing attestation for exactly this diff? Exit code 0/1. | | defend stats | Usage and knowledge map from .defend/attestations/. --me scopes to you, --json for tools, --html writes a dashboard page, --repos <a> <b> aggregates several repositories into a company view. | | defend verify | CI gate. Exit 0 only when a passing, correctly signed attestation exists for exactly this diff. | | defend report | The PR table as Markdown, for a GitHub comment. | | defend init | Personal mode by default (nothing to commit). --team for shared config and committed attestations, --ci github\|gitlab\|azure adds the CI template. |

Useful flags for defend: --agent claude-code|codex, --model <id>, --effort low|medium|high|max, --budget <usd>, --max-questions <n> (flat cap over the per-level budget), --paste deny|warn|allow, --yes (skip the large-change confirmation), --force.

Cost

Defend has no backend; the reviewer runs on your Claude Code or Codex subscription and the cost is yours. Measured with the defaults (Claude Code, sonnet analysis, haiku grading) on real repositories, October 2026:

| Change | Analysis | Per graded answer | Per escalated check | Typical total | |---|---|---|---|---| | 2 files, +2/-15 (service + test) | $0.26–0.34 | $0.05–0.06 | $0.15–0.19 | $0.45–0.60 for 2–3 questions | | 6 files, +223/-17 (import-cycle fix) | $0.06–0.25 | $0.05 | ≈ $0.20 | ≈ $0.40 | | 17 files, +1103 (seeded data + code) | $0.26 | — | — | analysis only | | 67 files, +13.8k (large branch) | ≈ $0.30 | $0.12–0.16 | — | ≈ $0.60 for 1 question |

Codex reports no cost, so the same runs show turns and cached tokens but no dollar figures. Defaults are chosen to keep a typical PR well under a dollar:

  • Model sonnet, effort medium for Claude Code. Codex uses the model in your ~/.codex/config.toml.
  • budgetUsd: 1 is a hard stop for the whole defense. Before every reviewer turn Defend checks that the previous turn's cost still fits, and the remaining amount is passed to the reviewer as its own ceiling, so a run cannot overshoot by a full turn. (Codex reports no cost, so the budget cannot be enforced there.)
  • Nothing is lost at a stop. A budget stop or /quit writes the attestation as incomplete with the questions answered so far and keeps the reviewer session. Running defend again on the same diff resumes from the next question without paying for the analysis twice; --restart begins over. Accepting a risk costs nothing: it is recorded locally without a reviewer turn.
  • Per-risk overrides let you pay for a stronger reviewer only where it matters, e.g. overrides: { critical: { model: opus, effort: high } }. The analysis turn always runs on the cheap default; the override applies to the answer turns once the risk is known.
  • timeoutSeconds: 180 per reviewer turn (the analysis turn gets twice that). A reviewer that cannot answer fails loudly instead of spinning.
  • Before the run the header shows model, effort, budget and timeout; after the analysis it shows what is left per question. After every answer you see the cost of that turn against the budget; the summary shows cost per question and one line with total spend, reviewer turns and tokens read from cache. Changes over 25 files or 1,500 lines ask for confirmation first.
  • Answers are graded, not re-investigated. The analysis turn, which already read the code, writes a hidden reference answer per question (what a correct answer must establish, expected concepts, fatal misconceptions, file:line). Each of your answers is then graded by a tool-free call on a small model (haiku by default) against that reference: about a cent instead of a full agentic turn. Only when you make a specific claim the reference does not cover (another caller, a guard, a lock, a test) does Defend escalate to the reviewer and check that claim in the repository. verification: auto | cheap | full in defend.yml or --verification selects this; full restores the old behavior of verifying every answer in the repository.
  • After the analysis the header says how many questions the remaining budget covers, so a short budget is visible before the first answer rather than mid-defense.

If the reviewer cannot run (expired login, missing CLI), defend exits with the reason and the command that fixes it. defend doctor checks the same things up front.

During a defense: an empty line submits the answer, /accept <reason> records an accepted risk instead of answering, /useless <why> flags a pointless question (recorded, never counted against you), /quit pauses without losing anything. After a graded FAIL you can type /dispute <why>: the strong reviewer re-checks that one verdict in the repository (once per question) and overturns it if you were right. After a failed defense, defend --only-failed re-asks just the failed questions on the same diff, without a new analysis.

Every question is blocking or advisory. Blocking means a wrong answer leaves an unguarded production failure mode (double side effects, data loss, auth bypass, money); at most one or two per defense. Advisory marks an understanding gap worth closing; it is recorded but never fails the defense. A short answer that establishes the expected points passes; follow-ups deepen, they do not gate.

Every file:line the reviewer shows you is checked against the working tree first: a file that does not exist or a line past the end of the file is marked as such instead of printed as fact, and the grader sees the actual text of each cited line next to the reference. This is deterministic and cheap; it cannot tell whether a valid line says what the reviewer claims, which is what /dispute is for.

How it connects to Claude Code and Codex

Defend is an orchestrator over the coding agent you already have. It does not index your repository or call a model API directly.

| | Claude Code | Codex | |---|---|---| | Invocation | claude -p with a JSON schema for structured output | codex exec --json --output-schema | | Repository access | read-only tools only (Read, Grep, Glob, git diff/log/show/blame) | --sandbox read-only | | Coherent session | --resume <session> for every answer | codex exec resume <thread> | | Isolation | no MCP servers, no project hooks, user settings only | project MCP config still loads (harmless) | | Fresh context | always a new session, never the one that wrote the code | same |

The reviewer that interviews you is never the session that generated the code: the same repository, a fresh conversation, so it has to infer the design from the code like a colleague would.

Both adapters implement one interface (DefenseAgent.runTurn) in src/agents/. Adding another provider is one file.

Using Defend from inside Claude Code or Codex

defend init installs a defend skill in .claude/skills/ and .agents/skills/. Inside either tool you can then say "defend this change" or "show my defend dashboard". The skill knows that the defense itself is interactive and must run in your terminal, and that the dashboard is defend stats --me --json, which it summarizes as a short knowledge map: defenses, pass rate, minutes, and the categories where your follow-ups cluster.

Configuration

defend.yml in the repository root. Everything is optional.

version: 1

reviewer:
  provider: claude-code   # claude-code | codex
  model: sonnet           # cheap default
  effort: medium          # low | medium | high | max
  overrides:
    critical: { model: opus, effort: high }

verification: auto        # auto | cheap | full
grader:
  model: haiku            # tool-free grader for answers
  effort: low

budgetUsd: 1              # hard stop for the whole defense
timeoutSeconds: 180       # per reviewer turn

questions:                # budget per risk level; the reviewer asks fewer when there is less to ask
  low: 1
  medium: 3
  high: 5
  critical: 6
maxFollowUps: 2

input:
  paste: deny             # deny | warn | allow

ignore:
  - "**/*.lock"
  - "**/generated/**"

rules:
  - name: payments
    paths: ["**/payment*/**", "**/billing/**"]
    risk: critical
    require: [data_integrity, security, failure_mode]

Rules are optional and only ever add scrutiny. Every change in every folder is analyzed by the reviewer, with or without rules. A matching rule does two things: raises the risk floor for the touched paths, and requires at least one question from each listed category. Rules never restrict what is analyzed and never supply the question text. The only thing that excludes files is the ignore list. Questions are always generated from the actual change and the actual repository, so a rule for payments produces a question about your payment change, not a checklist item.

Question categories: architecture, failure_mode, blast_radius, security, data_integrity, concurrency, state, testing.

Attestations

A passing defense writes .defend/attestations/<diffHash>.json:

{
  "author": { "name": "Jasmin", "email": "[email protected]" },
  "reviewer": { "provider": "codex" },
  "diffHash": "e3ef985bf51d…",
  "risk": "high",
  "result": "pass",
  "categories": { "state": "pass", "failure_mode": "pass", "security": "accepted_risk" },
  "questions": [{ "id": "q1", "category": "state", "status": "pass", "followUps": 1, "typedSeconds": 74, "pasteAttempts": 0 }]
}

Every attestation is also mirrored to ~/.defend/history/<repository>/, so defend stats --all shows your knowledge map across every repository on the machine without committing anything. In team mode the repository folder is committed too: the attestation travels with the branch and CI can verify it. Answers themselves are never stored.

Every attestation is signed (HMAC-SHA256 over its canonical JSON). The key comes from DEFEND_SIGNING_KEY, or a per-machine key generated on first use. Editing an attestation after the fact makes defend verify reject it.

What the attestation is: evidence that a named person defended this exact diff, with typing evidence per answer. What it is not: proof that nobody helped. It is friction and a record, not an anti-cheat mechanism.

CI enforcement

defend verify and defend report only need git and a shell, so they run on any CI. defend init --ci <provider> writes a ready template:

| Provider | --ci | File | Comment posted with | |---|---|---|---| | GitHub Actions | github (or --github) | .github/workflows/defend.yml | gh pr comment (built-in token) | | GitLab CI | gitlab | .gitlab-ci.defend.yml, include it from .gitlab-ci.yml | MR note via API, optional DEFEND_GITLAB_TOKEN | | Azure Pipelines | azure | azure-pipelines.defend.yml, add as build validation | PR thread via REST with System.AccessToken |

Anything else (Bitbucket, Jenkins, Buildkite): run defend verify --base origin/<target> as the gate and pipe defend report --base origin/<target> into whatever posts comments on your platform.

On every pull request the template runs defend verify --base origin/<base> and posts defend report:

🛡 Author Defense
Risk: HIGH · Result: ✅ PASS · Defended by: Ana

| Dimension      | Result |
| State          | ✅     |
| Failure mode   | ✅     |
| Security       | ⚠️ accepted risk |

Questions 3 · Follow-ups 1 · 184s · reviewer claude-code
Defense verified for diff e3ef985bf51d · Signature valid

Make the check required (branch protection, merge request approval rule, or build validation policy) and a change cannot merge until its author has defended the exact diff under review. The team shares one signing key: export DEFEND_SIGNING_KEY on developer machines and add it as the CI secret of the same name.

Who can defend this file

Every passing attestation records the files it covered. defend map turns that into a coverage map of the codebase: for each file, who defended it, when, and which categories (state, failure modes, security...) they held up under. Knowledge decays: a defense counts fully today and halves every 90 days, so the map stays honest after churn.

$ defend map src/payments
● src/payments/refund.ts
   Ana ×3, Marko · 1d ago · Failure mode, Security, State
● src/payments/charge.ts
   Dev ×2, Ana · 3d ago · Architecture, Data integrity, Concurrency

defend itself warns when a change touches files nobody has ever defended: if AI wrote it, no human on record understands it yet. Use the map to pick reviewers, to answer "where are we exposed?", and to see which modules a team would struggle to explain. It is a map of the code, not a ranking of people.

Dashboards

  • defend stats in the terminal, defend stats --me for yourself, defend stats --all across every repository you defended on this machine.
  • defend stats --html writes a self-contained page: defenses per week, confidence by category, usage and cost per reviewer, adoption per author (activity only), accepted risks, recent defenses.
  • defend stats --html --repos ~/src/api ~/src/web ~/src/mobile is the company view across repositories, which is what you want when the organisation pays for the Claude or Codex subscription and wants to see how the tool is used. No per-person understanding scores, by design.
  • Inside Claude Code or Codex: "show my defend dashboard" (installed by defend init).

Why not just write a skill that asks questions?

You can, and it will ask decent questions. What a skill cannot do:

  • Be independent. A skill runs inside the session that wrote the code, with that session's context and assumptions. Defend starts a fresh reviewer that has to infer the design from the code, like a colleague would.
  • Produce a record anyone can trust. Defend binds a signed attestation to the exact diff hash and the git author, and defend verify rejects anything edited afterwards. A chat transcript proves nothing to CI.
  • Block a merge. The GitHub workflow turns the attestation into a required check. Policy (rules, required categories, risk acceptance) lives in the repository, not in someone's prompt.
  • Work the same for everyone. The same defense whether the author uses Claude Code or Codex, with typed answers and paste policy, so the team gets one standard instead of twelve personal prompts.
  • Learn. /useless feedback, follow-up rates and accepted risks accumulate into a question-quality metric and a knowledge map across repositories and time. That data is the product; a skill starts from zero every time.

Privacy

Source code, diffs and answers stay on the machine that runs the defense. The only durable output is the attestation above. There is no telemetry.

Status

Early. The core loop (fresh reviewer, evidence-backed questions, typed answers, verification against the repository, diff-bound attestation) works with both providers. Not yet built: a GitHub check that renders the attestation on the PR, signed attestations, and organization policies.

License

MIT