A community-driven registry for the Claude Code ecosystem. Not affiliated with Anthropic.
Catch vibecoding mistakes before non-technical contributors cause incidents in shared codebases.
For the non-technical contributor: Claude wrote the code. You read the first two lines, it looked fine. The commit message says "update." You accepted "theirs" on all the merge conflicts. The test suite is green because Claude lowered the coverage threshold, not because the tests pass. The API key is in a file you never opened — it won't appear in your diff.
Run this before you commit. It reads your actual git state, not what you assume is in it.
For the developer: Everything above has already happened in your repo. Install this before it happens again.
40 risk categories. Developer-defined contracts. Every flag cites file:line. Claude reads the actual git state — nothing is self-reported.
| Risk | Without vibe-safe | With vibe-safe |
|---|---|---|
| Credential committed (not in diff) | Missed — not in staged files | Caught — full-repo grep, src/api/client.ts:14 |
| Committing directly to main | No check | Stopped — feature branch created automatically |
| Config/auth/migration/quality-gate files in diff | No check | Flagged with escalation instruction |
| Merging conflict by accepting all "theirs" | No check | Both sides explained, Danger Zone → stop |
| Claude lowered a quality threshold to pass CI | No check | Caught — diff scanned for numeric decreases in quality configs |
@ts-ignore / eslint-disable added | No check | Flagged — suppressed error, not fixed |
Failing test skipped with .skip() | No check | Flagged — bypassed test, not fixed |
| Test file deleted | No check | Flagged — suite passes by omission |
console.log / debugger left in code | No check | Flagged — debug artifact in production |
Empty catch {} block | No check | Flagged — errors silently swallowed |
Lock file changed without package.json | No check | Flagged — undocumented dependency change |
| Binary file committed | No check | Flagged — permanent history bloat |
| PII in committed code | No check | Flagged — email/phone pattern on added lines |
| Internal hostname committed | No check | Flagged — infrastructure topology exposed |
Claude proposes git push --force | No check | Auto-escalates to ALARM |
dangerouslySetInnerHTML / innerHTML = added | No check | Flagged — XSS attack surface |
eval( added | No check | Flagged — arbitrary code execution risk |
| SSL verification disabled | No check | STOP — TLS silently removed |
| CORS wildcard set | No check | Flagged — API open to any domain |
.gitignore entries removed | No check | Flagged — previously ignored files now tracked |
setTimeout/sleep with hardcoded value | No check | Flagged — timing hack, not a real fix |
: any / as any proliferation (TypeScript) | No check | Flagged — type system escaped |
debug: true in non-test config | No check | Flagged — debug mode in production |
throw new Error("TODO") / // TODO in implementation | No check | Flagged — placeholder shipped instead of real code |
| Commented-out code blocks | No check | Flagged — Claude disabled working code, possibly uncertain |
| Private key / cert file staged | No check | STOP — binary credential, text grep misses it |
rm -rf in committed script | No check | Flagged — destructive path without knowing prod layout |
throw "string" without Error | No check | Flagged — stack trace lost, bugs undiagnosable in production |
New env var, no .env.example update | No check | Flagged — next dev spinning up won't know to set it |
| Migration with no rollback | No check | Flagged — schema change that can't be undone automatically |
| New source code, no test changes | No check | Flagged (or hard-blocked via require_tests) |
| Claude changed more files than asked | No check | SCOPE mode — intent vs diff, file-by-file verdict |
Math.random() in auth/token/session file | No check | STOP — not cryptographically secure |
| SQL string concatenation / f-string SQL | No check | STOP — injection risk, use parameterized queries |
shell: true / shell=True in subprocess | No check | STOP — command injection via unsanitized input |
Missing await on async DB/HTTP call | No check | Flagged — result is likely a Promise, not a value |
| Test block added with no assertions | No check | Flagged — test always passes, behavior unchecked |
| gitleaks (entropy-based credential scan) | No check | STOP if installed — catches what grep misses |
| semgrep (OWASP rule-based analysis) | No check | STOP if installed — injection, traversal, and more |
| npm audit (known CVEs in dependencies) | No check | STOP if installed — high/critical CVEs blocked |
git clone https://github.com/googlarz/vibe-safe ~/.claude/skills/vibe-safe
Install the pre-commit hook (runs locally on every git commit):
cp ~/.claude/skills/vibe-safe/hooks/pre-commit .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
Install CI integration (runs in GitHub Actions — catches --no-verify bypasses):
mkdir -p .github/vibe-safe .github/workflows
cp ~/.claude/skills/vibe-safe/ci/vibe-safe-ci.sh .github/vibe-safe/
cp ~/.claude/skills/vibe-safe/ci/workflow.yml .github/workflows/vibe-safe.yml
Or just run vibe-safe — BEFORE mode installs both automatically.
GitLab CI integration:
mkdir -p .gitlab/vibe-safe
cp ~/.claude/skills/vibe-safe/ci/vibe-safe-ci.sh .gitlab/vibe-safe/
Include the job in your .gitlab-ci.yml:
include:
- local: '/ci/gitlab-ci.yml' # or copy the job from ci/gitlab-ci.yml
Set GITLAB_TOKEN in your CI/CD variables (Settings → CI/CD → Variables) to enable MR comment posting.
Bitbucket Pipelines integration:
mkdir -p .bitbucket/vibe-safe
cp ~/.claude/skills/vibe-safe/ci/vibe-safe-ci.sh .bitbucket/vibe-safe/
Merge the step definition from ci/bitbucket-pipelines.yml into your bitbucket-pipelines.yml.
Just say vibe-safe — Claude auto-detects the right mode from your git state:
No staged changes, describing a task → BEFORE mode
git diff --staged has content → COMMIT mode
Unstaged changes present → REVIEW mode
"did Claude change more than I asked?" → SCOPE mode
Commits ahead of main, about to open PR → PR mode
Conflict markers in any file → CONFLICT mode
Claude proposed something that feels big → ALARM mode
"what does this flag mean?" → EXPLAIN mode
Developer reviewing a vibe-coded PR → REVIEWER mode
Checking whether past commits are clean → HISTORY mode
.vibesafe exists, repo has evolved → REFRESH mode
Or invoke directly: vibe-safe commit / vibe-safe explain ssl / vibe-safe reviewer / vibe-safe refresh / etc.
After any session: vibe-safe verify — confirms the session is clean before you walk away.
Active, not passive. Claude runs the actual shell commands — git diff, git grep, git branch — and reports what it finds. You don't fill out a form.
Pre-commit hook runs without Claude. BEFORE mode installs hooks/pre-commit into .git/hooks/pre-commit. From then on, 70 mechanical checks run on every git commit whether or not you remember to invoke the skill. Branch check, credential scan, Danger Zone audit, suppression patterns, security sinks, private key files, env var drift, migration rollback, server-side injection (SSRF, path traversal, NoSQL, prototype pollution), authz mistakes, crypto pitfalls, migration revision conflicts, weak-default secrets, developer contracts — all in pure shell.
CI integration closes the bypass gap. The hook can be skipped with git commit --no-verify. The GitHub Actions workflow cannot. BEFORE mode also installs ci/vibe-safe-ci.sh + ci/workflow.yml — the same checks run on every push and PR, with GitHub annotations for each finding. --no-verify is auto-escalated to ALARM if Claude proposes it.
CI writes a PR comment and step summary. When GH_TOKEN and PR_NUMBER are available, the CI script posts (or updates) a <!-- vibe-safe-audit --> comment on the PR with all findings — no need to dig through the Actions log. The comment is deduplicated: re-runs update the same comment in place. A matching job summary appears in the Actions tab. Fork PRs with read-only tokens get a logged skip, not a silent failure.
require_reviewer enforced in CI. Set require_reviewer: @alice in .vibesafe and the CI script checks GitHub's reviewer API — if the named reviewer hasn't been added, the check fails. Only runs when GH_TOKEN and PR_NUMBER are available; skips with a warning otherwise.
Optional tooling integration. When gitleaks, semgrep, or npm audit are installed in CI, vibe-safe runs them automatically. gitleaks detects high-entropy secrets that grep misses (Base64-encoded keys, rotated patterns). semgrep applies OWASP rule sets for injection, path traversal, and deserialization. npm audit flags known CVEs in your dependency tree. All three degrade gracefully — if a tool isn't installed, its check is silently skipped.
Agentic remediation. COMMIT mode fixes what's fixable instead of just flagging:
| Problem | What Claude does |
|---|---|
On main/master | git checkout -b feature/[3-word-slug], then re-runs checks |
| Credential in staged file | git restore --staged <file>, explains key must be rotated |
| Danger Zone file staged | git restore --staged <file>, tells you what to ask a dev |
| Out-of-scope or too many files staged | SCOPE audit — file-by-file verdict, git restore for anything unexpected |
| All checks pass | Generates commit message, runs git commit -m "..." for you |
Developer-defined contracts. The developer sets the rules once in .vibesafe. vibe-safe enforces them for every PM contribution — no code review nagging required.
# .vibesafe
danger_zone: src/payments/
safe_zone: src/components/marketing/
require_tests: true # New source files must have test changes
max_changed_files: 15 # Warn + SCOPE audit if exceeded
require_migration_rollback: true # All migrations need a down/rollback
block_pattern: TODO # Hard stop if TODO appears in implementation
require_reviewer: @alice # Added to every PR description
Commit .vibesafe once. Every contributor — and the pre-commit hook and CI — gets the same rules automatically.
Runs before Claude writes anything. Checks your branch (creates a feature branch if on main), traces who owns the target files via git log, installs the pre-commit hook and CI workflow if missing, and produces a scoped prompt that limits what files Claude is allowed to touch.
If no .vibesafe exists: Claude scans the repo to discover rules (test file count, average commit size, migration rollback patterns, top committers), then generates a single document to paste into Slack or email — discovered rules with inline confirmation prompts, open questions below. PM sends it, pastes the answers back, Claude writes .vibesafe.
After Claude writes code, before you commit. Runs git diff HEAD for unstaged changes and git grep across all tracked files for credential patterns. Credentials live in files you didn't intend to change and won't appear in your diff.
When you think Claude changed more than you asked — or when max_changed_files fires. Claude asks what the original task was, then evaluates every changed file: IN SCOPE / LIKELY NEEDED / SUSPICIOUS / OUT OF SCOPE. Removes out-of-scope files with your confirmation.
70 checks across credentials, Danger Zones, code health, security patterns, server-side injection, authz/authn, crypto, scope, env vars, migrations, and developer contracts — each with remediation. When all pass: Claude generates the commit message and runs git commit for you.
Reads git diff main...HEAD, asks why you're making the change, generates a complete PR description with what changed, what to test, flagged uncertainties, and suggested reviewers. Appends a PR safety artifact — a table showing what vibe-safe verified — so the reviewer sees the evidence without asking.
Reads conflict markers and explains both sides in plain English — what the current version does, what your change does, what's specifically lost if you accept either side. Never recommends "accept all theirs/ours." Danger Zone file in conflict → STOP — CALL A DEVELOPER.
When Claude proposes something that feels big. Assesses reversibility, shared-infra impact, and whether a developer would expect to review this. Auto-escalates for: git push --force, git commit --no-verify, direct database commands, CI check bypasses. Output: GO AHEAD / PAUSE AND CHECK / STOP — CALL A DEVELOPER.
Post-session clean check. Runs branch check, full file list for the PR, credential sweep, and commit message audit. Output: CLEAN or remaining flags with file:line evidence.
Scans recent git history for past mistakes needing active remediation. Finds commits that added credential patterns (even if later "deleted"), suspicious commit messages hinting at cleanup attempts, and recently deleted files. Distinguishes active exposure (still in HEAD) from historical exposure (removed but still in history — key rotation + git filter-repo required). Includes exact remediation steps.
Deep plain-English explanation of any vibe-safe flag. vibe-safe explain ssl tells you what SSL verification is, why disabling it is dangerous, what it looks like when it goes wrong, what Claude should have done instead, and one sentence you can say to your developer. For when "flagged" isn't enough and you want to actually understand it.
For developers reviewing a PR opened by a non-technical contributor. Reads the full diff and produces: what the PM intended, what actually changed, which vibe-safe patterns are present, what to specifically test, and questions to ask if intent and implementation don't match.
Files that need developer involvement regardless of change size:
| Category | Patterns |
|---|---|
| Environment | .env, .env.* |
| Infrastructure | nginx.conf, *.conf, Dockerfile, docker-compose.* |
| CI/CD | .github/workflows/, Jenkinsfile, .circleci/, .gitlab-ci.yml |
| Database | migrations/, schema/, *.sql |
| Auth | files named: auth, login, session, jwt, oauth, permission, role |
| Build | webpack.config.*, vite.config.*, tsconfig.json |
| Quality gates | jest.config.*, vitest.config.*, codecov.yml, .nycrc, .eslintrc.*, .stylelintrc.*, sonar-project.properties |
| Dependencies | package.json, Gemfile, requirements.txt (version changes) |
Built with TDD: baseline test first (RED) → skill written (GREEN) → loopholes closed (REFACTOR).
Baseline (no skill): Subagent playing a non-technical PM, test repo with a credential outside the diff, nginx.conf, an irreversible migration, and a scope creep file. Result: 0/4 caught. Committed directly to main with a vague message.
With skill: Same scenario. Result: 4/4 caught — credential flagged with file:line, main-branch commit stopped, migration and nginx.conf escalated to developer.
Five additional mode tests passed: BEFORE (main-branch stop), CONFLICT (auth file Danger Zone), COMMIT (real-incident quality gate weakening from PM's own experience).
v1.7 new-check baseline (20 tests, automated): Pre-commit hook tested against all three new v1.7 check categories in isolated git repos:
| Scenario | Expected | Result |
|---|---|---|
process.env.NEW_KEY staged, no .env.example update | BLOCK | ✅ caught |
os.environ['NEW_KEY'] in Python, no .env.example | BLOCK | ✅ caught |
.env.example staged alongside new env ref | pass | ✅ passed |
JS migration without exports.down | BLOCK | ✅ caught (Danger Zone) |
Rails migration without def down | BLOCK | ✅ caught (Danger Zone) |
| Django auto-reversible migration | BLOCK | ✅ caught (Danger Zone — needs developer sign-off) |
Migration + require_migration_rollback: true, no down() | STOP | ✅ stopped |
Source file staged, require_tests: true, no test file | STOP | ✅ stopped |
Source + test file staged, require_tests: true | pass | ✅ passed |
block_pattern: TODO in source file | STOP | ✅ stopped |
block_pattern: TODO in test file only | pass | ✅ exempt |
max_changed_files: 2, 3 files staged | warn only | ✅ warned, didn't block |
| All 5 pre-existing checks (main, credential, test skip, XSS, eval) | BLOCK | ✅ no regressions |
20/20 tests passed. .env.example template files excluded from Danger Zone (they're meant to be committed). Block pattern exemption verified per-file, not per-content-line.
v1.8.1 CI script tests (15 tests, automated): CI script tested with bare-repo-as-origin harness (enables git fetch/git diff origin/main...HEAD without network):
| Scenario | Expected | Result |
|---|---|---|
| Credential in tracked file | BLOCK | ✅ caught |
Test bypass .skip() | BLOCK | ✅ caught |
XSS sink innerHTML = | BLOCK | ✅ caught |
eval() added | BLOCK | ✅ caught |
process.env.NEW_KEY without .env.example | BLOCK | ✅ caught (upgraded from warn to fail) |
process.env.NEW_KEY with .env.example | pass | ✅ passed |
.env.example staged alone | pass (warns) | ✅ passed |
Migration without down(), no contract | pass (warns) | ✅ passed |
Migration without down(), require_migration_rollback: true | BLOCK | ✅ caught |
Source file, require_tests: true, no test file | BLOCK | ✅ caught |
Source + test file, require_tests: true | pass | ✅ passed |
block_pattern: TODO in source | BLOCK | ✅ caught |
block_pattern: TODO in test file | pass | ✅ exempt (per-file check, .vibesafe itself excluded) |
max_changed_files: 2, 3 files changed | pass (warns) | ✅ warned, didn't fail |
| Clean change | pass | ✅ passed |
15/15 tests passed. Two bugs fixed during CI test authoring: env drift upgraded from warn to fail (parity with hook), block_pattern false positive when .vibesafe itself contains the blocked pattern.
v1.9.0 new-check verification (10 tests, automated): Five new manual checks and optional tooling integration tested:
| Scenario | Expected | Result |
|---|---|---|
Math.random() in auth.ts | STOP | ✅ caught |
Math.random() in animation.ts | pass | ✅ passed |
SQL string concatenation "SELECT..." + var | STOP | ✅ caught |
shell: true in script | STOP | ✅ caught |
| Test block added with no assertions | pass (warns) | ✅ warned, didn't block |
| Same 5 checks in CI script | STOP/warn | ✅ matched hook behavior |
| gitleaks absent — graceful skip | pass | ✅ no false failure |
| semgrep absent — graceful skip | pass | ✅ no false failure |
| npm audit absent — graceful skip | pass | ✅ no false failure |
| All pre-existing checks (15/15 CI, 20/20 hook) | no regressions | ✅ all passing |
10/10 tests passed. Optional tooling (gitleaks, semgrep, npm audit) fails gracefully when not installed — same checks still run via grep.
v1.10.0 expansion verification (25/25 hook, 20/20 CI, automated): Coverage threshold detection, developer contracts, false positive tuning, and GitLab/Bitbucket CI support tested across both scripts. All pre-existing checks preserved. Hook test count grew from 20→25; CI test count grew from 15→20.
v1.10.4 new security checks (29/29 hook, 24/24 CI, automated): Four new checks added and verified:
| Scenario | Expected | Result |
|---|---|---|
API key literal in src/config.ts (frontend path) | STOP | ✅ caught (hook + CI) |
API key literal in util.ts (non-frontend path) | pass | ✅ not a false positive |
logger.info('user token:', userToken) in dashboard.ts | pass (warns) | ✅ soft flag only |
Insecure CSP unsafe-eval header | pass (warns) | ✅ soft flag only |
New app.post() route without rate limiting | pass (warns) | ✅ soft flag only |
| All pre-existing checks (24/24 CI, 25/25 hook) | no regressions | ✅ all passing |
29/29 hook tests passed, 24/24 CI tests passed. auth.ts basename detection confirmed: files in auth/security namespace still hit Danger Zone before check 32; logger.info (backend logging pattern) correctly reaches check 32 and soft-flags without blocking.
v1.10.6–v1.10.8 credential-scan hardening (incident-driven): A real production incident — a DemoCard component with hardcoded email/password demo accounts bundled into the public JS artifact — exposed three compounding misses in the credential regex. All three fixed and regression-tested:
| Gap | Fix |
|---|---|
Colon syntax password: 'value' not caught (only = was) | CRED_PATTERN extended to [:=] |
Special chars in values (Demo@123!) missed | !@# added to the value character class |
| No email+password proximity detection | New check 35 — blocks email + password literal in the same source file (skips test/fixture/seed/mock files) |
Nested test-dir exclusion also fixed: :!tests/ (root-only) → :(exclude,glob)**/tests/** so backend/tests/, app/tests/ are properly excluded from the cross-scan. 9/9 gap-regression tests passed.
v1.11.0 — 23 new checks across 6 tiers (41 tests, automated): Expanded the hook from 35 → 58 checks after a deep gap analysis of "what patterns vibes-coding produces that grep can catch":
NEXT_PUBLIC_*/VITE_*), extended cloud-key prefixes (ASIA/ghs_/github_pat_/hf_/npm_/xox*/SG./whsec_)none algorithm, JWT without expiry/algorithms whitelistpull_request_target without SHA pinning, continue-on-error masking41/41 tests passed.
v1.11.1 — migration revision conflict (check 58, 4 tests): After a parallel-migration incident (two 019_* migrations both pointing to 018_client_deliverables, breaking alembic upgrade head), added detection: when a migration is staged, its down_revision is compared against every committed migration — a shared parent (split chain) is blocked with both filenames and the correct head to chain from. 4/4 tests passed.
v1.12.0 — Python pitfalls + supply chain (checks 59–64, 14 tests):
except:, dynamic code-execution calls in source, random module in security-named Python filesAccountKey= and GCP private_key_id added to CRED_PATTERN@v*/@main/@latest) — warns before the danger-zone bail so it's always visible14/14 tests passed.
v1.13.0 — weak defaults & misconfig (checks 65–68, 11 tests):
JWT_SECRET = "changeme", SIGNING_KEY = "your-secret-here") — catches the UPPER/camelCase/hyphenated secret names the case-sensitive check 2 misseshttpOnly:false/secure:false in cookie context)chmod 777 / os.chmod 0o777)math/rand in security-named files — completes the crypto-RNG trio (JS check 26 → Python 63 → Go 68)11/11 tests passed. Hook now runs 70 mechanical checks.
Three categories of risk that grep cannot cover.
Why not catchable: Whether a response leaks sensitive fields depends on what the serializer includes — that requires understanding the data model, not reading diffs.
How to handle:
return await db.user.findFirst(...) directly in a route handler is the root cause. Fix with a schema that explicitly names exposed fields: response_model=UserPublic (FastAPI), fields = ['id', 'name'] (DRF), as_json(only: [:id, :name]) (Rails), select: { id: true } (Prisma).password_hash, stripe_customer_id, ssn, internal_id don't appear in responses before launch.Why not catchable: Whether you need one depends on what data you collect, where your users are, and applicable law — none of which are in the code.
How to handle:
email, name, phone, ip_address, location, device_id, date_of_birth, behavioral tracking — any of these mean you need a policy before real users.Why not catchable: Where data ends up, who can access it, and whether it's encrypted requires understanding infrastructure — not reading diffs.
How to handle:
console.log, logger.info, or your observability platform (Datadog, Sentry, CloudWatch) is stored, queryable, retained for months. Treat log destinations with the same access controls as your database.package.json.Credentials live in files you didn't intend to change. If you scan only staged files, you miss them. vibe-safe runs git grep across all tracked files in every REVIEW and COMMIT check — the same command that catches a secret committed three weeks ago in a different session.
MIT
1000+ skills curated from Anthropic, Vercel, Stripe, and other engineering teams
Design enforcement with memory — keeps your UI consistent across a project
Universal SEO skill for Claude Code. 25 sub-skills + 18 sub-agents covering technical SEO, E-E-A-T, schema, GEO/AEO, bac
Route Claude Code traffic to any of 17 provider backends including free or local models