Stop Claude Code and Codex from making the same expensive mistakes twice.
Chinese Docs · Rule Reference · Contributing
VibeGuard adds native rules + real-time hooks + static guards to catch what AI coding agents get wrong — before it reaches your codebase:
- Duplicate files and reinvented modules
- Invented APIs, fake libraries, and hardcoded placeholder values
- Dangerous shell/git operations (
rm -rfdangerous paths,git clean -f, non-fast-forward pushes) - Audited cleanup for intentional local discards, with exact path plans and confirmation gates
- Analysis paralysis and unverified "I'm done" claims
- Silent exception swallowing and
Any-type abuse - AI-slop patterns flagged on every commit
Works with Claude Code and Codex CLI.
git clone https://github.com/majiayu000/vibeguard.git ~/vibeguard
bash ~/vibeguard/setup.shRequires Python 3. On supported macOS/Linux targets, setup downloads a
prebuilt vibeguard-runtime release binary and verifies it with SHA256SUMS,
so Rust/Cargo is not required by default.
Open a new Claude Code or Codex session. Run bash ~/vibeguard/setup.sh --check to verify.
The current mainline is install-verified on macOS and CI-verified on Ubuntu, macOS, and Windows.
- Latest release train:
v1.1.x - Local health gate:
bash setup.sh --check --strict - Expected verdict after a healthy install:
HEALTHY - Claude Code: native rules, skills, commands, hooks, and git hooks are installed by
setup.sh; scheduled GC is opt-in with--with-scheduler - Codex CLI:
~/.codex/AGENTS.md, copied skills, native Bash/apply_patch/PermissionRequest/PostToolUse/Stop hooks, and~/.vibeguard/run-hook-codex.share installed bysetup.sh - Known Codex boundary: Read/Glob/Grep native hooks are not currently available through Codex, so read-only exploration gates remain Claude Code or app-server-wrapper only
Latest benchmark gate: hook latency is tracked through CI's Hook Latency (P95) report. Lower is better; the latest mainline run stayed below the regression threshold and improved the hot-path P95 samples versus the previous main commit.
| Layer | What it does |
|---|---|
| Native Rules | Bias the model away from bad decisions before it acts |
| Hooks | Block dangerous or low-quality actions in real time |
| Static Guards | Scan projects for AI-slop, duplicates, and structural issues |
| Slash Commands | /vibeguard:* workflows for preflight / review / check / learn |
| Learning System | Turn repeated AI mistakes into reusable defenses |
| Observability | Metrics and health for every interception |
VibeGuard has two layers:
| Surface | Scope | Canonical Source |
|---|---|---|
| VibeGuard Core | Rules, hooks, static guards, install/runtime contract, observability | rules/claude-rules/, schemas/install-modules.json, hooks/, guards/ |
| VibeGuard Workflows | Slash commands, agent prompts, planning/execution presets | skills/, workflows/, agents/ |
If these surfaces disagree, treat the Core contract as authoritative first, then update workflow/docs surfaces to match it.
For repository layout ownership, see Directory Map.
Real Codex hook output:
You: "Add a login endpoint"
AI: → tries to create auth_service.py
✗ VibeGuard blocks — duplicate of existing auth.py, search first
→ tries to import `flask-auth-magic`
✗ VibeGuard blocks — non-existent library, verify before adding
→ hardcodes JWT secret as "your-secret-key"
✗ VibeGuard flags — use env var or secret manager
→ runs `git push --force`
✗ VibeGuard git pre-push hook denies — history rewrites require explicit human approval
→ runs `git clean -fd`
✗ VibeGuard denies — points to an authorized discard workflow with an exact deletion plan
→ keeps reading files without acting
⚠ VibeGuard escalates — force a concrete next step or report blocker
→ claims done without verifying
⚠ VibeGuard gates — run build/test before finishing
Every interception returns a fix instruction, not just a failure — so the agent can self-correct.
Re-record your own demo: see docs/assets/README.md (one command via asciinema + agg).
Use VibeGuard if you:
- Use Claude Code or Codex regularly
- Have seen duplicate files, fake APIs, over-engineering, or unverified "done" claims
- Want mechanical enforcement, not just prompt guidelines
It may be overkill if you only use AI occasionally or don't want hook-level interception.
Inspired by OpenAI Harness Engineering and Stripe Minions. Fully implements all 5 Harness Golden Principles.
The native rule set in rules/claude-rules/ is installed to Claude Code's native rules system (~/.claude/rules/vibeguard/), directly influencing AI reasoning. Plus a 7-layer constraint index injected into ~/.claude/CLAUDE.md:
| Layer | Constraint | Effect |
|---|---|---|
| L1 | Search before create | Must search for existing implementations before creating new files |
| L2 | Naming conventions | snake_case internally, camelCase at API boundaries, no aliases |
| L3 | Quality baseline | No silent exception swallowing, no Any types in public methods |
| L4 | Data integrity | No data = show blank, no hardcoding, no inventing APIs |
| L5 | Minimal changes | Only do what was asked, no unsolicited "improvements" |
| L6 | Process gates | Large changes require preflight, structured planning, and verification |
| L7 | Commit discipline | No AI markers, no force push, no secrets |
Rules use negative constraints ("X does not exist") to implicitly guide AI, which is often more effective than positive descriptions.
Canonical references for this contract:
- Install/runtime contract:
schemas/install-modules.json - Native rule source:
rules/claude-rules/ - Public summary of current rule surface:
docs/rule-reference.md
Most hooks trigger automatically during AI operations. skills-loader remains an optional manual hook. Codex deploys native Bash/apply_patch/PermissionRequest/PostToolUse/Stop hooks; read-only exploration hooks remain Claude Code or app-server-wrapper only:
| Scenario | Hook | Result |
|---|---|---|
AI creates new .py/.ts/.rs/.go/.js file |
pre-write-guard |
Warn by default — search-first reminder; set VIBEGUARD_WRITE_MODE=block or write_mode=block in ~/.vibeguard/config.json to hard-block |
| AI creates or edits production source above 400 lines | pre-write-guard, pre-edit-guard, post-write-guard, post-edit-guard |
Warn — typical-size advisory; keep the current change localized and plan a later split if growth continues |
| AI creates or edits production source above 800 lines | pre-write-guard, pre-edit-guard |
Block — split the file before writing or patching |
AI runs destructive local cleanup (rm -rf dangerous paths, git clean -f, git checkout/restore .) |
pre-bash-guard |
Block — suggests safe alternatives and audited discard flow |
| AI pushes a non-fast-forward update or branch deletion | git pre-push |
Block — protects remote history; rewrites and deletions require explicit human approval plus the repository bypass policy |
| AI edits non-existent file | pre-edit-guard |
Block — must Read file first |
AI adds unwrap(), hardcoded paths |
post-edit-guard |
Warn — with fix instructions |
AI adds console.log / print() debug statements |
post-edit-guard |
Warn — use logger instead |
| AI creates duplicate definitions after a new file write | post-write-guard |
Warn — detect duplicate symbols and same-name files |
| AI keeps reading/searching without acting | analysis-paralysis-guard |
Escalate — force a concrete next step or blocker report |
AI edits code in full / strict profile |
post-build-check |
Warn — run language-appropriate build check |
git commit |
pre-commit-guard |
Block — quality + build checks (staged files only), 10s timeout |
| AI tries to finish with unverified changes | stop-guard |
Signal — logs a Stop reminder; the Stop hook exits 0 to avoid feedback loops |
| Session ends | learn-evaluator |
Evaluate — collect metrics and detect correction signals |
U-16 file-size enforcement applies to non-test source files with .rs, .ts, .tsx, .js, .jsx, .py, or .go extensions. The default typical-size advisory starts above 400 lines (u16.warn_limit in ~/.vibeguard/config.json / VG_U16_WARN_LIMIT), while the hard limit remains 800 lines (u16.limit in ~/.vibeguard/config.json / VG_U16_LIMIT). For Codex, apply_patch Add File and apply_patch Update File are both normalized before the file hook runs, so edits that would take a production source file past the hard limit are denied before mutation.
Representative standalone checks you can run on any project. The complete inventory lives in docs/rule-reference.md.
# Universal
bash ~/vibeguard/guards/universal/check_code_slop.sh /path/to/project # AI code slop
python3 ~/vibeguard/guards/universal/check_dependency_layers.py /path # dependency direction
python3 ~/vibeguard/guards/universal/check_circular_deps.py /path # circular deps
bash ~/vibeguard/guards/universal/check_test_integrity.sh /path # test shadowing / integrity issues
bash ~/vibeguard/guards/universal/check_dependency_changes.sh --base origin/main --head HEAD # SEC-11 dependency review
bash ~/vibeguard/guards/universal/check_test_weakening.sh --base origin/main --head HEAD # SEC-11/W-12 test weakening
# Rust
bash ~/vibeguard/guards/rust/check_unwrap_in_prod.sh /path # unwrap/expect in prod
bash ~/vibeguard/guards/rust/check_nested_locks.sh /path # deadlock risk
bash ~/vibeguard/guards/rust/check_declaration_execution_gap.sh /path # declared but not wired
bash ~/vibeguard/guards/rust/check_duplicate_types.sh /path # duplicate type definitions
bash ~/vibeguard/guards/rust/check_semantic_effect.sh /path # semantic side effects
bash ~/vibeguard/guards/rust/check_single_source_of_truth.sh /path # single source of truth
bash ~/vibeguard/guards/rust/check_taste_invariants.sh /path # taste/style invariants
bash ~/vibeguard/guards/rust/check_workspace_consistency.sh /path # workspace dep consistency
# Go
bash ~/vibeguard/guards/go/check_error_handling.sh /path # unchecked errors
bash ~/vibeguard/guards/go/check_goroutine_leak.sh /path # goroutine leaks
bash ~/vibeguard/guards/go/check_defer_in_loop.sh /path # defer in loop
# TypeScript
bash ~/vibeguard/guards/typescript/check_any_abuse.sh /path # any type abuse
bash ~/vibeguard/guards/typescript/check_console_residual.sh /path # console.log residue
bash ~/vibeguard/guards/typescript/check_component_duplication.sh /path # duplicated component files
bash ~/vibeguard/guards/typescript/check_duplicate_constants.sh /path # repeated constant definitions
# Python
python3 ~/vibeguard/guards/python/check_duplicates.py /path # duplicate functions/classes/protocols
python3 ~/vibeguard/guards/python/check_naming_convention.py /path # camelCase mix
python3 ~/vibeguard/guards/python/check_dead_shims.py /path # dead re-export shims12 custom commands covering the full development lifecycle. Shortcuts: /vg:pf /vg:gc /vg:ck /vg:lrn.
| Command | Purpose |
|---|---|
/vibeguard:preflight |
Generate constraint set before changes |
/vibeguard:check |
Full guard scan + compliance report |
/vibeguard:review |
Structured code review (security → logic → quality → perf) |
/vibeguard:cross-review |
Dual-model adversarial review (Claude + Codex) |
/vibeguard:build-fix |
Build error resolution |
/vibeguard:learn |
Generate guard rules from errors / extract Skills from discoveries |
/vibeguard:skill-validate |
Gate proposed skills with required format sections and repair/regression evidence before acceptance |
/vibeguard:interview |
Deep requirements interview → SPEC.md |
/vibeguard:exec-plan |
Long-running task execution plan, cross-session resume |
/vibeguard:live-truth |
Fresh evidence gates for latest, PR-ready, merged, running, deployed, and published claims |
/vibeguard:gc |
Garbage collection (logs + worktrees + rule budget + code slop scan) |
/vibeguard:stats |
Hook trigger statistics |
Routing Contract
Workflow routing is defined once in workflows/references/routing-contract.md.
- Precedence:
user_override→risk/destructive gate→ambiguity gate→readiness classifier→execution/delegation lane - Readiness outputs:
execute_direct,plan_first,clarify_first - Planning surfaces emit the shared handoff fields:
mode,artifacts,runtime_pinning_snapshot,verification_owner,stop_conditions,lane_map - Delegated multi-agent work uses workflows/references/delegation-contract.md for child-agent assignments, parallelism limits, and single-owner reintegration
Use workflow prompts and dispatcher guidance as consumers of that contract, not as independent routing sources.
14 built-in agent prompts (13 specialists + 1 dispatcher) with automatic routing:
| Agent | Purpose |
|---|---|
dispatcher |
Auto-route — analyzes task type and routes to the best agent |
planner / architect |
Requirements analysis and system design |
tdd-guide |
RED → GREEN → IMPROVE test-driven development |
code-reviewer / security-reviewer |
Layered code review and OWASP Top 10 |
build-error-resolver |
Build error diagnosis and fix |
go-reviewer / python-reviewer / database-reviewer |
Language-specific review |
refactor-cleaner / doc-updater / e2e-runner |
Refactoring, docs, and E2E tests |
bash ~/vibeguard/scripts/quality-grader.sh # Quality grade (A/B/C/D)
bash ~/vibeguard/scripts/stats.sh # Project hook trigger stats (7 days)
bash ~/vibeguard/scripts/hook-health.sh 24 # Project hook health snapshot
bash ~/vibeguard/scripts/stats.sh --scope global # Global hook trigger stats
bash ~/vibeguard/scripts/doctors/codex-doctor.sh # Codex install + hook capability diagnosis
bash ~/vibeguard/scripts/metrics/metrics-exporter.sh # Prometheus metrics export
bash ~/vibeguard/scripts/verify/doc-freshness-check.sh # Rule-guard coverage checkDoctors are read-only diagnosis wrappers over the existing defense system. They summarize installation state, capability gaps, noisy hooks, recent events, and repair commands; hooks and guards remain the enforcement layer that blocks or warns during real tool execution.
Hook latency is also a product contract. See Hook Latency Contract for per-hook P95 budgets, hotspot attribution, and the static gates that block expensive hook patterns.
The local observability contract is documented in Observability Harness Contract, including project/global scope, metric labels, and the external-stack roadmap.
VibeGuard guards its own behavior — the test suite and eval harness ship in the repo, not as an afterthought.
- Behavior eval (CI-blocking): a zero-cost gate that runs the real guard hooks end-to-end and asserts the actual block/deny decision on both the Claude Code hook and the Codex wrapper. Enforced in CI at a 100% pass / 100% coverage threshold — removing a required platform slice fails the build (
eval/run_behavior_eval.py). - Rule-detection benchmark: a 40-sample, schema-validated, digest-pinned dataset (planted rule violations across SEC / Python / TypeScript / Go / Rust / universal rules, plus clean controls) scored on detection rate, a severity-weighted score, and per-severity Expected Calibration Error (ECE) — calibration, not just accuracy. Run manually with
python3 eval/run_eval.py(uses the Claude API; not a merge gate). - Test suite: ~40 hook/guard test scripts under
tests/and 100+ unit tests in the Rustvibeguard-runtimecrate. CI runs on Linux, macOS, and Windows.
Closed-loop learning evolves defenses from mistakes:
Mode A — Defensive
/vibeguard:learn <error description>
Analyzes root cause (5-Why) → generates a new guard/hook/rule → verifies detection → the same class of error should not recur.
Mode B — Accumulative
/vibeguard:learn extract
Extracts non-obvious solutions as structured Skill files for future reuse.
Default setup downloads and verifies the pinned vibeguard-runtime release for
supported platforms. Source builds remain available for unsupported/offline
installs and for users who explicitly request them.
| Platform | Default runtime path | Rust/Cargo needed? |
|---|---|---|
macOS arm64 (aarch64-apple-darwin) |
Prebuilt release binary | No |
macOS x86_64 (x86_64-apple-darwin) |
Prebuilt release binary | No |
Linux x86_64 (x86_64-unknown-linux-musl) |
Prebuilt release binary | No |
Linux arm64 (aarch64-unknown-linux-musl) |
Prebuilt release binary | No |
Other targets, offline installs, or --build-from-source |
Local source build | Yes |
setup.sh uses gh release download when gh is available, otherwise curl.
If a supported-target download fails, it falls back to cargo build when Cargo
is available. Checksum mismatch or a missing checksum entry is fatal and does
not fall back to source.
# Profiles
bash ~/vibeguard/setup.sh # Install (default: core profile)
bash ~/vibeguard/setup.sh --profile minimal # Minimal: pre-hooks only (lightweight)
bash ~/vibeguard/setup.sh --profile full # Full: adds Stop signal + Build Check + learning
bash ~/vibeguard/setup.sh --profile strict # Strict: full hooks + Claude Code U-32 SessionStart constraint budget
# Language selection (only install rules/guards for specified languages)
bash ~/vibeguard/setup.sh --languages rust,python
bash ~/vibeguard/setup.sh --profile full --languages rust,typescript
# Runtime / scheduler
bash ~/vibeguard/setup.sh --build-from-source # Force local Cargo build
bash ~/vibeguard/setup.sh --with-scheduler # Opt in to launchd/systemd scheduled GC
# Verify / Uninstall
bash ~/vibeguard/setup.sh --check # Verify installation
bash ~/vibeguard/setup.sh --check --quiet # Show only problems + rollup
bash ~/vibeguard/setup.sh --check --json # Machine-readable JSON for CI
bash ~/vibeguard/setup.sh --check --strict # Exit 1/2 on warn/broken
bash ~/vibeguard/setup.sh --clean # Uninstall--check reports a structured rollup (OK / INFO / WARN / FAIL / BROKEN / MISSING)
plus a final Verdict line of HEALTHY, DEGRADED, or BROKEN. The default mode
always exits 0 for backwards compatibility — add --strict (or use --json,
which implies it) to make CI fail when the install is broken.
| Profile | Hooks Installed | Use Case |
|---|---|---|
minimal |
pre-write, pre-edit, pre-bash | Lightweight — only critical interception |
core (default) |
minimal + post-edit, post-write, analysis-paralysis | Standard development |
full |
core + stop-guard, learn-evaluator, post-build-check | Full defense + learning |
strict |
full + Claude Code count-active-constraints (SessionStart/U-32); Codex native hooks remain full | Maximum enforcement |
setup.sh also prepares the shared pre-commit wrapper at ~/.vibeguard/pre-commit and installs this repository's git pre-commit and pre-push hooks during setup. The git pre-push hook owns force-push / branch-deletion protection; pre-bash-guard does not regex-match git push --force. To attach the wrapper to another repository, use scripts/project-init.sh or that repository's own install step.
VibeGuard deploys hooks and skills to both Claude Code and Codex CLI.
Hooks live in ~/.codex/hooks.json (requires [features].hooks = true in config.toml):
| Event | Hook | Function |
|---|---|---|
PreToolUse(Bash) |
pre-bash-guard.sh |
Destructive local cleanup interception + package manager correction |
PermissionRequest(Bash) |
pre-bash-guard.sh |
Fail-closed approval gate for dangerous commands |
PreToolUse(Edit/Write via apply_patch) |
pre-edit-guard.sh, pre-write-guard.sh |
File existence and search-first gates before patching |
PermissionRequest(Edit/Write via apply_patch) |
pre-edit-guard.sh, pre-write-guard.sh |
Fail-closed approval gate before privileged patching |
PostToolUse(Bash/apply_patch) |
post-build-check.sh |
Build failure detection after commands or patches |
PostToolUse(Edit/Write via apply_patch) |
post-edit-guard.sh, post-write-guard.sh |
Post-patch quality and duplicate checks |
Stop |
stop-guard.sh |
Uncommitted changes signal (logs a gate event, non-blocking Stop) |
Stop |
learn-evaluator.sh |
Session metrics collection |
This is the default enforcement layer. It talks to Codex through native hooks
and does not wrap or replace the Codex server. Codex has no native Read,
Glob, or Grep hook surface, so analysis-paralysis is not available on
the native Codex path. Use Claude Code when read-only exploration gating is
required; the optional app-server wrapper is only for external orchestrators
that already require codex app-server.
Codex hook command names are namespaced as vibeguard-*.sh to avoid collisions with other toolchains sharing ~/.codex/hooks.json. Output format differences are handled by the run-hook-codex.sh wrapper (Claude Code decision:block -> Codex deny payloads). Codex sends apply_patch as a patch command, so the wrapper normalizes that payload into Edit/Write-shaped inputs before calling the existing VibeGuard file hooks. For Update File patches, the wrapper also passes the line delta so pre-edit-guard.sh can enforce U-16 before Codex mutates the file. When a hook suggests updatedInput, the Codex CLI wrapper cannot apply it automatically, so VibeGuard emits an explicit note with the suggested replacement command instead of silently dropping it.
Hook status is a separate human diagnostics surface. Use vibeguard-runtime hook-status --mode focused inside a git repository to inspect the matching project log, or add --scope global for ~/.vibeguard/events.jsonl. --log-file PATH always wins for explicit fixtures or one-off diagnosis. The command reports recent pass, skipped, slow, timeout, and adapter-error states without adding successful hook summaries to the model context. Only actionable warn / block results should continue through hookSpecificOutput.additionalContext. See docs/reference/codex-hook-status.md.
MCP server status: the legacy mcp-server/ prototype is not installed by setup.sh and is not part of the supported runtime surface. Supported integrations are the Claude Code hooks, native Codex hooks, and the optional app-server wrapper below; any future MCP reintroduction must go through an explicit install path and hash/audit baseline.
Optional app-server wrapper (advanced orchestrators only):
Most local Codex setups do not need this path. It is not the default
protection layer; use native Codex hooks in ~/.codex/hooks.json for local
protection.
~/.vibeguard/installed/bin/vibeguard-runtime codex-app-server-wrapper --repo-dir ~/vibeguard --codex-command "codex app-server"--strategy vibeguard(default): applies strategy-based command, file-change, analysis-loop, and post-turn gates externally--strategy noop: pure pass-through for debugging- Runtime: Rust-only via
vibeguard-runtime; there is no Python app-server wrapper fallback. - App-server wrapper is optional and mainly for external orchestrators that already speak
codex app-server - App-server wrapper scope today: Bash approval interception;
applyPatchApproval/item/fileChange/requestApprovalfile-change guards mapped topre-edit,pre-write,post-edit, andpost-write; proxy-nativeanalysis-paralysiswarnings for read-only command streaks; post-turn stop/build feedback with explicitthread/session/turnpropagation. - Guard mode:
VIBEGUARD_CODEX_GUARD_MODE=guardedby default.decline/deniedtells Codex to continue the turn with a warning;strictupgrades file changes tocancel/abort;advisoryemits warnings without blocking. - Default local protection should use native Codex hooks in
~/.codex/hooks.json - Still unsupported on native Codex path:
Read/Glob/Grephooks such asanalysis-paralysis
| Tool | How |
|---|---|
| OpenAI Codex | cp ~/vibeguard/templates/AGENTS.md ./AGENTS.md + bash ~/vibeguard/setup.sh (installs skills + Codex hooks) |
| Any project (rules only) | cp ~/vibeguard/docs/CLAUDE.md.example ./CLAUDE.md |
Bootstrap another repository with project-specific guidance and the pre-commit wrapper:
bash ~/vibeguard/scripts/project-init.sh /path/to/projectRun stable contract checks locally before pushing, or wire them as a pre-commit hook:
bash scripts/local-contract-check.sh # run the full local gate
bash scripts/install-pre-commit-hook.sh # install as git pre-commit hookSee CONTRIBUTING.md for the local-vs-CI split and the --quick flag.
Add your own rules to ~/.vibeguard/user-rules/. Any .md files placed there are automatically installed to ~/.claude/rules/vibeguard/custom/ on the next setup run. Format: standard Claude Code rule files with YAML frontmatter.
| Principle | From | Implementation |
|---|---|---|
| Automation over documentation | Harness #3 | Mechanized checks complement rules, workflows, and review |
| Error messages = fix instructions | Harness #3 | Every interception tells AI how to fix, not just what's wrong |
| Maps not manuals | Harness #5 | 7-layer index + negative constraints + lazy loading |
| Failure → capability | Harness #2 | Mistake → learn → new guard → never again |
| If agent can't see it, it doesn't exist | Harness #1 | All decisions written to repo (CLAUDE.md / ExecPlan / logs) |
| Give agent eyes | Harness #4 | Observability stack (logs + metrics + alerts) |
Guard scripts rely heavily on pattern matching (grep/awk or lightweight AST helpers), which means false positives can still happen in some scenarios.
- Known False Positives — identified false positive scenarios, fixes, and lessons learned
Key lessons:
- grep is not an AST parser — nested scopes and multi-block structures need language-aware tools
- Guard fix messages are consumed by AI agents — an imprecise fix hint can itself trigger unnecessary edits
- Project type awareness matters — CLI/Web/MCP/Library codebases may need different acceptable patterns for the same language rule
| Doc | Purpose |
|---|---|
| docs/README_CN.md | Chinese overview and setup guide |
| docs/rule-reference.md | Rule layers, guard coverage, and language-specific checks |
| docs/CLAUDE.md.example | Project-level CLAUDE template without installing hooks |
| docs/linux-setup.md | Linux-specific setup notes |
| docs/known-issues/false-positives.md | Known guard false positives and mitigation notes |
| docs/assets/README.md | Demo recording script and assets |
| CONTRIBUTING.md | Contributor workflow, validation commands, and commit protocol |


