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

@vibeguard-dev/local

v1.8.0

Published

Static SQL safety analysis for AI agents — catch dangerous queries before they reach your database.

Downloads

64

Readme

@vibeguard-dev/local

Static SQL safety analysis for AI agents. Catch the dangerous queries before they reach your database.

npm version License CI


🆕 v1.8 — works with every major coding agent

One command auto-installs the SQL safety skill into every agent on your machine:

npm install @vibeguard-dev/local libpg-query
npx vg-local install-skill         # interactive — prompts before writing anywhere

Supported agents (auto-detected):

| Agent | Detection signal | What gets installed | |---|---|---| | Claude Code (user + project) | ~/.claude/ or ./.claude/ | skills/vibeguard-sql-safety/SKILL.md | | Cursor (legacy + modern) | .cursorrules or .cursor/rules/ | rule file with the SQL safety instruction | | aider | CONVENTIONS.md or .aider.conf.yml | block appended to CONVENTIONS.md | | GitHub Copilot CLI | .github/instructions/ etc. | .github/instructions/vibeguard-sql-safety.instructions.md | | Google Gemini CLI | gemini.md or .gemini/ | block appended to gemini.md | | Codeium Windsurf (legacy + modern) | .windsurfrules or .windsurf/rules/ | rule file with the SQL safety instruction | | AGENTS.md family — Codex CLI, OpenCode, OpenClaw, Hermes, Pi | AGENTS.md, opencode.json, .pi/, .openclaw-system.md | block appended to AGENTS.md |

All instruction-file installs are idempotent (re-running replaces between marker comments, never duplicates). All file-write decisions are filesystem-based and conservativeinstall-skill only writes to harnesses it can auto-detect, and prompts before touching anything unless --yes is passed.

After the install, every supported agent reads its instruction file on every prompt and pre-flights SQL through:

echo "$SQL" | vg-local analyze --stdin --format=jsonl

Exit code 1 if any block-severity catch fires; one JSON object per catch on stdout. The agent gates on that.

→ Detailed install / flag reference: see Agent skill install below.


What it does

Your AI agent generates a SQL query. Before you run it, @vibeguard-dev/local checks the query's structure for known footguns: missing WHERE clauses, cartesian explosions, type-coercion bugs, recursive CTEs that don't terminate, irreversible DROP / TRUNCATE, over-fetching projections. 36 senior-DBA-level checks, all static, sub-millisecond, zero network calls.

Known limitations

VibeGuard is a static, schema-blind analyzer. It checks the shape of a query, not its run-time effect. A few boundaries you should know about before you ship it into CI:

  • Literal tautologies in WHERE are caught (since v1.6.0). SQL-034 fires at block / 95 on UPDATE / DELETE whose WHERE reduces to a literal tautology — WHERE 1=1, WHERE true, WHERE id = id, WHERE NOT false, WHERE 'a' = 'a'. The cross-join variants (UPDATE … FROM / DELETE … USING without a join predicate) are caught by SQL-035 and SQL-036 at block / 90.

    What is still NOT caught: semantic tautologies that depend on schema knowledge, such as DELETE FROM users WHERE id IS NOT NULL on a NOT NULL PK column, or DELETE FROM users WHERE id IN (SELECT id FROM users). These require column-nullability or correlated- reference tracking and are out of scope for the local SDK.

  • Schema-aware checks are out of scope. The SDK does not know which columns are NOT NULL, which columns are foreign-key targets, or which tables hold sensitive data. Rules that would require that context (e.g. "this WHERE col IS NOT NULL is a no-op because col is the NOT NULL PK") are deliberately not in local.

  • Run-time effects are not modeled. The analyzer does not execute the query, plan it, or evaluate constants. WHERE 1=1 and WHERE current_timestamp > '1970-01-01' are static-tautological in the same way; the SDK treats both as "has a WHERE clause".

The trade-off is intentional: every check runs offline, sub-millisecond, with zero network calls and zero schema dependencies. If you need schema-aware analysis, that's the cloud product.

Quickstart

npm install @vibeguard-dev/local libpg-query

libpg-query is a peer dependency — install it alongside the SDK. Server-side Node only for the initial release; browser support is out of scope for now.

One-shot CLI

The fastest way to see what the SDK does:

npx @vibeguard-dev/local init

That scaffolds an example SQL file, runs the analyzer on it, prints the catch with severity and fix, and adds an npm run lint:sql script to your package.json you can wire into CI. For ongoing use:

vg-local analyze 'src/**/*.sql'
# Exits 0 if no block-severity catches; 1 if any. CI-friendly.

vg-local analyze 'src/**/*.sql' --fix-dry-run
# Print a unified diff of what --fix would change. Read-only.

vg-local analyze 'src/**/*.sql' --fix
# Apply autofixes in place. SQL-005 / SQL-006 / SQL-001 / SQL-011
# have fixers; other rules surface their catches unchanged.

Agent skill install (vg-local install-skill)

One command auto-detects every agent harness on the current machine

  • project and installs the vibeguard-sql-safety skill into each:
npx vg-local install-skill          # interactive
npx vg-local install-skill --yes    # non-interactive (CI / scripts)

Harnesses supported in v1.8+: Claude Code (user + project), Cursor (.cursorrules and .cursor/rules/), aider (CONVENTIONS.md), GitHub Copilot CLI (.github/instructions/), Google Gemini CLI (gemini.md), Codeium Windsurf (.windsurfrules and .windsurf/rules/), and any harness that reads AGENTS.md — Codex CLI, OpenCode, OpenClaw, Hermes (Nous Research), Pi (Inflection).

10 distinct target ids; detection is filesystem-based (the subcommand looks for each harness's marker file or directory). Run vg-local install-skill --help for the full detection signal list.

For deterministic activation in Claude Code (the only harness where description-based routing is best-effort — every other supported harness reads its instruction file on every prompt by construction), opt in to a CLAUDE.md memory directive:

npx vg-local install-skill --yes --with-memory=user
# or --with-memory=project for project-scoped activation

Restrict to one specific harness:

npx vg-local install-skill --target=copilot-cli
# valid: claude-user | claude-project | cursor-rules-file |
#        cursor-rules-dir | aider | agents-md | copilot-cli |
#        gemini | windsurf-rules-file | windsurf-rules-dir

Idempotent — all file-append targets use marker comments (<!-- vibeguard-skill-begin --> / <!-- vibeguard-skill-end -->); re-running replaces between markers, never duplicates.

The SKILL.md file also ships in the npm tarball at node_modules/@vibeguard-dev/local/examples/agent-skill/SKILL.md for users who prefer to copy it manually.

Machine-readable output (--format=jsonl)

For agent harnesses, CI pipelines, and jq users, analyze has a stable JSONL output mode:

vg-local analyze 'src/**/*.sql' --format=jsonl
# One JSON object per catch on stdout. Parse errors stay on stderr.

vg-local analyze 'src/**/*.sql' --format=jsonl \
  | jq -c 'select(.severity == "block")'
# Filter to blocking catches only.

--format=ndjson is accepted as an alias and emits the same bytes. The per-line schema is stable post-1.7.0 and documented in STABILITY.md.

Pipe from stdin (--stdin)

For agents and shell pipelines that have SQL in-memory and don't want to write a temp file:

echo "$SQL" | vg-local analyze --stdin --format=jsonl
# Reads SQL from stdin. The "file" field in JSONL output is "<stdin>".

--stdin is mutually exclusive with positional globs, --fix, and --fix-dry-run (no on-disk file to write back to). The future --stdin --fix "stream-rewrite" mode is deliberately out of scope for v1.7.

Reflect mode (experimental)

vg-local analyze --reflect (or --format=reflect) emits one reflection JSON object per catch — designed for agent episodic-memory ingestion. Each line includes pain_score, importance, reflection, and suggested_lesson alongside the standard catch metadata. The schema is vg-reflect/0 and is explicitly NOT under semver commitments yet — see STABILITY.md → Reflection output schema (EXPERIMENTAL) for the graduation criteria, and docs/reflect-mode.md for consumption recipes.

vg-local analyze 'src/**/*.sql' --reflect \
  | jq -r '"- \(.suggested_lesson)"' >> LESSONS.md

ESM

import { analyze, init } from "@vibeguard-dev/local";

await init(); // one-time WASM-parser bootstrap

const result = analyze(`UPDATE users SET email = '[email protected]'`);

if (result.catches.length > 0) {
  console.error(result.catches[0]);
  // {
  //   code: 'SQL-003',
  //   title: 'Unbounded UPDATE statement',
  //   severity: 'block',
  //   confidence: 99,
  //   detail: 'UPDATE on `users` has no WHERE clause. Every row in the table will be modified...',
  //   fix:    'Add a WHERE clause that scopes the update to specific rows...',
  //   threatCategories: ['destruction'],
  // }
}

CommonJS

const { analyze, init } = require("@vibeguard-dev/local");

(async () => {
  await init();
  const result = analyze("DELETE FROM users");
  console.log(result.catches[0]?.code); // 'SQL-003'
})();

That's the whole API. After init(), every analyze() call is synchronous and sub-millisecond on typical queries.

What we deliberately do NOT do

This SDK does static analysis only. It checks the shape of your SQL. It does not:

  • Compare your agent's stated intent against what the SQL would actually do
  • Estimate real blast radius from the upstream Postgres planner
  • Provide tamper-evident audit logging
  • Offer human-in-the-loop escalation for grey-zone queries
  • Track per-agent behavioral baselines over time

For those, you want VibeGuard Cloud — the wire-protocol proxy and MCP server this SDK is the static-analysis layer of. Use the SDK locally; use the cloud in production. The two are designed to work together.

The 36 catches

Each catch has a stable code (e.g. SQL-001), a severity, a confidence range, and links to a docs page with examples and references. Catch IDs are forever-stable — once published, an ID always means the same thing (see STABILITY.md).

| Code | Title | Severity | Confidence | Default | Auto-fix | Status | |---|---|---|---|---|---|---| | SQL-001 | Cartesian explosion | block | 90–95 | ON | placeholder | ✅ shipped | | SQL-002 | Self-join footgun | warn | 70–85 | ON | — | ✅ shipped | | SQL-003 | Unbounded UPDATE / DELETE | block | 95–99 | ON | — | ✅ shipped | | SQL-004 | Implicit type coercion in WHERE | warn | 75–85 | ON | — | ✅ shipped | | SQL-005 | NULL comparison footgun | warn | 90–95 | ON | yes | ✅ shipped | | SQL-006 | OFFSET without ORDER BY | warn | 85–95 | ON | placeholder | ✅ shipped | | SQL-007 | NOT IN with nullable subquery | warn | 75–85 | ON | — | ✅ shipped | | SQL-008 | String-concat injection patterns | block | 80–95 | ON | — | ✅ shipped | | SQL-009 | DISTINCT without obvious reduction | info | 60–75 | ON | — | ✅ shipped | | SQL-010 | Correlated subquery in SELECT | warn | 70–85 | ON | — | ✅ shipped | | SQL-011 | Aggregate without GROUP BY | warn | 85–95 | ON | yes | ✅ shipped | | SQL-012 | Recursive CTE without termination | block | 80–95 | ON | — | ✅ shipped | | SQL-013 | DROP / TRUNCATE / DDL destruction | block / warn | 85–99 | ON | — | ✅ shipped (1.1.0) | | SQL-014 | INSERT/UPDATE/DELETE without RETURNING | info | 50 | OFF (opt-in) | — | ✅ shipped (1.1.0) | | SQL-015 | SELECT * over-fetch | info | 60 | ON | — | ✅ shipped (1.1.0) | | SQL-016 | COPY … FROM/TO PROGRAM (server-side RCE) | block | 99 | ON | — | ✅ shipped (1.6.0) | | SQL-017 | CREATE EXTENSION of untrusted procedural language | block | 95 | ON | — | ✅ shipped (1.6.0) | | SQL-018 | ALTER TABLE … DROP COLUMN | warn | 90 | ON | — | ✅ shipped (1.6.0) | | SQL-019 | CREATE TRIGGER (hidden side effects) | info | 75 | ON | — | ✅ shipped (1.6.0) | | SQL-020 | CREATE OR REPLACE FUNCTION (silent overwrite) | info | 70 | ON | — | ✅ shipped (1.6.0) | | SQL-021 | GRANT … TO PUBLIC | warn | 90 | ON | — | ✅ shipped (1.6.0) | | SQL-022 | CREATE/ALTER ROLE … SUPERUSER | block | 95 | ON | — | ✅ shipped (1.6.0) | | SQL-023 | pg_terminate_backend / pg_cancel_backend | warn | 85 | ON | — | ✅ shipped (1.6.0) | | SQL-024 | VACUUM FULL (ACCESS EXCLUSIVE outage) | warn | 80 | ON | — | ✅ shipped (1.6.0) | | SQL-025 | REFRESH MATERIALIZED VIEW (blocking refresh) | warn | 75 | ON | — | ✅ shipped (1.6.0) | | SQL-026 | MERGE with tautological ON | block | 90 | ON | — | ✅ shipped (1.6.0) | | SQL-027 | SET search_path to attacker-controlled schema | warn | 85 | ON | — | ✅ shipped (1.6.0) | | SQL-028 | pg_create_*_replication_slot | warn | 80 | ON | — | ✅ shipped (1.6.0) | | SQL-029 | dblink / CREATE SERVER (outbound network) | warn | 80 | ON | — | ✅ shipped (1.6.0) | | SQL-030 | pg_read_* / lo_export / pg_ls_dir (server FS) | warn | 90 | ON | — | ✅ shipped (1.6.0) | | SQL-031 | INSERT … SELECT … ON CONFLICT DO UPDATE (unbounded upsert) | info | 75 | ON | — | ✅ shipped (1.6.0) | | SQL-032 | EXPLAIN ANALYZE of a destructive statement | info | 80 | ON | — | ✅ shipped (1.6.0) | | SQL-033 | DO $$ … $$ opaque procedural block | info | 70 | ON | — | ✅ shipped (1.6.0) | | SQL-034 | WHERE 1=1 / literal tautology on UPDATE/DELETE | block | 95 | ON | — | ✅ shipped (1.6.0) | | SQL-035 | UPDATE … FROM without join predicate | block | 90 | ON | — | ✅ shipped (1.6.0) | | SQL-036 | DELETE … USING without join predicate | block | 90 | ON | — | ✅ shipped (1.6.0) |

See ROADMAP.md for what's in / out of scope.

Per-rule overrides

Opt in to default-OFF rules, or disable default-ON rules for a single call, via the rules option. The key is the rule's catch code (case-insensitive):

// Opt in to SQL-014 (missing RETURNING)
const result = analyze(sql, {
  rules: { 'sql-014': { enabled: true } },
});

// Disable SQL-007 for one call
const result = analyze(sql, {
  rules: { 'sql-007': { enabled: false } },
});

Use with...

Each example is a short, runnable integration showing how to wire the SDK into a common AI tool's pre-execution flow:

For in-editor feedback on sql`...` template literals (with --fix autofix), see the sibling package eslint-plugin-vibeguard.

Architecture, in one paragraph

The SDK parses your SQL with libpg-query, walks the resulting AST with a small, pure-function traversal helper, and runs each query through a registry of catch-functions. Each catch returns either null (didn't fire) or a structured Catch with code, severity, confidence, detail, and fix. No network calls. No state between calls. Sub-millisecond on typical queries. See ARCHITECTURE.md for the full design rationale.

Contributing

We welcome new catches that meet the SDK's scope: static-AST-detectable SQL anti-patterns with documented real-world incidents. The proposal process starts with an issue (template here); PRs come after maintainer feedback on whether the pattern fits.

See CONTRIBUTING.md for the full process, CODE_OF_CONDUCT.md for community expectations, and ARCHITECTURE.md for how the codebase is laid out.

Security

This SDK does static analysis. It does not execute SQL. It does not open network connections. It does not log to disk.

If you find a vulnerability — a false-negative that lets a real-world dangerous pattern through, a panic / crash on adversarial input, or a supply-chain concern — see SECURITY.md for the disclosure process. Do not file security issues as public GitHub issues.

License

Apache License 2.0 — see also NOTICE for attribution requirements that travel with derivative works.

About

VibeGuard is a wire-protocol security layer for AI agents that write SQL. This SDK is the open-source static-analysis component of the broader product.