Static analysis guardrails for AI-generated code
npx claudepluginhub wisteria30/code-guardrailsDetect and block test doubles and unapproved fallbacks in production code. AI coding tools silently introduce mock/stub/fake objects and fallback behaviors — this plugin catches them.
Catch silent fallbacks and test doubles that AI coding tools sneak into your production code.
AI tools generate working code fast. But behind the scenes, they swallow exceptions with pass, leave mock objects in production, and paper over failures with ?? "default". Miss it in review, and it ships.
code-guardrails parses every file save with a Rust engine plus ast-grep and warns Claude immediately when these patterns appear.
Prerequisites: Claude Code, ast-grep 0.14+, ripgrep 14.0+, Rust 1.77+
brew install ast-grep ripgrep
curl https://sh.rustup.rs -sSf | sh
Run inside Claude Code:
/plugin marketplace add Wisteria30/code-guardrails
/plugin install code-guardrails@code-guardrails-marketplace
Restart Claude Code. Verify with /scan.
cp -Rf ~/.claude/plugins/code-guardrails .claude/plugins/code-guardrails
rm -rf .claude/plugins/code-guardrails/.git
git add .claude/plugins/code-guardrails && git commit -m "chore: add code-guardrails plugin"
The hook detects violations after the fact, but CLAUDE.md prevents them from being written in the first place. Add the following to your project's CLAUDE.md:
## AI Code Policy
code-guardrails hook is active. Every Edit/Write is scanned for violations.
- NEVER write `except: pass`, empty `catch {}`, or `.catch(() => null)` — log the error and re-raise or wrap
- NEVER use `mock`, `stub`, `fake` identifiers in production code — test doubles belong in test files only
- NEVER add silent defaults (`.get(key, default)`, `?? value`, `|| value`) without spec approval — fail explicitly or mark with `# policy-approved: REQ-xxx <reason>`
- NEVER leave TODO/placeholder/stub implementations — implement fully or raise NotImplementedError
- Unspecified fallbacks are bugs. If the spec doesn't say "default to X", don't default to X
Adapt the rules to your project. The key is specific, verifiable constraints — vague guidance like "handle errors properly" doesn't change behavior.
Flags mock / stub / fake identifiers and unittest.mock imports in non-test files. Test files are always ignored.
# NG — mock left in production code
mock_client = MockHttpClient()
from unittest.mock import patch
# OK — inside test files (test_*.py, **/tests/**, etc.)
mock_client = MockHttpClient()
Flags patterns that silently swallow errors or substitute default values. Proper error handling (logging, re-raise, error wrapping) is not flagged.
# NG — swallowed exception
try:
connect()
except ConnectionError:
pass
# NG — silent defaults
timeout = config.get("timeout", 30)
name = user_name or "unknown"
port = os.getenv("PORT", "8080")
val = getattr(obj, "attr", None)
# NG — suppressed error
with contextlib.suppress(KeyError):
process(data)
# OK — exception handled properly
try:
connect()
except ConnectionError as e:
logger.error(f"Connection failed: {e}")
raise ServiceUnavailable("DB unreachable") from e
# OK — .get() without a default
value = config.get("timeout")
# OK — or in a condition, not an assignment
if user_name or fallback_name:
greet()
// NG — silent defaults
const port = config.port ?? 3000;
const name = input || "default";
options.timeout ||= 5000;
cache ??= new Map();
// NG — swallowed errors
try { await fetch(url); } catch (e) { return []; }
try { parse(json); } catch {}
fetch(url).catch(() => null);
// OK — exception handled properly
try {
await fetch(url);
} catch (e) {
logger.error(e);
throw new FetchError("request failed", { cause: e });
}
// OK — catch with re-throw
promise.catch((e) => { throw new AppError(e); });
Intentional fallbacks can be approved with an adjacent comment:
# policy-approved: REQ-123 explicit locale default
lang = payload.get("lang", "ja-JP")
// policy-approved: ADR-7 demo-mode fallback
const label = apiValue ?? "demo";
Accepted prefixes: REQ-, ADR-, SPEC- followed by an identifier.
| Trigger | Behavior |
|---|---|
| PostToolUse hook | Scans the changed file after every Edit / Write. Warns Claude on violations |
/scan command | Full project scan on demand |
17 rules (9 Python + 8 TypeScript), validated against 34+ test fixtures.
The hot path uses a Rust engine, and full-tree scans use ripgrep to prefilter candidate files before invoking ast-grep.
Test paths (**/test/**, **/tests/**, **/*_test.py, *.test.ts, etc.) are excluded from all rules.
Claude Code marketplace entries for the plugin-safe Antigravity Awesome Skills library and its compatible editorial bundles.
Production-ready workflow orchestration with 84 marketplace plugins, 192 local specialized agents, and 156 local skills - optimized for granular installation and minimal token usage
Directory of popular Claude Code extensions including development tools, productivity plugins, and MCP integrations