{"owner":"Dicklesworthstone","repo":"destructive_command_guard","hasSkills":true,"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md"],"skills":{"AGENTS.md":"# AGENTS.md — dcg (Destructive Command Guard)\n\n> Guidelines for AI coding agents working in this Rust codebase.\n\n---\n\n## RULE 0 - THE FUNDAMENTAL OVERRIDE PREROGATIVE\n\nIf I tell you to do something, even if it goes against what follows below, YOU MUST LISTEN TO ME. I AM IN CHARGE, NOT YOU.\n\n---\n\n## RULE NUMBER 1: NO FILE DELETION\n\n**YOU ARE NEVER ALLOWED TO DELETE A FILE WITHOUT EXPRESS PERMISSION.** Even a new file that you yourself created, such as a test code file. You have a horrible track record of deleting critically important files or otherwise throwing away tons of expensive work. As a result, you have permanently lost any and all rights to determine that a file or folder should be deleted.\n\n**YOU MUST ALWAYS ASK AND RECEIVE CLEAR, WRITTEN PERMISSION BEFORE EVER DELETING A FILE OR FOLDER OF ANY KIND.**\n\n---\n\n## Irreversible Git & Filesystem Actions — DO NOT EVER BREAK GLASS\n\n> **Note:** This project exists specifically to block these dangerous commands for AI agents. Practice what we preach.\n\n1. **Absolutely forbidden commands:** `git reset --hard`, `git clean -fd`, `rm -rf`, or any command that can delete or overwrite code/data must never be run unless the user explicitly provides the exact command and states, in the same message, that they understand and want the irreversible consequences.\n2. **No guessing:** If there is any uncertainty about what a command might delete or overwrite, stop immediately and ask the user for specific approval. \"I think it's safe\" is never acceptable.\n3. **Safer alternatives first:** When cleanup or rollbacks are needed, request permission to use non-destructive options (`git status`, `git diff`, `git stash`, copying to backups) before ever considering a destructive command.\n4. **Mandatory explicit plan:** Even after explicit user authorization, restate the command verbatim, list exactly what will be affected, and wait for a confirmation that your understanding is correct. Only then may you execute it—if anything remains ambiguous, refuse and escalate.\n5. **Document the confirmation:** When running any approved destructive command, record (in the session notes / final response) the exact user text that authorized it, the command actually run, and the execution time. If that record is absent, the operation did not happen.\n\n---\n\n## Git Branch: ONLY Use `main`, NEVER `master`\n\n**The default branch is `main`. The `master` branch exists only for legacy URL compatibility.**\n\n- **All work happens on `main`** — commits, PRs, feature branches all merge to `main`\n- **Never reference `master` in code or docs** — if you see `master` anywhere, it's a bug that needs fixing\n- **The `master` branch must stay synchronized with `main`** — after pushing to `main`, also push to `master`:\n  ```bash\n  git push origin main:master\n  ```\n\n**Why this matters:** The `dcg update` command and install URLs historically referenced `master`. If `master` falls behind `main`, users get stale code. We had a bug where `master` was **497 commits behind**, causing users to see old installer behavior.\n\n**If you see `master` referenced anywhere:**\n1. Update it to `main`\n2. Ensure `master` is synchronized: `git push origin main:master`\n\n---\n\n## Toolchain: Rust & Cargo\n\nWe only use **Cargo** in this project, NEVER any other package manager.\n\n- **Edition:** Rust 2024 (nightly required — see `rust-toolchain.toml`)\n- **Dependency versions:** Explicit versions for stability\n- **Configuration:** Cargo.toml only (single crate, not a workspace)\n- **Unsafe code:** Forbidden (`#![forbid(unsafe_code)]`)\n\n### Key Dependencies\n\n| Crate | Purpose |\n|-------|---------|\n| `serde` + `serde_json` | JSON parsing for Claude Code hook protocol |\n| `serde_yaml` | External pack YAML parsing |\n| `toml` + `toml_edit` | TOML config parsing with formatting preservation |\n| `fancy-regex` | Advanced regex with lookahead/lookbehind |\n| `regex` | `RegexSet` for heredoc detection |\n| `memchr` | SIMD-accelerated substring search |\n| `aho-corasick` | Multi-pattern string matching for keyword quick-reject |\n| `colored` | Terminal colors with TTY detection |\n| `clap` + `clap_complete` | CLI argument parsing with shell completions |\n| `chrono` | RFC 3339 timestamps |\n| `ast-grep-core` + `ast-grep-language` | AST-based pattern matching for heredoc/inline-script content |\n| `rusqlite` | Bundled upstream SQLite for best-effort telemetry history |\n| `rust-mcp-sdk` | MCP server integration (stdio transport) |\n| `tokio` | Async runtime for MCP server mode |\n| `ratatui` + `comfy-table` + `indicatif` + `console` | TUI/CLI visual polish |\n| `self_update` | Binary self-update from GitHub Releases |\n| `vergen-gix` | Build metadata embedding (build.rs) |\n| `tracing` + `tracing-subscriber` | Structured logging and diagnostics |\n| `sha2` + `hmac` | Hashing and HMAC for allow-once short codes |\n| `flate2` | Gzip compression for history export |\n\n### Release Profile\n\nThe release build optimizes for binary size:\n\n```toml\n[profile.release]\nopt-level = \"z\"     # Optimize for size (lean binary for distribution)\nlto = true          # Link-time optimization\ncodegen-units = 1   # Single codegen unit for better optimization\npanic = \"abort\"     # Smaller binary, no unwinding overhead\nstrip = true        # Remove debug symbols\n```\n\n### Feature Flags\n\n```toml\n[features]\nrayon = [\"dep:rayon\"]           # Rayon data parallelism (optional)\nrich-output = [\"dep:rich_rust\"] # Enable rich_rust for premium terminal output\nlegacy-output = []              # Keep old rendering (placeholder for gradual migration)\n```\n\n---\n\n## Code Editing Discipline\n\n### No Script-Based Changes\n\n**NEVER** run a script that processes/changes code files in this repo. Brittle regex-based transformations create far more problems than they solve.\n\n- **Always make code changes manually**, even when there are many instances\n- For many simple changes: use parallel subagents\n- For subtle/complex changes: do them methodically yourself\n\n### No File Proliferation\n\nIf you want to change something or add a feature, **revise existing code files in place**.\n\n**NEVER** create variations like:\n- `mainV2.rs`\n- `main_improved.rs`\n- `main_enhanced.rs`\n\nNew files are reserved for **genuinely new functionality** that makes zero sense to include in any existing file. The bar for creating new files is **incredibly high**.\n\n---\n\n## Backwards Compatibility\n\nWe do not care about backwards compatibility—we're in early development with no users. We want to do things the **RIGHT** way with **NO TECH DEBT**.\n\n- Never create \"compatibility shims\"\n- Never create wrapper functions for deprecated APIs\n- Just fix the code directly\n\n---\n\n## Compiler Checks (CRITICAL)\n\n**After any substantive code changes, you MUST verify no errors were introduced:**\n\n```bash\n# Check for compiler errors and warnings\ncargo check --all-targets\n\n# Check for clippy lints (pedantic + nursery are enabled)\ncargo clippy --all-targets -- -D warnings\n\n# Verify formatting\ncargo fmt --check\n```\n\nIf you see errors, **carefully understand and resolve each issue**. Read sufficient context to fix them the RIGHT way.\n\n---\n\n## Windows Support (native, `x86_64-pc-windows-msvc`)\n\ndcg ships a **native Windows** binary (built/tested on `windows-latest` with the\nnightly toolchain) and a `check (windows)` CI job. When touching anything\nplatform-sensitive, follow these conventions:\n\n- **Separate command-pattern DATA from dcg's own paths.** Destructive-command\n  patterns (`rm -rf /`, `normalize.rs` stripping `/usr/bin/git`, `/etc`, `/tmp`)\n  are DATA about Unix commands and must STAY — Windows users still run git-bash.\n  Only dcg's *own* config/state paths get Windows-ified (resolve via the `dirs`\n  crate; the system layer is `%ProgramData%\\dcg`, helper `config::system_config_dir()`).\n- **`.exe` suffix.** When constructing a path to the dcg binary, use\n  `env!(\"CARGO_BIN_EXE_dcg\")` / `assert_cmd::cargo::cargo_bin(\"dcg\")` in tests, or\n  `std::env::consts::EXE_SUFFIX` in `src`. **Never** a bare `push(\"dcg\")` — the\n  Windows CI job greps for it and fails. Use `dirs::home_dir()` (not `HOME`,\n  which is unset on Windows) and set `USERPROFILE`/`TEMP`/`TMP` alongside `HOME`\n  in test isolation.\n- **Verify Windows branches from Linux** without a Windows box: `mingw` + the\n  `x86_64-pc-windows-gnu` target are installed, so\n  `cargo check --target x86_64-pc-windows-gnu --lib` (or `--bin dcg` / `--tests`)\n  compile-checks every `#[cfg(windows)]` path. When `pwsh` is installed, use it\n  to run the PowerShell installer/test scripts; otherwise run those gates on the\n  native Windows release host.\n- **Windows packs.** `src/packs/windows/` holds the native-Windows packs\n  (`windows.filesystem`/`windows.system` default-ON on Windows, `windows.misc`/\n  `windows.powershell` opt-in). Patterns use inline `(?i)`; keyword arrays\n  may retain conventional casing variants for readability, but keyword\n  quick-rejection is ASCII case-insensitive so mixed-case Windows spellings\n  cannot skip the regex stage (see `src/packs/windows/mod.rs`). See\n  [`docs/windows.md`](docs/windows.md).\n- **The `careful_company_running_windows` preset.**\n  `src/packs/careful_company_running_windows/` holds six opt-in sub-packs\n  covering **outbound communication and data egress** (email, chat/webhooks,\n  HTTP upload, file transfer, tunnels) plus **tampering with the controls that\n  supervise the agent** (Defender/firewall/EDR, audit logs, and dcg's own\n  bypass/uninstall). It is the only pack ID with *curated transitive\n  membership*: enabling it also enables the pinned\n  `CAREFUL_COMPANY_PRESET_MEMBERS` list in `src/packs/mod.rs`\n  (`windows.*`, `database.*`, `storage.*`, `remote.*`, `backup.*`, `secrets.*`,\n  `cloud.*`). That list is deliberately explicit — do **not** convert it to\n  prefix matching, or future packs will join a security posture silently.\n  Two invariants to preserve when touching this area:\n  - **Tier order.** `windows.*` is tier 11 and the preset is tier 12, so\n    Windows packs keep claiming attribution for commands both match. Rule ids\n    (`pack_id:pattern_name`) are what allowlists key on, so reordering these\n    silently invalidates existing `windows.*` allowlist entries.\n  - **The `hfdt` trust boundary.** While any preset sub-pack is enabled,\n    `src/evaluator.rs` allows a command whose executable is `hfdt` **before any\n    pack runs** — including `core.*`. It is structural (whole-segment\n    executable match, no chains/redirection/substitution), but it does mean\n    enabling the preset *reduces* coverage for that one executable. Keep it\n    documented in `README.md` and `docs/careful-company-windows.md`.\n\n---\n\n## Testing\n\n### Testing Policy\n\nEvery module includes inline `#[cfg(test)]` unit tests alongside the implementation. Tests must cover:\n- Happy path\n- Edge cases (empty input, max values, boundary conditions)\n- Error conditions\n\nEnd-to-end tests live in `scripts/e2e_test.sh`.\n\n### Unit Tests\n\nThe test suite includes 80+ tests covering all functionality:\n\n```bash\n# Run all tests\ncargo test\n\n# Run with output\ncargo test -- --nocapture\n\n# Run specific test module\ncargo test normalize_command_tests\ncargo test safe_pattern_tests\ncargo test destructive_pattern_tests\n```\n\n### The Three Release-Blocking E2E Suites (read before touching perf or protocols)\n\n`cargo test` cannot catch the failure modes that have actually broken users.\nThree real-binary, no-mock suites exist specifically to close those gaps. All\nthree must be green before any release.\n\n| Suite | Catches | Why unit tests can't |\n|-------|---------|----------------------|\n| `scripts/e2e_harness_matrix.sh` | Wire-protocol breakage for **every** agent (Claude Code, Codex, Gemini, Copilot, Hermes, Grok, agy) | Unit tests call Rust functions; harnesses parse **bytes**. Asserts decision field + exit code + stdout/stderr separation per protocol against the real binary. |\n| `scripts/perf_baseline.py --assert-budget-ms` | **#245**: per-invocation cost silently eating the fixed hook deadline | The perf job is a *relative* ratchet — a uniform slowdown just gets re-baselined. This gate asserts cold p95 against the **shipped** `HOOK_EVALUATION_BUDGET_MS` with a hermetic HOME and scrubbed `DCG_*`. |\n| `scripts/e2e_fleet_install.sh` | Published artifact missing/unrunnable per platform; installer picking the wrong triple; checksum/signature verification silently skipped; hook config non-idempotent | Nothing in-tree proves the **public download path** works on real Linux/macOS/Windows hardware. |\n\n```bash\n# Protocol conformance for all 7 harnesses (needs a release binary + jq)\n./scripts/e2e_harness_matrix.sh --binary target/release/dcg\n\n# Absolute latency gate — the #245 guard. Budget MUST come from src/perf.rs.\npython3 scripts/perf_baseline.py --bin target/release/dcg --skip-trace \\\n  --assert-budget-ms 1000 --assert-margin-pct 50\n\n# Real installs from the PUBLIC release on every DSR host\n./scripts/e2e_fleet_install.sh --version vX.Y.Z          # whole fleet\n./scripts/e2e_fleet_install.sh --version vX.Y.Z --local-only\n```\n\nRules:\n- **Scrub ambient `DCG_*` before measuring anything.** Operators bitten by #245\n  export `DCG_HOOK_TIMEOUT_MS=5000` (an agent `settings.json` `env` block puts\n  it in every child process), so an un-scrubbed suite measures the *workaround*\n  and passes on exactly the machines that need protecting. `env -i` covers the\n  hook calls; the installer cannot use it (it needs the host PATH for\n  `curl`/`tar`/`xz`/`minisign`), so the probes also `unset` every `DCG_*` up\n  front. Assert `general.hook_timeout_source` too — a bare `>= 1000` check\n  cannot tell the shipped default from an inherited 5000.\n- **Set `DCG_SELF_HEAL_HOOK=0` before the installer runs, not after.** dcg\n  repairs a missing/stale hook entry whenever it runs in hook mode, and native\n  Windows resolves the settings path via the Win32 known-folder API, which\n  `USERPROFILE` cannot redirect — so a late disable can rewrite a real\n  machine's agent config.\n- **Never hard-code the budget in `.github/workflows/ci.yml`.** It is grepped\n  out of `HOOK_EVALUATION_BUDGET_MS`; `perf::tests::ci_enforces_absolute_latency_gate_against_shipped_budget`\n  fails if that wiring is removed or the margin is loosened past 60%.\n- Measure dcg's own cost as `full_eval − DCG_BYPASS`, never raw wall-clock:\n  process spawn (≈940ms under Windows PowerShell) sits **outside** the\n  evaluation deadline and would otherwise produce false alarms.\n- The fleet suite installs into a scratch prefix with an isolated `HOME` and\n  `--no-configure`; it never touches a host's real agent hook config.\n- A probe that dies partway must FAIL, not pass: every probe emits\n  `probe_complete` and the runner asserts the full expected case set.\n\n### End-to-End Testing\n\n```bash\n# Run the E2E test script (needs bash >= 4; macOS /bin/bash 3.2 breaks the summary)\n./scripts/e2e_test.sh\n\n# Or test manually\necho '{\"tool_name\":\"Bash\",\"tool_input\":{\"command\":\"git reset --hard\"}}' | cargo run --release\n# Should output JSON denial\n\necho '{\"tool_name\":\"Bash\",\"tool_input\":{\"command\":\"git status\"}}' | cargo run --release\n# Should output nothing (allowed)\n```\n\n### Test Categories\n\n| Module | Tests | Purpose |\n|--------|-------|---------|\n| `normalize_command_tests` | 8 | Path stripping for git/rm binaries |\n| `quick_reject_tests` | 5 | Fast-path filtering for non-git/rm commands |\n| `safe_pattern_tests` | 16 | Whitelist accuracy |\n| `destructive_pattern_tests` | 20 | Blacklist coverage |\n| `input_parsing_tests` | 8 | JSON parsing robustness |\n| `deny_output_tests` | 2 | Output format validation |\n| `integration_tests` | 4 | End-to-end pipeline |\n| `optimization_tests` | 9 | Performance paths |\n| `edge_case_tests` | 24 | Real-world edge cases |\n\n---\n\n## Third-Party Library Usage\n\nIf you aren't 100% sure how to use a third-party library, **SEARCH ONLINE** to find the latest documentation and current best practices.\n\n---\n\n## dcg (Destructive Command Guard) — This Project\n\n**This is the project you're working on.** dcg is a high-performance Claude Code hook that blocks destructive commands before they execute. It protects against dangerous git commands, filesystem operations, database queries, container commands, and more through a modular pack system.\n\n### What It Does\n\nGuards AI coding agents from executing destructive commands by intercepting Claude Code's `PreToolUse` hook protocol, evaluating commands against safe/destructive pattern lists, and denying dangerous operations with structured JSON output including remediation suggestions.\n\n### Architecture\n\n```\nJSON Input → Parse → Quick Reject (memchr) → Normalize → Safe Patterns → Destructive Patterns → Default Allow\n```\n\n### Key Files\n\n| File | Purpose |\n|------|---------|\n| `src/main.rs` | Entry point, hook I/O, CLI dispatch |\n| `src/evaluator.rs` | Pattern matching engine (safe + destructive evaluation) |\n| `src/hook.rs` | Claude Code PreToolUse hook protocol handling |\n| `src/normalize.rs` | Command normalization (path stripping, alias expansion) |\n| `src/heredoc.rs` | Heredoc and inline script extraction |\n| `src/ast_matcher.rs` | AST-based pattern matching for embedded code |\n| `src/config.rs` | Configuration loading (TOML, allowlists, pack enable/disable) |\n| `src/allowlist.rs` | Allowlist management (project, user, system scopes) |\n| `src/cli.rs` | CLI commands (explain, scan, packs, allowlist, etc.) |\n| `src/scan.rs` | Codebase scanning for destructive patterns |\n| `src/context.rs` | Contextual analysis for pattern matching |\n| `src/confidence.rs` | Match confidence scoring |\n| `src/error_codes.rs` | Standardized DCG-XXXX error codes |\n| `src/exit_codes.rs` | Process exit code definitions |\n| `src/packs/` | Modular pattern pack system (core + extensions) |\n| `src/output/` | Output formatting (JSON, colorful stderr) |\n| `src/highlight.rs` | Syntax highlighting for command display |\n| `src/logging.rs` | Tracing/logging configuration |\n| `src/perf.rs` | Performance budgets and benchmarks |\n| `src/simulate.rs` | Command simulation and dry-run support |\n| `src/mcp.rs` | MCP server integration |\n| `src/agent.rs` | Agent detection and identification |\n| `src/interactive.rs` | Interactive mode |\n| `src/git.rs` | Git-specific command analysis |\n| `src/history/` | Decision history and telemetry |\n| `src/sarif.rs` | SARIF output format for scan results |\n| `src/pending_exceptions.rs` | Pending exception management |\n| `src/lib.rs` | Library re-exports |\n| `Cargo.toml` | Dependencies and release optimizations |\n| `build.rs` | Build script for version metadata (vergen) |\n| `rust-toolchain.toml` | Nightly toolchain requirement |\n| `scripts/e2e_test.sh` | End-to-end test script (hundreds of command scenarios) |\n\n### Output Style\n\nThis tool has two output modes:\n\n- **JSON to stdout:** For Claude Code hook protocol (`hookSpecificOutput` with `permissionDecision: \"deny\"`)\n- **Colorful warning to stderr:** For human visibility when commands are blocked\n\nOutput behavior:\n- **Deny:** Colorful warning to stderr + JSON to stdout\n- **Allow:** No output (silent exit)\n- **--version/-V:** Version info with build metadata to stderr\n- **--help/-h:** Usage information to stderr\n\nColors are automatically disabled when stderr is not a TTY (e.g., piped to file).\n\n### Pattern System\n\n- **34 safe patterns** (whitelist, checked first)\n- **16 destructive patterns** (blacklist, checked second)\n- **Default allow** for unmatched commands\n\n### Adding New Patterns\n\n1. Identify the command to block/allow\n2. Write a regex using `fancy-regex` syntax (supports lookahead/lookbehind)\n3. Add to `SAFE_PATTERNS` or `DESTRUCTIVE_PATTERNS` using the macros:\n\n```rust\n// Safe pattern (whitelist)\npattern!(\"pattern-name\", r\"regex-here\")\n\n// Destructive pattern (blacklist)\ndestructive!(\n    r\"regex-here\",\n    \"Human-readable reason for blocking\"\n)\n```\n\n4. Add tests for all variants\n5. Run `cargo test` and `./scripts/e2e_test.sh`\n\n### Performance Requirements\n\nEvery Bash command passes through this hook. Performance is critical:\n\n- Quick rejection filter eliminates 99%+ of commands before regex\n- Lazy-initialized static regex patterns (compiled once, reused)\n- Sub-millisecond execution for typical commands\n- Zero allocations on the hot path for safe commands\n\n### Heredoc Detection Notes\n\n- **Rule IDs**: Heredoc patterns use stable IDs like `heredoc.python.shutil_rmtree` for allowlisting.\n- **Bounded failure**: Heredoc parse/AST failures use the configured bounded\n  fallback; disabling fallback blocks. Absolute hook-deadline exhaustion and\n  incomplete nested evaluation return `Indeterminate`, never `Allow`.\n- **Tests**: Prefer targeted tests in `src/ast_matcher.rs` and `src/heredoc.rs`.\n  - `cargo test ast_matcher`\n  - `cargo test heredoc`\n  - Add positive and negative fixtures for each new pattern.\n\n---\n\n<!-- dcg-machine-readable-v1 -->\n\n## DCG Hook Protocol (Machine-Readable Reference)\n\n> This section provides structured documentation for AI agents integrating with dcg.\n\n### JSON Input Format\n\ndcg reads from stdin in Claude Code's `PreToolUse` hook format:\n\n```json\n{\n  \"tool_name\": \"Bash\",\n  \"tool_input\": {\n    \"command\": \"git reset --hard HEAD~5\"\n  }\n}\n```\n\n**Required fields:**\n- `tool_name`: Must be `\"Bash\"` for dcg to process (other tools are ignored)\n- `tool_input.command`: The shell command string to evaluate\n\n### JSON Output Format (Denial)\n\nWhen a command is blocked, dcg outputs JSON to stdout:\n\n```json\n{\n  \"hookSpecificOutput\": {\n    \"hookEventName\": \"PreToolUse\",\n    \"permissionDecision\": \"deny\",\n    \"permissionDecisionReason\": \"BLOCKED by dcg\\n\\nTip: dcg explain \\\"git reset --hard HEAD~5\\\"\\n\\nReason: git reset --hard destroys uncommitted changes\\n\\nExplanation: Rewrites history and discards uncommitted changes.\\n\\nRule: core.git:reset-hard\\n\\nIf this operation is truly needed, ask the user for explicit permission and have them run the command manually.\",\n    \"ruleId\": \"core.git:reset-hard\",\n    \"packId\": \"core.git\",\n    \"severity\": \"critical\",\n    \"confidence\": 0.95,\n    \"allowOnceCode\": \"a1b2c3\",\n    \"allowOnceFullHash\": \"sha256:abc123...\",\n    \"remediation\": {\n      \"safeAlternative\": \"git stash\",\n      \"explanation\": \"Use git stash to save your changes first.\",\n      \"allowOnceCommand\": \"dcg allow-once a1b2c3\"\n    }\n  }\n}\n```\n\n**Key fields for agent parsing:**\n| Field | Type | Description |\n|-------|------|-------------|\n| `permissionDecision` | `\"allow\"` \\| `\"deny\"` | The decision |\n| `ruleId` | `string` | Stable pattern ID (e.g., `\"core.git:reset-hard\"`) for allowlisting |\n| `packId` | `string` | Pack that matched (e.g., `\"core.git\"`) |\n| `severity` | `string` | `\"critical\"`, `\"high\"`, `\"medium\"`, or `\"low\"` |\n| `confidence` | `number` | Match confidence 0.0-1.0 |\n| `allowOnceCode` | `string` | Short code for `dcg allow-once` |\n| `remediation.safeAlternative` | `string?` | Suggested safe command |\n\n### JSON Output Format (Allow)\n\nWhen a command is allowed: **no output** (silent exit 0).\n\n---\n\n## Exit Codes Reference\n\n| Code | Meaning | Agent Action |\n|------|---------|--------------|\n| `0` | Command allowed OR protocol JSON denial was emitted | Parse stdout; if empty, command was allowed |\n| `1` | Parse error or invalid input | Retry with corrected input |\n| `2` | Configuration error | Check config syntax and stderr diagnostics |\n\n**Detection logic for agents:**\n```bash\noutput=$(echo \"$hook_input\" | dcg 2>/dev/null)\nif [ -z \"$output\" ]; then\n  echo \"ALLOWED\"\nelse\n  echo \"DENIED: $output\"\nfi\n```\n\nCodex CLI uses a stricter hook parser: blocked commands return a minimal\n`hookSpecificOutput` denial on stdout with exit code 0. See\n[`docs/codex-integration.md`](docs/codex-integration.md) for the Codex-specific\nprotocol notes.\n\n---\n\n## Error Codes Reference\n\nDCG uses standardized error codes in the format `DCG-XXXX` for machine-parseable error handling.\n\n### Error Categories\n\n| Range | Category | Description |\n|-------|----------|-------------|\n| DCG-1xxx | `pattern_match` | Pattern matching and evaluation errors |\n| DCG-2xxx | `configuration` | Configuration loading and parsing errors |\n| DCG-3xxx | `runtime` | Runtime and execution errors |\n| DCG-4xxx | `external` | External integration errors |\n\n### Common Error Codes\n\n| Code | Description | Typical Cause |\n|------|-------------|---------------|\n| `DCG-1001` | Pattern compilation failed | Invalid regex syntax in pattern |\n| `DCG-1002` | Pattern match timeout | Complex pattern taking too long |\n| `DCG-2001` | Config file not found | Missing configuration file |\n| `DCG-2002` | Config parse error | Invalid TOML/JSON syntax |\n| `DCG-2004` | Allowlist load error | Invalid allowlist file |\n| `DCG-3001` | JSON parse error | Malformed JSON input |\n| `DCG-3002` | IO error | File read/write failure |\n| `DCG-4001` | External pack load failed | Invalid external pack YAML |\n\n### Error JSON Structure\n\nWhen errors are returned in JSON format, they follow this structure:\n\n```json\n{\n  \"error\": {\n    \"code\": \"DCG-3001\",\n    \"category\": \"runtime\",\n    \"message\": \"JSON parse error: unexpected token at position 15\",\n    \"context\": {\n      \"position\": 15,\n      \"input_preview\": \"{ \\\"tool_name\\\": ...\"\n    }\n  }\n}\n```\n\n**Fields:**\n- `code`: Stable error code for programmatic handling\n- `category`: Error category (`pattern_match`, `configuration`, `runtime`, `external`)\n- `message`: Human-readable error description\n- `context`: Additional details (optional, varies by error type)\n\n---\n\n## Allowlist & Bypass Instructions\n\n### Temporary Bypass (24-hour allow-once)\n\nWhen a command is blocked, the output includes an `allowOnceCode`. Use it:\n\n```bash\ndcg allow-once <code>\n```\n\nThis allows the specific command for 24 hours in the current directory scope.\n\n### Permanent Allowlist (by rule ID)\n\nAdd a rule to the project allowlist:\n\n```bash\ndcg allowlist add <ruleId> --project\n# Example: dcg allowlist add core.git:reset-hard --project\n```\n\nAllowlist files (in priority order):\n1. `.dcg/allowlist.toml` (project)\n2. `~/.config/dcg/allowlist.toml` (user)\n3. `/etc/dcg/allowlist.toml` (system)\n\n### Bypass Environment Variable\n\nFor emergency bypass (use sparingly):\n\n```bash\nDCG_BYPASS=1 <command>\n```\n\n**Warning:** This disables all protection. Log and justify any usage.\n\n---\n\n## Pattern Quick Reference\n\n### Core Git Patterns (Always Enabled)\n\n| Pattern ID | Blocks | Severity |\n|------------|--------|----------|\n| `core.git:reset-hard` | `git reset --hard` | Critical |\n| `core.git:reset-merge` | `git reset --merge` | High |\n| `core.git:checkout-discard` | `git checkout -- <file>` | High |\n| `core.git:restore-discard` | `git restore <file>` (without `--staged`) | High |\n| `core.git:clean-force` | `git clean -f`, `git clean -fd` | High |\n| `core.git:force-push` | `git push --force`, `git push -f` | High |\n| `core.git:branch-force-delete` | `git branch -d`, `--delete`, `-D`, `-f`, `-M`, `-C` | High |\n| `core.git:stash-drop` | `git stash drop`, `git stash clear` | High |\n\n### Core Filesystem Patterns (Always Enabled)\n\n| Pattern ID | Blocks | Severity |\n|------------|--------|----------|\n| `core.filesystem:rm-rf-root` | `rm -rf /`, `rm -rf ~` | Critical |\n| `core.filesystem:rm-rf-general` | `rm -rf` outside temp dirs | High |\n\n### Safe Patterns (Whitelist - Always Allowed)\n\n| Pattern | Command | Why Safe |\n|---------|---------|----------|\n| `git-checkout-branch` | `git checkout -b <branch>` | Creates new branch |\n| `git-checkout-orphan` | `git checkout --orphan <branch>` | Creates orphan branch |\n| `git-restore-staged` | `git restore --staged <file>` | Only unstages, doesn't discard |\n| `git-clean-dry-run` | `git clean -n`, `git clean --dry-run` | Preview only |\n| `rm-tmp` | `rm -rf /tmp/*`, `/var/tmp/*` | Temp directory cleanup |\n\n### Pack Enable/Disable Examples\n\n```toml\n# ~/.config/dcg/config.toml\n[packs]\nenabled = [\n    \"database.postgresql\",    # Blocks DROP TABLE, TRUNCATE\n    \"kubernetes.kubectl\",     # Blocks kubectl delete namespace\n    \"cloud.aws\",              # Blocks aws ec2 terminate-instances\n]\n\ndisabled = [\n    \"containers.docker\",      # Disable Docker protection\n]\n```\n\nList all packs: `dcg packs --verbose`\n\n---\n\n## CLI Quick Reference for Agents\n\n| Command | Purpose |\n|---------|---------|\n| `dcg explain \"<command>\"` | Detailed trace of why command is blocked/allowed |\n| `dcg allow-once <code>` | Allow a blocked command for 24 hours |\n| `dcg allowlist add <ruleId> --project` | Permanently allow a rule |\n| `dcg packs` | List enabled packs |\n| `dcg packs --verbose` | List all packs with pattern counts |\n| `dcg scan .` | Scan codebase for destructive patterns |\n| `dcg --version` | Show version and build info |\n\n---\n\n## Agent Integration Checklist\n\nWhen integrating with dcg, ensure your agent:\n\n- [ ] Parses stdout for JSON denial responses\n- [ ] Handles empty stdout as \"command allowed\"\n- [ ] Uses `ruleId` for stable allowlisting (not pattern text)\n- [ ] Displays `remediation.safeAlternative` to users when available\n- [ ] Respects `severity` for prioritization (critical > high > medium > low)\n- [ ] Uses `dcg explain` before asking users to bypass\n\n---\n\n## JSON Schema Reference\n\nFormal JSON Schema definitions (Draft 2020-12) for all dcg output formats are available in `docs/json-schema/`:\n\n| Schema | Purpose |\n|--------|---------|\n| [`hook-output.json`](docs/json-schema/hook-output.json) | PreToolUse hook denial response format |\n| [`scan-results.json`](docs/json-schema/scan-results.json) | `dcg scan` command output format |\n| [`stats-output.json`](docs/json-schema/stats-output.json) | `dcg stats` command output format |\n| [`error.json`](docs/json-schema/error.json) | Error response formats for various commands |\n\nUse these schemas for:\n- Validating dcg output in automated pipelines\n- Generating type-safe client code\n- Understanding the complete output contract\n\n<!-- end-dcg-machine-readable -->\n\n---\n\n## CI/CD Pipeline\n\n### Jobs Overview\n\n| Job | Trigger | Purpose | Blocking |\n|-----|---------|---------|----------|\n| `check` | PR, push | Format, clippy, UBS, tests | Yes |\n| `coverage` | PR, push | Coverage thresholds | Yes |\n| `memory-tests` | PR, push | Memory leak detection | Yes |\n| `benchmarks` | push to main | Performance budgets | Warn only |\n| `e2e` | PR, push | End-to-end shell tests | Yes |\n| `scan-regression` | PR, push | Scan output stability | Yes |\n| `perf-regression` | PR, push | Process-per-invocation perf | Yes |\n\n### Check Job\n\nRuns format, clippy, UBS static analysis, and unit tests. Includes:\n- `cargo fmt --check` - Code formatting\n- `cargo clippy --all-targets -- -D warnings` - Lints (pedantic + nursery enabled)\n- UBS analysis on changed Rust files (warning-only, non-blocking)\n- `cargo nextest run` - Full test suite with JUnit XML report\n\n### Coverage Job\n\nRuns `cargo llvm-cov` and enforces the thresholds configured in\n`.github/workflows/ci.yml` (`OVERALL_MIN`, `EVALUATOR_MIN`, `HOOK_MIN`).\nThese are enforced gates, not aspirational targets:\n- **Overall:** >= 70%\n- **src/evaluator.rs:** >= 65%\n- **src/hook.rs:** >= 70%\n\nIf CI thresholds change, update this section in the same change. The\n`coverage_threshold_docs` test checks that these documented values stay in sync\nwith the workflow.\n\nCoverage is uploaded to Codecov for trend tracking. Dashboard: https://codecov.io/gh/Dicklesworthstone/destructive_command_guard\n\n### Memory Tests Job\n\nRuns dedicated memory leak tests with:\n- `--test-threads=1` for accurate measurements\n- Release mode for realistic performance\n- 1-2MB growth budgets per test\n\nTests include: hook input parsing, pattern evaluation, heredoc extraction, file extractors, full pipeline, and a self-test that verifies the framework catches leaks.\n\n### Benchmarks Job\n\nRuns on push to main only (benchmarks are noisy on PRs). Checks performance budgets from `src/perf.rs`:\n- Quick reject: < 50us panic\n- Fast path: < 500us panic\n- Pattern match: < 1ms panic\n- Heredoc extract: < 2ms panic\n- Full heredoc pipeline: < 20ms panic\n- Hook evaluation deadline: 1000ms (exhaustion is indeterminate, never a silent allow)\n\n### UBS Static Analysis\n\nUltimate Bug Scanner runs on changed Rust files. Currently warning-only (non-blocking) to tune for false positives. Configuration in `.ubsignore` excludes test/bench/fuzz directories.\n\n### Dependabot\n\nAutomated dependency updates configured in `.github/dependabot.yml`:\n- **Cargo dependencies:** Weekly (Monday 9am EST), 5 PR limit\n- **GitHub Actions:** Weekly (Monday 9am EST), 3 PR limit\n- **Grouping:** Minor/patch updates grouped; serde updates separate (more careful review)\n\n### Debugging CI Failures\n\n#### Coverage Threshold Failure\n1. Check which file(s) dropped below threshold in CI output\n2. Run `cargo llvm-cov --html` locally to see uncovered lines\n3. Add tests for uncovered code paths\n4. Download `coverage-report` artifact for full details\n\n#### Memory Test Failure\n1. Download `memory-test-output` artifact\n2. Check which test failed and growth amount\n3. Run locally: `cargo test --test memory_tests --release -- --nocapture --test-threads=1`\n4. Profile with valgrind if needed\n\n#### UBS Warnings\n1. Check ubs-output.log in CI summary\n2. Review flagged issues - may be false positives\n3. If valid issues, fix them; if false positives, add to `.ubsignore`\n\n#### E2E Test Failure\n1. Download `e2e-artifacts` artifact\n2. Check `e2e_output.json` for failing test details\n3. Run locally: `./scripts/e2e_test.sh --verbose`\n4. The step summary shows the first failure with output\n\n#### Benchmark Regression\n1. Download `benchmark-results` artifact\n2. Compare against budgets in `src/perf.rs`\n3. Profile locally with `cargo bench --bench heredoc_perf`\n4. Check for algorithmic regressions in hot path\n\n---\n\n## Release Process\n\nWhen fixes are ready for release, follow this process:\n\nThe steps below describe the normal GitHub Actions path. If Actions cannot run\nor a native Windows artifact must be built locally, the more detailed\n**Local/DSR Release and Windows Deployment Runbook** near the end of this file\nis authoritative.\n\n### 1. Verify CI Passes Locally\n\n```bash\ncargo fmt --check\ncargo check --all-targets\ncargo clippy --all-targets -- -D warnings\ncargo test\n```\n\n### 2. Commit Changes\n\n```bash\ngit add -A\ngit commit -m \"fix: description of fixes\n\n- List specific fixes\n- Include any breaking changes\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\"\n```\n\n### 3. Bump Version (if needed)\n\nThe version in `Cargo.toml` determines the release tag. A version may be reused\nafter a failed *local, pre-tag* attempt. Once its tag has been pushed or a\nrelease has been published, treat that version as immutable and bump to a new\npatch version instead of moving the tag or replacing signed assets.\n\n- **Patch** (0.2.10 -> 0.2.11): Bug fixes, no new features\n- **Minor** (0.2.x -> 0.3.0): New features, backward compatible\n- **Major** (0.x -> 1.0): Breaking changes\n\n### 4. Push and Trigger Release\n\n```bash\ngit push origin main\ngit push origin main:master  # Keep master in sync\n```\n\nThe `release-automation.yml` workflow will:\n1. Detect version change in `Cargo.toml`\n2. Create an annotated git tag (e.g., `v0.2.13`)\n3. Push the tag, which triggers `dist.yml`\n\nThe `dist.yml` workflow will:\n1. Run tests and clippy\n2. Build binaries for all platforms (Linux x86/ARM, macOS Intel/Apple Silicon, Windows)\n3. Create `.tar.xz` archives with SHA256 checksums\n4. Sign artifacts with Sigstore (cosign) - creates `.sigstore.json` bundles\n5. Upload everything to GitHub Releases\n\n### 5. Verify Release\n\n```bash\ngh release list --limit 5\ngh release view v0.2.13  # Check assets were uploaded\n```\n\nExpected assets per release:\n- `dcg-{target}.tar.xz` (Unix) or `.zip` (Windows) - Binary archive\n- `<archive>.sha256` - Mandatory per-artifact checksum\n- `<archive>.sigstore.json` - Sigstore signature bundle\n- `install.sh`, `install.ps1`, and their checksum/Sigstore sidecars\n- Manual DSR releases additionally include minisign signatures, SLSA\n  provenance, a build manifest, and the pinned public verification keys\n\n### Troubleshooting Failed Releases\n\nIf CI fails:\n1. Check workflow run: `gh run list --workflow=dist.yml --limit=5`\n2. View failed job: `gh run view <run-id>`\n3. Fix issues locally, commit, and push again\n4. If no public tag or release exists yet, retry the same version; otherwise\n   create a new patch release. Never force-move a public release tag.\n\nCommon failures:\n- **Clippy errors**: Fix lints, ensure `cargo clippy -- -D warnings` passes\n- **Test failures**: Run `cargo test` to reproduce\n- **Format errors**: Run `cargo fmt` to fix\n\n---\n\n## MCP Agent Mail — Multi-Agent Coordination\n\nA mail-like layer that lets coding agents coordinate asynchronously via MCP tools and resources. Provides identities, inbox/outbox, searchable threads, and advisory file reservations with human-auditable artifacts in Git.\n\n### Why It's Useful\n\n- **Prevents conflicts:** Explicit file reservations (leases) for files/globs\n- **Token-efficient:** Messages stored in per-project archive, not in context\n- **Quick reads:** `resource://inbox/...`, `resource://thread/...`\n\n### Same Repository Workflow\n\n1. **Register identity:**\n   ```\n   ensure_project(project_key=<abs-path>)\n   register_agent(project_key, program, model)\n   ```\n\n2. **Reserve files before editing:**\n   ```\n   file_reservation_paths(project_key, agent_name, [\"src/**\"], ttl_seconds=3600, exclusive=true)\n   ```\n\n3. **Communicate with threads:**\n   ```\n   send_message(..., thread_id=\"FEAT-123\")\n   fetch_inbox(project_key, agent_name)\n   acknowledge_message(project_key, agent_name, message_id)\n   ```\n\n4. **Quick reads:**\n   ```\n   resource://inbox/{Agent}?project=<abs-path>&limit=20\n   resource://thread/{id}?project=<abs-path>&include_bodies=true\n   ```\n\n### Macros vs Granular Tools\n\n- **Prefer macros for speed:** `macro_start_session`, `macro_prepare_thread`, `macro_file_reservation_cycle`, `macro_contact_handshake`\n- **Use granular tools for control:** `register_agent`, `file_reservation_paths`, `send_message`, `fetch_inbox`, `acknowledge_message`\n\n### Common Pitfalls\n\n- `\"from_agent not registered\"`: Always `register_agent` in the correct `project_key` first\n- `\"FILE_RESERVATION_CONFLICT\"`: Adjust patterns, wait for expiry, or use non-exclusive reservation\n- **Auth errors:** If JWT+JWKS enabled, include bearer token with matching `kid`\n\n---\n\n## Beads (br) — Dependency-Aware Issue Tracking\n\nBeads provides a lightweight, dependency-aware issue database and CLI (`br` - beads_rust) for selecting \"ready work,\" setting priorities, and tracking status. It complements MCP Agent Mail's messaging and file reservations.\n\n**Important:** `br` is non-invasive—it NEVER runs git commands automatically. You must manually commit changes after `br sync --flush-only`.\n\n### Conventions\n\n- **Single source of truth:** Beads for task status/priority/dependencies; Agent Mail for conversation and audit\n- **Shared identifiers:** Use Beads issue ID (e.g., `br-123`) as Mail `thread_id` and prefix subjects with `[br-123]`\n- **Reservations:** When starting a task, call `file_reservation_paths()` with the issue ID in `reason`\n\n### Typical Agent Flow\n\n1. **Pick ready work (Beads):**\n   ```bash\n   br ready --json  # Choose highest priority, no blockers\n   ```\n\n2. **Reserve edit surface (Mail):**\n   ```\n   file_reservation_paths(project_key, agent_name, [\"src/**\"], ttl_seconds=3600, exclusive=true, reason=\"br-123\")\n   ```\n\n3. **Announce start (Mail):**\n   ```\n   send_message(..., thread_id=\"br-123\", subject=\"[br-123] Start: <title>\", ack_required=true)\n   ```\n\n4. **Work and update:** Reply in-thread with progress\n\n5. **Complete and release:**\n   ```bash\n   br close 123 --reason \"Completed\"\n   br sync --flush-only  # Export to JSONL (no git operations)\n   ```\n   ```\n   release_file_reservations(project_key, agent_name, paths=[\"src/**\"])\n   ```\n   Final Mail reply: `[br-123] Completed` with summary\n\n### Mapping Cheat Sheet\n\n| Concept | Value |\n|---------|-------|\n| Mail `thread_id` | `br-###` |\n| Mail subject | `[br-###] ...` |\n| File reservation `reason` | `br-###` |\n| Commit messages | Include `br-###` for traceability |\n\n---\n\n## bv — Graph-Aware Triage Engine\n\nbv is a graph-aware triage engine for Beads projects (`.beads/beads.jsonl`). It computes PageRank, betweenness, critical path, cycles, HITS, eigenvector, and k-core metrics deterministically.\n\n**Scope boundary:** bv handles *what to work on* (triage, priority, planning). For agent-to-agent coordination (messaging, work claiming, file reservations), use MCP Agent Mail.\n\n**CRITICAL: Use ONLY `--robot-*` flags. Bare `bv` launches an interactive TUI that blocks your session.**\n\n### The Workflow: Start With Triage\n\n**`bv --robot-triage` is your single entry point.** It returns:\n- `quick_ref`: at-a-glance counts + top 3 picks\n- `recommendations`: ranked actionable items with scores, reasons, unblock info\n- `quick_wins`: low-effort high-impact items\n- `blockers_to_clear`: items that unblock the most downstream work\n- `project_health`: status/type/priority distributions, graph metrics\n- `commands`: copy-paste shell commands for next steps\n\n```bash\nbv --robot-triage        # THE MEGA-COMMAND: start here\nbv --robot-next          # Minimal: just the single top pick + claim command\n```\n\n### Command Reference\n\n**Planning:**\n| Command | Returns |\n|---------|---------|\n| `--robot-plan` | Parallel execution tracks with `unblocks` lists |\n| `--robot-priority` | Priority misalignment detection with confidence |\n\n**Graph Analysis:**\n| Command | Returns |\n|---------|---------|\n| `--robot-insights` | Full metrics: PageRank, betweenness, HITS, eigenvector, critical path, cycles, k-core, articulation points, slack |\n| `--robot-label-health` | Per-label health: `health_level`, `velocity_score`, `staleness`, `blocked_count` |\n| `--robot-label-flow` | Cross-label dependency: `flow_matrix`, `dependencies`, `bottleneck_labels` |\n| `--robot-label-attention [--attention-limit=N]` | Attention-ranked labels |\n\n**History & Change Tracking:**\n| Command | Returns |\n|---------|---------|\n| `--robot-history` | Bead-to-commit correlations |\n| `--robot-diff --diff-since <ref>` | Changes since ref: new/closed/modified issues, cycles |\n\n**Other:**\n| Command | Returns |\n|---------|---------|\n| `--robot-burndown <sprint>` | Sprint burndown, scope changes, at-risk items |\n| `--robot-forecast <id\\|all>` | ETA predictions with dependency-aware scheduling |\n| `--robot-alerts` | Stale issues, blocking cascades, priority mismatches |\n| `--robot-suggest` | Hygiene: duplicates, missing deps, label suggestions |\n| `--robot-graph [--graph-format=json\\|dot\\|mermaid]` | Dependency graph export |\n| `--export-graph <file.html>` | Interactive HTML visualization |\n\n### Scoping & Filtering\n\n```bash\nbv --robot-plan --label backend              # Scope to label's subgraph\nbv --robot-insights --as-of HEAD~30          # Historical point-in-time\nbv --recipe actionable --robot-plan          # Pre-filter: ready to work\nbv --recipe high-impact --robot-triage       # Pre-filter: top PageRank\nbv --robot-triage --robot-triage-by-track    # Group by parallel work streams\nbv --robot-triage --robot-triage-by-label    # Group by domain\n```\n\n### Understanding Robot Output\n\n**All robot JSON includes:**\n- `data_hash` — Fingerprint of source beads.jsonl\n- `status` — Per-metric state: `computed|approx|timeout|skipped` + elapsed ms\n- `as_of` / `as_of_commit` — Present when using `--as-of`\n\n**Two-phase analysis:**\n- **Phase 1 (instant):** degree, topo sort, density\n- **Phase 2 (async, 500ms timeout):** PageRank, betweenness, HITS, eigenvector, cycles\n\n### jq Quick Reference\n\n```bash\nbv --robot-triage | jq '.quick_ref'                        # At-a-glance summary\nbv --robot-triage | jq '.recommendations[0]'               # Top recommendation\nbv --robot-plan | jq '.plan.summary.highest_impact'        # Best unblock target\nbv --robot-insights | jq '.status'                         # Check metric readiness\nbv --robot-insights | jq '.Cycles'                         # Circular deps (must fix!)\n```\n\n---\n\n## UBS — Ultimate Bug Scanner\n\n**Golden Rule:** `ubs <changed-files>` before every commit. Exit 0 = safe. Exit >0 = fix & re-run.\n\n### Commands\n\n```bash\nubs file.rs file2.rs                    # Specific files (< 1s) — USE THIS\nubs $(git diff --name-only --cached)    # Staged files — before commit\nubs --only=rust,toml src/               # Language filter (3-5x faster)\nubs --ci --fail-on-warning .            # CI mode — before PR\nubs .                                   # Whole project (ignores target/, Cargo.lock)\n```\n\n### Output Format\n\n```\nWarning  Category (N errors)\n    file.rs:42:5 - Issue description\n    Suggested fix\nExit code: 1\n```\n\nParse: `file:line:col` -> location | fix hint -> how to fix | Exit 0/1 -> pass/fail\n\n### Fix Workflow\n\n1. Read finding -> category + fix suggestion\n2. Navigate `file:line:col` -> view context\n3. Verify real issue (not false positive)\n4. Fix root cause (not symptom)\n5. Re-run `ubs <file>` -> exit 0\n6. Commit\n\n### Bug Severity\n\n- **Critical (always fix):** Memory safety, use-after-free, data races, SQL injection\n- **Important (production):** Unwrap panics, resource leaks, overflow checks\n- **Contextual (judgment):** TODO/FIXME, println! debugging\n\n---\n\n## RCH — Remote Compilation Helper\n\nRCH offloads `cargo build`, `cargo test`, `cargo clippy`, and other compilation commands to a fleet of 8 remote Contabo VPS workers instead of building locally. This prevents compilation storms from overwhelming csd when many agents run simultaneously.\n\n**RCH is installed at `~/.local/bin/rch` and is hooked into Claude Code's PreToolUse automatically.** Most of the time you don't need to do anything if you are Claude Code — builds are intercepted and offloaded transparently.\n\nTo manually offload a build:\n```bash\nrch exec -- cargo build --release\nrch exec -- cargo test\nrch exec -- cargo clippy\n```\n\nQuick commands:\n```bash\nrch doctor                    # Health check\nrch workers probe --all       # Test connectivity to all 8 workers\nrch status                    # Overview of current state\nrch queue                     # See active/waiting builds\n```\n\nIf rch or its workers are unavailable, it fails open — builds run locally as normal.\n\n**Note for Codex/GPT-5.2:** Codex does not have the automatic PreToolUse hook, but you can (and should) still manually offload compute-intensive compilation commands using `rch exec -- <command>`. This avoids local resource contention when multiple agents are building simultaneously.\n\n---\n\n## ast-grep vs ripgrep\n\n**Use `ast-grep` when structure matters.** It parses code and matches AST nodes, ignoring comments/strings, and can **safely rewrite** code.\n\n- Refactors/codemods: rename APIs, change import forms\n- Policy checks: enforce patterns across a repo\n- Editor/automation: LSP mode, `--json` output\n\n**Use `ripgrep` when text is enough.** Fastest way to grep literals/regex.\n\n- Recon: find strings, TODOs, log lines, config values\n- Pre-filter: narrow candidate files before ast-grep\n\n### Rule of Thumb\n\n- Need correctness or **applying changes** -> `ast-grep`\n- Need raw speed or **hunting text** -> `rg`\n- Often combine: `rg` to shortlist files, then `ast-grep` to match/modify\n\n### Rust Examples\n\n```bash\n# Find structured code (ignores comments)\nast-grep run -l Rust -p 'fn $NAME($$$ARGS) -> $RET { $$$BODY }'\n\n# Find all unwrap() calls\nast-grep run -l Rust -p '$EXPR.unwrap()'\n\n# Quick textual hunt\nrg -n 'println!' -t rust\n\n# Combine speed + precision\nrg -l -t rust 'unwrap\\(' | xargs ast-grep run -l Rust -p '$X.unwrap()' --json\n```\n\n---\n\n## Morph Warp Grep — AI-Powered Code Search\n\n**Use `mcp__morph-mcp__warp_grep` for exploratory \"how does X work?\" questions.** An AI agent expands your query, greps the codebase, reads relevant files, and returns precise line ranges with full context.\n\n**Use `ripgrep` for targeted searches.** When you know exactly what you're looking for.\n\n**Use `ast-grep` for structural patterns.** When you need AST precision for matching/rewriting.\n\n### When to Use What\n\n| Scenario | Tool | Why |\n|----------|------|-----|\n| \"How is pattern matching implemented?\" | `warp_grep` | Exploratory; don't know where to start |\n| \"Where is the quick reject filter?\" | `warp_grep` | Need to understand architecture |\n| \"Find all uses of `Regex::new`\" | `ripgrep` | Targeted literal search |\n| \"Find files with `println!`\" | `ripgrep` | Simple pattern |\n| \"Replace all `unwrap()` with `expect()`\" | `ast-grep` | Structural refactor |\n\n### warp_grep Usage\n\n```\nmcp__morph-mcp__warp_grep(\n  repoPath: \"/dp/destructive_command_guard\",\n  query: \"How does the safe pattern whitelist work?\"\n)\n```\n\nReturns structured results with file paths, line ranges, and extracted code snippets.\n\n### Anti-Patterns\n\n- **Don't** use `warp_grep` to find a specific function name -> use `ripgrep`\n- **Don't** use `ripgrep` to understand \"how does X work\" -> wastes time with manual reads\n- **Don't** use `ripgrep` for codemods -> risks collateral edits\n\n<!-- bv-agent-instructions-v1 -->\n\n---\n\n## Beads Workflow Integration\n\nThis project uses [beads_rust](https://github.com/Dicklesworthstone/beads_rust) (`br`) for issue tracking. Issues are stored in `.beads/` and tracked in git.\n\n**Important:** `br` is non-invasive—it NEVER executes git commands. After `br sync --flush-only`, you must manually run `git add .beads/ && git commit`.\n\n### Essential Commands\n\n```bash\n# View issues (launches TUI - avoid in automated sessions)\nbv\n\n# CLI commands for agents (use these instead)\nbr ready              # Show issues ready to work (no blockers)\nbr list --status=open # All open issues\nbr show <id>          # Full issue details with dependencies\nbr create --title=\"...\" --type=task --priority=2\nbr update <id> --status=in_progress\nbr close <id> --reason \"Completed\"\nbr close <id1> <id2>  # Close multiple issues at once\nbr sync --flush-only  # Export to JSONL (NO git operations)\n```\n\n### Workflow Pattern\n\n1. **Start**: Run `br ready` to find actionable work\n2. **Claim**: Use `br update <id> --status=in_progress`\n3. **Work**: Implement the task\n4. **Complete**: Use `br close <id>`\n5. **Sync**: Run `br sync --flush-only` then manually commit\n\n### Key Concepts\n\n- **Dependencies**: Issues can block other issues. `br ready` shows only unblocked work.\n- **Priority**: P0=critical, P1=high, P2=medium, P3=low, P4=backlog (use numbers, not words)\n- **Types**: task, bug, feature, epic, question, docs\n- **Blocking**: `br dep add <issue> <depends-on>` to add dependencies\n\n### Session Protocol\n\n**Before ending any session, run this checklist:**\n\n```bash\ngit status              # Check what changed\ngit add <files>         # Stage code changes\nbr sync --flush-only    # Export beads to JSONL\ngit add .beads/         # Stage beads changes\ngit commit -m \"...\"     # Commit everything together\ngit push                # Push to remote\n```\n\n### Best Practices\n\n- Check `br ready` at session start to find available work\n- Update status as you work (in_progress -> closed)\n- Create new issues with `br create` when you discover tasks\n- Use descriptive titles and set appropriate priority/type\n- Always `br sync --flush-only && git add .beads/` before ending session\n\n<!-- end-bv-agent-instructions -->\n\n## Landing the Plane (Session Completion)\n\n**When ending a work session**, you MUST complete ALL steps below.\n\n**MANDATORY WORKFLOW:**\n\n1. **File issues for remaining work** - Create issues for anything that needs follow-up\n2. **Run quality gates** (if code changed) - Tests, linters, builds\n3. **Update issue status** - Close finished work, update in-progress items\n4. **Sync beads** - `br sync --flush-only` to export to JSONL\n5. **Hand off** - Provide context for next session\n\n\n---\n\n## cass — Cross-Agent Session Search\n\n`cass` indexes prior agent conversations (Claude Code, Codex, Cursor, Gemini, ChatGPT, etc.) so we can reuse solved problems.\n\n**Rules:** Never run bare `cass` (TUI). Always use `--robot` or `--json`.\n\n### Examples\n\n```bash\ncass health\ncass search \"async runtime\" --robot --limit 5\ncass view /path/to/session.jsonl -n 42 --json\ncass expand /path/to/session.jsonl -n 42 -C 3 --json\ncass capabilities --json\ncass robot-docs guide\n```\n\n### Tips\n\n- Use `--fields minimal` for lean output\n- Filter by agent with `--agent`\n- Use `--days N` to limit to recent history\n\nstdout is data-only, stderr is diagnostics; exit code 0 means success.\n\nTreat cass as a way to avoid re-solving problems other agents already handled.\n\n---\n\n## Local/DSR Release and Windows Deployment Runbook\n\nUse this fallback only when GitHub Actions cannot perform the release, when a\nnative-host build is explicitly required, or when the user directs you to use\nDSR. It refines the shorter release checklist above. Do not jump straight to\n`dsr fallback`: keep source freezing, build, packaging, signing, publication,\nand public verification as separately inspectable stages.\n\n### Non-Negotiable Release Invariants\n\n1. **One immutable source identity.** The local `HEAD`, peeled release tag,\n   remote `main`, compatibility branch, build checkout, build manifest, and\n   published release must all name the same commit.\n2. **Frozen bytes before signatures.** Finish archive layout and names before\n   generating checksums, SLSA provenance, minisign signatures, or Sigstore\n   bundles. Any byte or filename change invalidates downstream metadata and\n   requires regenerating and reverifying it.\n3. **Integrity is not authenticity.** SHA256 is mandatory, but it does not\n   authenticate the publisher. Manual releases require the DSR minisign trust\n   path and the pinned local-release cosign trust path. Workflow releases use\n   GitHub Actions OIDC for Sigstore.\n4. **No destructive synchronization or cleanup.** Assume an automatic source\n   mirror may delete files until its dry-run proves otherwise. Never bypass dcg\n   to clean a checkout, output directory, key copy, or failed release. Rule 1\n   still applies to temporary files and directories.\n5. **A partial matrix must be deliberate.** A working Windows artifact does not\n   prove that every advertised target exists. Define the expected target/asset\n   matrix before building and either satisfy it or explicitly treat the release\n   as an emergency partial release with tested source-install fallback.\n\n### 1. Decide the Path and Freeze the Source\n\nFirst inspect Actions rather than waiting blindly:\n\n```bash\ngh run list --limit 20\ndsr check Dicklesworthstone/destructive_command_guard\n```\n\nIf the manual path is justified, run all release gates *before* tagging:\n\n```bash\ncargo fmt --check\ncargo check --all-targets\ncargo clippy --all-targets -- -D warnings\ncargo test\ncargo check --target x86_64-pc-windows-gnu --lib\ncargo build --release\n./scripts/e2e_test.sh --verbose\npwsh -NoProfile -File ./scripts/e2e_test.ps1 -Verbose\n```\n\nRun any additional gates relevant to the changed surface. A release candidate\nwith code changes receives the full suite; a crate-scoped or `--lib` run is not\na release substitute. Both E2E scripts discover the release binary through\n`CARGO_TARGET_DIR` and reject a stale in-repository binary. If `--binary` /\n`-Binary` is supplied explicitly, pass an absolute path: the suites change\ndirectories while testing isolated configurations. If local PowerShell is\nunavailable, run the PowerShell suite against the native release candidate on\nthe Windows build host before publication.\n\nConfirm the worktree contains only intentional release content, commit it, then\ncreate an annotated tag. Never force an existing public tag:\n\n```bash\nVERSION=vX.Y.Z\ngit status --short\ngit tag -a \"$VERSION\" -m \"Release $VERSION\"\ngit push origin main\ngit push origin main:master\ngit push origin \"$VERSION\"\n```\n\nChoose exactly one owner for the tag and release. If the local path owns them,\ndo not also let `release-automation` create the same tag in parallel.\n\nRecord and compare the identities instead of trusting labels:\n\n```bash\nHEAD_SHA=$(git rev-parse HEAD)\nTAG_SHA=$(git rev-parse \"${VERSION}^{commit}\")\ntest \"$HEAD_SHA\" = \"$TAG_SHA\"\ngit ls-remote origin refs/heads/main refs/heads/master \"refs/tags/$VERSION\" \"refs/tags/$VERSION^{}\"\n```\n\nFor an annotated tag, compare against the peeled `^{}`\nentry—not the tag-object SHA. If any identity differs, stop before building.\nDo not “repair” a published tag; make a patch release.\n\n### 2. Preflight DSR and the Native Windows Host\n\nValidate configuration, target naming, quality commands, host health, disk\nspace, and the exact build plan:\n\n```bash\ndsr repos validate --repo destructive_command_guard\ndsr quality --tool destructive_command_guard --dry-run\ndsr health all --no-cache\ndsr build destructive_command_guard \\\n  --version \"${VERSION#v}\" \\\n  --target windows/amd64 \\\n  --dry-run\n```\n\nThe installer asset name, DSR `artifact_naming`, target triple, archive format,\nand release upload name must agree. A naming mismatch can silently trigger a\nsource build instead of installing the native artifact.\n\nTreat DSR's automatic remote source sync as deletion-capable. Under this\nrepository's no-deletion rule, do not sync into an existing checkout. For a\nnative build:\n\n1. Create a brand-new checkout path on the Windows host at the exact tag.\n2. Verify that checkout's `HEAD` equals `TAG_SHA` and that its worktree is\n   clean.\n3. Temporarily point DSR's host source mapping at that fresh checkout.\n4. Use a brand-new output path and run the build with `--no-sync`:\n\n   ```bash\n   dsr build destructive_command_guard \\\n     --version \"${VERSION#v}\" \\\n     --target windows/amd64 \\\n     --no-sync \\\n     --output-dir <brand-new-output-directory>\n   ```\n\n5. Restore the previous DSR host mapping immediately after collection, even\n   when the build or artifact collection fails.\n\nDo not remove the staged checkout or output directory without the user's\nwritten permission. Record the native host, target triple, commit SHA, Rust\ntoolchain, build duration, and collected executable SHA256 in the release\nnotes/manifest. Monitor a long native build instead of starting a competing\nbuild because it appears quiet.\n\n### 3. Package the Native Artifact Correctly\n\nDSR may successfully collect `dcg.exe` even when the coordinator lacks a ZIP\ntool. That is a packaging failure, not a compile failure. In that case, package\nthe collected executable on Windows with PowerShell `Compress-Archive`.\n\nThe Windows release ZIP must contain exactly one root entry named `dcg.exe`.\nBefore signing:\n\n- Extract the ZIP into a new inspection directory.\n- Hash the extracted `dcg.exe`.\n- Confirm that hash equals the collected native PE hash recorded by DSR.\n- Run the extracted binary and confirm its version matches `VERSION`.\n- Confirm it is the native MSVC release build—not a GNU compile-check artifact,\n  debug binary, stale binary, or installer smoke fixture.\n\nNever rename arbitrary bytes to make them look like a ZIP, and never package a\ndifferent binary merely because it has the expected filename.\n\n### 4. Freeze, Checksum, and Sign the Complete Asset Set\n\nWrite down the expected assets before signing. Depending on release scope this\nincludes archives, standalone binaries, installers, the build manifest,\nper-file `.sha256` sidecars, `SHA256SUMS`, SLSA `.intoto.jsonl` provenance,\n`.minisig` files, `.sigstore.json` bundles, and public verification keys.\n\nThe order is strict:\n\n1. Finalize payload bytes and filenames.\n2. Generate per-file SHA256 sidecars and the aggregate checksum manifest.\n3. Generate and verify SLSA provenance against the frozen payload.\n4. Sign publishable payloads and metadata with DSR minisign.\n5. Generate key-based cosign bundles for the local-release trust path.\n6. Independently verify every signature and bundle.\n\nUse DSR's configured private keys directly from its protected secret location.\nPrivate keys and password material must remain mode `600` and must never be\ncopied into the repository, release directory, generic temporary directory, or\nremote build checkout. Publish only public keys and their fingerprints. If\nduplicate secret material is discovered, stop and follow Rule 1; do not set\n`DCG_BYPASS` or otherwise evade a blocked cleanup command.\n\nBefore publication, confirm that:\n\n- `install.sh`, `install.ps1`, and `README.md` agree on the current minisign\n  public key and local cosign public-key fingerprint.\n- A retired key is accepted only for the exact historical release that used\n  it, never as an unbounded fallback.\n- The cosign verifier meets the installer's patched-version floor\n  (2.6.2+ on v2 or 3.0.4+ on v3); unknown, development, and prerelease version\n  strings fail closed for signature verification.\n\nOnce signing begins, treat the directory as immutable. If a checksum generator,\nuploader, or packaging tool wants to rewrite `SHA256SUMS`, a sidecar, or an\narchive, stop and restart the checksum/signature stages from the newly frozen\nbytes.\n\n### 5. Verify Locally and on the Native Windows Machine\n\nPerform positive and negative tests before uploading:\n\n- SHA256, minisign, cosign, and SLSA verification all succeed independently.\n- A valid artifact paired with the wrong minisign signature fails.\n- A valid artifact paired with the wrong Sigstore bundle fails.\n- A modified artifact fails every applicable integrity/authenticity check.\n- `install.ps1` installs the local artifact into a fresh destination with\n  `-RequireMinisign -Verify -NoConfigure -Force`, using explicit local\n  artifact/checksum/signature/bundle inputs.\n- The installed binary hash equals the signed payload hash, reports the\n  expected version, and passes the installer self-test.\n\nRun the installer twice in a hermetic Windows home and confirm hook\nconfiguration is idempotent: one dcg-owned hook per supported integration,\ncoexisting hooks preserved, valid JSON without a UTF-8 BOM, and no stale dcg\nentry. Run `dcg doctor` and `dcg config --format json`; do not guess config\npaths, enabled packs, timeout sources, or whether two visually similar hook\nentries are actually duplicates. On native Windows the canonical user config is\n`%APPDATA%\\dcg\\config.toml`; the legacy `~/.config/dcg/config.toml` may also be\nhonored, so use the config report to identify the file that actually won.\n\nFor the `careful_company_running_windows` preset, verify the effective 3000 ms\ndefault hook budget on a cold Windows process and confirm all six preset\nsub-packs plus the curated transitive members are active. Then test\nrepresentative allow and deny cases through both PowerShell and `cmd.exe` hook\npayloads, including outbound mail/upload blocks and the structural `hfdt`\nexception (plain `hfdt` allowed; chaining, redirection, and substitution are not\nimplicitly trusted). Exercise committed `.ps1`, `.cmd`, and `.bat` fixtures with\n`dcg scan` rather than placing an intentionally blocked test string on the\nguarded operator shell's own command line.\n\nWindows PowerShell 5.1 has two diagnostic traps:\n\n- Successful native programs such as cosign and `dcg --version` may write to\n  stderr. With `$ErrorActionPreference = 'Stop'` and merged streams, PowerShell\n  can wrap this as `NativeCommandError`. Temporarily make native stderr\n  non-terminating and decide success from the native process exit code.\n- `$LASTEXITCODE` can be stale after invoking a PowerShell script in-process.\n  For installer acceptance, launch a child PowerShell process, wait for it, and\n  inspect that process object's `ExitCode`.\n\nOlder dcg versions could not replace their own running `dcg.exe`. The current\nupdater has a deferred Windows swap path, but every release must retain the\nreal-Windows running-binary update/rollback test. When recovering an older\ninstallation that lacks the fix, run the release installer directly.\n\n### 6. Inspect the Upload Plan, Then Publish\n\nNever assume an uploader is byte-preserving or complete. Run its dry-run/upload\nplan before signing when possible, and compare the selected filenames with the\nfrozen expected-asset list.\n\nAn observed DSR failure mode is regenerating aggregate checksum metadata during\nrelease assembly while omitting installers or `.sigstore.json` bundles from the\nselected upload set. If the current `dsr release` plan would mutate signed\nmetadata or omit required files, do not use it for publication. DSR can still\nprovide the native build, manifest, minisign signatures, and SLSA provenance;\npublish the frozen files with an explicit, enumerated `gh release create` /\n`gh release upload` invocation instead.\n\nPrefer assembling assets on a draft release. Never use `--clobber` on a signed\nasset and never replace an asset behind an existing public URL. If published\nbytes are wrong, withdraw the bad release as directed by the user and issue a\nnew patch version.\n\nIf a local release is now authoritative, inspect queued GitHub workflows. Cancel\nonly `dist` / release-automation runs that could race to create or replace the\nsame release. Do not cancel unrelated CI, coverage, or benchmark runs.\n\n### 7. Verify the Published Release From Scratch\n\nDownload the release into a new local directory and verify it without relying\non build-directory state:\n\n1. Compare the public asset names with the frozen expected-asset list.\n2. Verify the aggregate and per-file SHA256 data.\n3. Verify every minisign signature using the published/pinned public key.\n4. Verify every Sigstore bundle against the correct local-key or Actions-OIDC\n   trust root.\n5. Verify every SLSA subject digest against its public artifact.\n6. Confirm the release is public, non-draft, and has the intended prerelease\n   status.\n\nThen run the installer from the *public release URL* on the native Windows host\ninto a fresh destination. Pin `-Version`, require minisign, enable `-Verify`,\nand confirm the installed hash, version, self-test, `dcg doctor`, effective\nconfig, hook idempotency, and representative PowerShell/`cmd.exe` policy\nbehavior. A local-file install does not substitute for this public-path test.\n\nFinally verify the repository invariants again:\n\n```bash\ngit status --short\ngit rev-parse HEAD\ngit rev-parse \"${VERSION}^{commit}\"\ngit ls-remote origin refs/heads/main refs/heads/master \"refs/tags/$VERSION\" \"refs/tags/$VERSION^{}\"\ngh release view \"$VERSION\"\n```\n\nThe release is complete only when the source identities agree, the worktree is\nclean, all intended assets are publicly downloadable and independently\nverifiable, and a fresh native Windows installation succeeds from the public\nrelease.\n\n---\n\nNote for Codex/GPT-5.2:\n\nYou constantly bother me and stop working with concerned questions that look similar to this:\n\n```\nUnexpected changes (need guidance)\n\n- Working tree still shows edits I did not make in Cargo.toml, Cargo.lock, src/cli/commands/upgrade.rs, src/storage/sqlite.rs, tests/conformance.rs, tests/storage_deps.rs. Please advise whether to keep/commit/revert these before any further work. I did not touch them.\n\nNext steps (pick one)\n\n1. Decide how to handle the unrelated modified files above so we can resume cleanly.\n2. Triage beads_rust-orko (clippy/cargo warnings) and beads_rust-ydqr (rustfmt failures).\n3. If you want a full suite run later, fix conformance/clippy blockers and re-run cargo test --all.\n```\n\nNEVER EVER DO THAT AGAIN. The answer is literally ALWAYS the same: those are changes created by the potentially dozen of other agents working on the project at the same time. This is not only a common occurrence, it happens multiple times PER MINUTE. The way to deal with it is simple: you NEVER, under ANY CIRCUMSTANCE, stash, revert, overwrite, or otherwise disturb in ANY way the work of other agents. Just treat those changes identically to changes that you yourself made. Just fool yourself into thinking YOU made the changes and simply don't recall it for some reason.\n\n---\n\n## Note on Built-in TODO Functionality\n\nAlso, if I ask you to explicitly use your built-in TODO functionality, don't complain about this and say you need to use beads. You can use built-in TODOs if I tell you specifically to do so. Always comply with such orders.\n"},"files":{"AGENTS.md":"# AGENTS.md — dcg (Destructive Command Guard)\n\n> Guidelines for AI coding agents working in this Rust codebase.\n\n---\n\n## RULE 0 - THE FUNDAMENTAL OVERRIDE PREROGATIVE\n\nIf I tell you to do something, even if it goes against what follows below, YOU MUST LISTEN TO ME. I AM IN CHARGE, NOT YOU.\n\n---\n\n## RULE NUMBER 1: NO FILE DELETION\n\n**YOU ARE NEVER ALLOWED TO DELETE A FILE WITHOUT EXPRESS PERMISSION.** Even a new file that you yourself created, such as a test code file. You have a horrible track record of deleting critically important files or otherwise throwing away tons of expensive work. As a result, you have permanently lost any and all rights to determine that a file or folder should be deleted.\n\n**YOU MUST ALWAYS ASK AND RECEIVE CLEAR, WRITTEN PERMISSION BEFORE EVER DELETING A FILE OR FOLDER OF ANY KIND.**\n\n---\n\n## Irreversible Git & Filesystem Actions — DO NOT EVER BREAK GLASS\n\n> **Note:** This project exists specifically to block these dangerous commands for AI agents. Practice what we preach.\n\n1. **Absolutely forbidden commands:** `git reset --hard`, `git clean -fd`, `rm -rf`, or any command that can delete or overwrite code/data must never be run unless the user explicitly provides the exact command and states, in the same message, that they understand and want the irreversible consequences.\n2. **No guessing:** If there is any uncertainty about what a command might delete or overwrite, stop immediately and ask the user for specific approval. \"I think it's safe\" is never acceptable.\n3. **Safer alternatives first:** When cleanup or rollbacks are needed, request permission to use non-destructive options (`git status`, `git diff`, `git stash`, copying to backups) before ever considering a destructive command.\n4. **Mandatory explicit plan:** Even after explicit user authorization, restate the command verbatim, list exactly what will be affected, and wait for a confirmation that your understanding is correct. Only then may you execute it—if anything remains ambiguous, refuse and escalate.\n5. **Document the confirmation:** When running any approved destructive command, record (in the session notes / final response) the exact user text that authorized it, the command actually run, and the execution time. If that record is absent, the operation did not happen.\n\n---\n\n## Git Branch: ONLY Use `main`, NEVER `master`\n\n**The default branch is `main`. The `master` branch exists only for legacy URL compatibility.**\n\n- **All work happens on `main`** — commits, PRs, feature branches all merge to `main`\n- **Never reference `master` in code or docs** — if you see `master` anywhere, it's a bug that needs fixing\n- **The `master` branch must stay synchronized with `main`** — after pushing to `main`, also push to `master`:\n  ```bash\n  git push origin main:master\n  ```\n\n**Why this matters:** The `dcg update` command and install URLs historically referenced `master`. If `master` falls behind `main`, users get stale code. We had a bug where `master` was **497 commits behind**, causing users to see old installer behavior.\n\n**If you see `master` referenced anywhere:**\n1. Update it to `main`\n2. Ensure `master` is synchronized: `git push origin main:master`\n\n---\n\n## Toolchain: Rust & Cargo\n\nWe only use **Cargo** in this project, NEVER any other package manager.\n\n- **Edition:** Rust 2024 (nightly required — see `rust-toolchain.toml`)\n- **Dependency versions:** Explicit versions for stability\n- **Configuration:** Cargo.toml only (single crate, not a workspace)\n- **Unsafe code:** Forbidden (`#![forbid(unsafe_code)]`)\n\n### Key Dependencies\n\n| Crate | Purpose |\n|-------|---------|\n| `serde` + `serde_json` | JSON parsing for Claude Code hook protocol |\n| `serde_yaml` | External pack YAML parsing |\n| `toml` + `toml_edit` | TOML config parsing with formatting preservation |\n| `fancy-regex` | Advanced regex with lookahead/lookbehind |\n| `regex` | `RegexSet` for heredoc detection |\n| `memchr` | SIMD-accelerated substring search |\n| `aho-corasick` | Multi-pattern string matching for keyword quick-reject |\n| `colored` | Terminal colors with TTY detection |\n| `clap` + `clap_complete` | CLI argument parsing with shell completions |\n| `chrono` | RFC 3339 timestamps |\n| `ast-grep-core` + `ast-grep-language` | AST-based pattern matching for heredoc/inline-script content |\n| `rusqlite` | Bundled upstream SQLite for best-effort telemetry history |\n| `rust-mcp-sdk` | MCP server integration (stdio transport) |\n| `tokio` | Async runtime for MCP server mode |\n| `ratatui` + `comfy-table` + `indicatif` + `console` | TUI/CLI visual polish |\n| `self_update` | Binary self-update from GitHub Releases |\n| `vergen-gix` | Build metadata embedding (build.rs) |\n| `tracing` + `tracing-subscriber` | Structured logging and diagnostics |\n| `sha2` + `hmac` | Hashing and HMAC for allow-once short codes |\n| `flate2` | Gzip compression for history export |\n\n### Release Profile\n\nThe release build optimizes for binary size:\n\n```toml\n[profile.release]\nopt-level = \"z\"     # Optimize for size (lean binary for distribution)\nlto = true          # Link-time optimization\ncodegen-units = 1   # Single codegen unit for better optimization\npanic = \"abort\"     # Smaller binary, no unwinding overhead\nstrip = true        # Remove debug symbols\n```\n\n### Feature Flags\n\n```toml\n[features]\nrayon = [\"dep:rayon\"]           # Rayon data parallelism (optional)\nrich-output = [\"dep:rich_rust\"] # Enable rich_rust for premium terminal output\nlegacy-output = []              # Keep old rendering (placeholder for gradual migration)\n```\n\n---\n\n## Code Editing Discipline\n\n### No Script-Based Changes\n\n**NEVER** run a script that processes/changes code files in this repo. Brittle regex-based transformations create far more problems than they solve.\n\n- **Always make code changes manually**, even when there are many instances\n- For many simple changes: use parallel subagents\n- For subtle/complex changes: do them methodically yourself\n\n### No File Proliferation\n\nIf you want to change something or add a feature, **revise existing code files in place**.\n\n**NEVER** create variations like:\n- `mainV2.rs`\n- `main_improved.rs`\n- `main_enhanced.rs`\n\nNew files are reserved for **genuinely new functionality** that makes zero sense to include in any existing file. The bar for creating new files is **incredibly high**.\n\n---\n\n## Backwards Compatibility\n\nWe do not care about backwards compatibility—we're in early development with no users. We want to do things the **RIGHT** way with **NO TECH DEBT**.\n\n- Never create \"compatibility shims\"\n- Never create wrapper functions for deprecated APIs\n- Just fix the code directly\n\n---\n\n## Compiler Checks (CRITICAL)\n\n**After any substantive code changes, you MUST verify no errors were introduced:**\n\n```bash\n# Check for compiler errors and warnings\ncargo check --all-targets\n\n# Check for clippy lints (pedantic + nursery are enabled)\ncargo clippy --all-targets -- -D warnings\n\n# Verify formatting\ncargo fmt --check\n```\n\nIf you see errors, **carefully understand and resolve each issue**. Read sufficient context to fix them the RIGHT way.\n\n---\n\n## Windows Support (native, `x86_64-pc-windows-msvc`)\n\ndcg ships a **native Windows** binary (built/tested on `windows-latest` with the\nnightly toolchain) and a `check (windows)` CI job. When touching anything\nplatform-sensitive, follow these conventions:\n\n- **Separate command-pattern DATA from dcg's own paths.** Destructive-command\n  patterns (`rm -rf /`, `normalize.rs` stripping `/usr/bin/git`, `/etc`, `/tmp`)\n  are DATA about Unix commands and must STAY — Windows users still run git-bash.\n  Only dcg's *own* config/state paths get Windows-ified (resolve via the `dirs`\n  crate; the system layer is `%ProgramData%\\dcg`, helper `config::system_config_dir()`).\n- **`.exe` suffix.** When constructing a path to the dcg binary, use\n  `env!(\"CARGO_BIN_EXE_dcg\")` / `assert_cmd::cargo::cargo_bin(\"dcg\")` in tests, or\n  `std::env::consts::EXE_SUFFIX` in `src`. **Never** a bare `push(\"dcg\")` — the\n  Windows CI job greps for it and fails. Use `dirs::home_dir()` (not `HOME`,\n  which is unset on Windows) and set `USERPROFILE`/`TEMP`/`TMP` alongside `HOME`\n  in test isolation.\n- **Verify Windows branches from Linux** without a Windows box: `mingw` + the\n  `x86_64-pc-windows-gnu` target are installed, so\n  `cargo check --target x86_64-pc-windows-gnu --lib` (or `--bin dcg` / `--tests`)\n  compile-checks every `#[cfg(windows)]` path. When `pwsh` is installed, use it\n  to run the PowerShell installer/test scripts; otherwise run those gates on the\n  native Windows release host.\n- **Windows packs.** `src/packs/windows/` holds the native-Windows packs\n  (`windows.filesystem`/`windows.system` default-ON on Windows, `windows.misc`/\n  `windows.powershell` opt-in). Patterns use inline `(?i)`; keyword arrays\n  may retain conventional casing variants for readability, but keyword\n  quick-rejection is ASCII case-insensitive so mixed-case Windows spellings\n  cannot skip the regex stage (see `src/packs/windows/mod.rs`). See\n  [`docs/windows.md`](docs/windows.md).\n- **The `careful_company_running_windows` preset.**\n  `src/packs/careful_company_running_windows/` holds six opt-in sub-packs\n  covering **outbound communication and data egress** (email, chat/webhooks,\n  HTTP upload, file transfer, tunnels) plus **tampering with the controls that\n  supervise the agent** (Defender/firewall/EDR, audit logs, and dcg's own\n  bypass/uninstall). It is the only pack ID with *curated transitive\n  membership*: enabling it also enables the pinned\n  `CAREFUL_COMPANY_PRESET_MEMBERS` list in `src/packs/mod.rs`\n  (`windows.*`, `database.*`, `storage.*`, `remote.*`, `backup.*`, `secrets.*`,\n  `cloud.*`). That list is deliberately explicit — do **not** convert it to\n  prefix matching, or future packs will join a security posture silently.\n  Two invariants to preserve when touching this area:\n  - **Tier order.** `windows.*` is tier 11 and the preset is tier 12, so\n    Windows packs keep claiming attribution for commands both match. Rule ids\n    (`pack_id:pattern_name`) are what allowlists key on, so reordering these\n    silently invalidates existing `windows.*` allowlist entries.\n  - **The `hfdt` trust boundary.** While any preset sub-pack is enabled,\n    `src/evaluator.rs` allows a command whose executable is `hfdt` **before any\n    pack runs** — including `core.*`. It is structural (whole-segment\n    executable match, no chains/redirection/substitution), but it does mean\n    enabling the preset *reduces* coverage for that one executable. Keep it\n    documented in `README.md` and `docs/careful-company-windows.md`.\n\n---\n\n## Testing\n\n### Testing Policy\n\nEvery module includes inline `#[cfg(test)]` unit tests alongside the implementation. Tests must cover:\n- Happy path\n- Edge cases (empty input, max values, boundary conditions)\n- Error conditions\n\nEnd-to-end tests live in `scripts/e2e_test.sh`.\n\n### Unit Tests\n\nThe test suite includes 80+ tests covering all functionality:\n\n```bash\n# Run all tests\ncargo test\n\n# Run with output\ncargo test -- --nocapture\n\n# Run specific test module\ncargo test normalize_command_tests\ncargo test safe_pattern_tests\ncargo test destructive_pattern_tests\n```\n\n### The Three Release-Blocking E2E Suites (read before touching perf or protocols)\n\n`cargo test` cannot catch the failure modes that have actually broken users.\nThree real-binary, no-mock suites exist specifically to close those gaps. All\nthree must be green before any release.\n\n| Suite | Catches | Why unit tests can't |\n|-------|---------|----------------------|\n| `scripts/e2e_harness_matrix.sh` | Wire-protocol breakage for **every** agent (Claude Code, Codex, Gemini, Copilot, Hermes, Grok, agy) | Unit tests call Rust functions; harnesses parse **bytes**. Asserts decision field + exit code + stdout/stderr separation per protocol against the real binary. |\n| `scripts/perf_baseline.py --assert-budget-ms` | **#245**: per-invocation cost silently eating the fixed hook deadline | The perf job is a *relative* ratchet — a uniform slowdown just gets re-baselined. This gate asserts cold p95 against the **shipped** `HOOK_EVALUATION_BUDGET_MS` with a hermetic HOME and scrubbed `DCG_*`. |\n| `scripts/e2e_fleet_install.sh` | Published artifact missing/unrunnable per platform; installer picking the wrong triple; checksum/signature verification silently skipped; hook config non-idempotent | Nothing in-tree proves the **public download path** works on real Linux/macOS/Windows hardware. |\n\n```bash\n# Protocol conformance for all 7 harnesses (needs a release binary + jq)\n./scripts/e2e_harness_matrix.sh --binary target/release/dcg\n\n# Absolute latency gate — the #245 guard. Budget MUST come from src/perf.rs.\npython3 scripts/perf_baseline.py --bin target/release/dcg --skip-trace \\\n  --assert-budget-ms 1000 --assert-margin-pct 50\n\n# Real installs from the PUBLIC release on every DSR host\n./scripts/e2e_fleet_install.sh --version vX.Y.Z          # whole fleet\n./scripts/e2e_fleet_install.sh --version vX.Y.Z --local-only\n```\n\nRules:\n- **Scrub ambient `DCG_*` before measuring anything.** Operators bitten by #245\n  export `DCG_HOOK_TIMEOUT_MS=5000` (an agent `settings.json` `env` block puts\n  it in every child process), so an un-scrubbed suite measures the *workaround*\n  and passes on exactly the machines that need protecting. `env -i` covers the\n  hook calls; the installer cannot use it (it needs the host PATH for\n  `curl`/`tar`/`xz`/`minisign`), so the probes also `unset` every `DCG_*` up\n  front. Assert `general.hook_timeout_source` too — a bare `>= 1000` check\n  cannot tell the shipped default from an inherited 5000.\n- **Set `DCG_SELF_HEAL_HOOK=0` before the installer runs, not after.** dcg\n  repairs a missing/stale hook entry whenever it runs in hook mode, and native\n  Windows resolves the settings path via the Win32 known-folder API, which\n  `USERPROFILE` cannot redirect — so a late disable can rewrite a real\n  machine's agent config.\n- **Never hard-code the budget in `.github/workflows/ci.yml`.** It is grepped\n  out of `HOOK_EVALUATION_BUDGET_MS`; `perf::tests::ci_enforces_absolute_latency_gate_against_shipped_budget`\n  fails if that wiring is removed or the margin is loosened past 60%.\n- Measure dcg's own cost as `full_eval − DCG_BYPASS`, never raw wall-clock:\n  process spawn (≈940ms under Windows PowerShell) sits **outside** the\n  evaluation deadline and would otherwise produce false alarms.\n- The fleet suite installs into a scratch prefix with an isolated `HOME` and\n  `--no-configure`; it never touches a host's real agent hook config.\n- A probe that dies partway must FAIL, not pass: every probe emits\n  `probe_complete` and the runner asserts the full expected case set.\n\n### End-to-End Testing\n\n```bash\n# Run the E2E test script (needs bash >= 4; macOS /bin/bash 3.2 breaks the summary)\n./scripts/e2e_test.sh\n\n# Or test manually\necho '{\"tool_name\":\"Bash\",\"tool_input\":{\"command\":\"git reset --hard\"}}' | cargo run --release\n# Should output JSON denial\n\necho '{\"tool_name\":\"Bash\",\"tool_input\":{\"command\":\"git status\"}}' | cargo run --release\n# Should output nothing (allowed)\n```\n\n### Test Categories\n\n| Module | Tests | Purpose |\n|--------|-------|---------|\n| `normalize_command_tests` | 8 | Path stripping for git/rm binaries |\n| `quick_reject_tests` | 5 | Fast-path filtering for non-git/rm commands |\n| `safe_pattern_tests` | 16 | Whitelist accuracy |\n| `destructive_pattern_tests` | 20 | Blacklist coverage |\n| `input_parsing_tests` | 8 | JSON parsing robustness |\n| `deny_output_tests` | 2 | Output format validation |\n| `integration_tests` | 4 | End-to-end pipeline |\n| `optimization_tests` | 9 | Performance paths |\n| `edge_case_tests` | 24 | Real-world edge cases |\n\n---\n\n## Third-Party Library Usage\n\nIf you aren't 100% sure how to use a third-party library, **SEARCH ONLINE** to find the latest documentation and current best practices.\n\n---\n\n## dcg (Destructive Command Guard) — This Project\n\n**This is the project you're working on.** dcg is a high-performance Claude Code hook that blocks destructive commands before they execute. It protects against dangerous git commands, filesystem operations, database queries, container commands, and more through a modular pack system.\n\n### What It Does\n\nGuards AI coding agents from executing destructive commands by intercepting Claude Code's `PreToolUse` hook protocol, evaluating commands against safe/destructive pattern lists, and denying dangerous operations with structured JSON output including remediation suggestions.\n\n### Architecture\n\n```\nJSON Input → Parse → Quick Reject (memchr) → Normalize → Safe Patterns → Destructive Patterns → Default Allow\n```\n\n### Key Files\n\n| File | Purpose |\n|------|---------|\n| `src/main.rs` | Entry point, hook I/O, CLI dispatch |\n| `src/evaluator.rs` | Pattern matching engine (safe + destructive evaluation) |\n| `src/hook.rs` | Claude Code PreToolUse hook protocol handling |\n| `src/normalize.rs` | Command normalization (path stripping, alias expansion) |\n| `src/heredoc.rs` | Heredoc and inline script extraction |\n| `src/ast_matcher.rs` | AST-based pattern matching for embedded code |\n| `src/config.rs` | Configuration loading (TOML, allowlists, pack enable/disable) |\n| `src/allowlist.rs` | Allowlist management (project, user, system scopes) |\n| `src/cli.rs` | CLI commands (explain, scan, packs, allowlist, etc.) |\n| `src/scan.rs` | Codebase scanning for destructive patterns |\n| `src/context.rs` | Contextual analysis for pattern matching |\n| `src/confidence.rs` | Match confidence scoring |\n| `src/error_codes.rs` | Standardized DCG-XXXX error codes |\n| `src/exit_codes.rs` | Process exit code definitions |\n| `src/packs/` | Modular pattern pack system (core + extensions) |\n| `src/output/` | Output formatting (JSON, colorful stderr) |\n| `src/highlight.rs` | Syntax highlighting for command display |\n| `src/logging.rs` | Tracing/logging configuration |\n| `src/perf.rs` | Performance budgets and benchmarks |\n| `src/simulate.rs` | Command simulation and dry-run support |\n| `src/mcp.rs` | MCP server integration |\n| `src/agent.rs` | Agent detection and identification |\n| `src/interactive.rs` | Interactive mode |\n| `src/git.rs` | Git-specific command analysis |\n| `src/history/` | Decision history and telemetry |\n| `src/sarif.rs` | SARIF output format for scan results |\n| `src/pending_exceptions.rs` | Pending exception management |\n| `src/lib.rs` | Library re-exports |\n| `Cargo.toml` | Dependencies and release optimizations |\n| `build.rs` | Build script for version metadata (vergen) |\n| `rust-toolchain.toml` | Nightly toolchain requirement |\n| `scripts/e2e_test.sh` | End-to-end test script (hundreds of command scenarios) |\n\n### Output Style\n\nThis tool has two output modes:\n\n- **JSON to stdout:** For Claude Code hook protocol (`hookSpecificOutput` with `permissionDecision: \"deny\"`)\n- **Colorful warning to stderr:** For human visibility when commands are blocked\n\nOutput behavior:\n- **Deny:** Colorful warning to stderr + JSON to stdout\n- **Allow:** No output (silent exit)\n- **--version/-V:** Version info with build metadata to stderr\n- **--help/-h:** Usage information to stderr\n\nColors are automatically disabled when stderr is not a TTY (e.g., piped to file).\n\n### Pattern System\n\n- **34 safe patterns** (whitelist, checked first)\n- **16 destructive patterns** (blacklist, checked second)\n- **Default allow** for unmatched commands\n\n### Adding New Patterns\n\n1. Identify the command to block/allow\n2. Write a regex using `fancy-regex` syntax (supports lookahead/lookbehind)\n3. Add to `SAFE_PATTERNS` or `DESTRUCTIVE_PATTERNS` using the macros:\n\n```rust\n// Safe pattern (whitelist)\npattern!(\"pattern-name\", r\"regex-here\")\n\n// Destructive pattern (blacklist)\ndestructive!(\n    r\"regex-here\",\n    \"Human-readable reason for blocking\"\n)\n```\n\n4. Add tests for all variants\n5. Run `cargo test` and `./scripts/e2e_test.sh`\n\n### Performance Requirements\n\nEvery Bash command passes through this hook. Performance is critical:\n\n- Quick rejection filter eliminates 99%+ of commands before regex\n- Lazy-initialized static regex patterns (compiled once, reused)\n- Sub-millisecond execution for typical commands\n- Zero allocations on the hot path for safe commands\n\n### Heredoc Detection Notes\n\n- **Rule IDs**: Heredoc patterns use stable IDs like `heredoc.python.shutil_rmtree` for allowlisting.\n- **Bounded failure**: Heredoc parse/AST failures use the configured bounded\n  fallback; disabling fallback blocks. Absolute hook-deadline exhaustion and\n  incomplete nested evaluation return `Indeterminate`, never `Allow`.\n- **Tests**: Prefer targeted tests in `src/ast_matcher.rs` and `src/heredoc.rs`.\n  - `cargo test ast_matcher`\n  - `cargo test heredoc`\n  - Add positive and negative fixtures for each new pattern.\n\n---\n\n<!-- dcg-machine-readable-v1 -->\n\n## DCG Hook Protocol (Machine-Readable Reference)\n\n> This section provides structured documentation for AI agents integrating with dcg.\n\n### JSON Input Format\n\ndcg reads from stdin in Claude Code's `PreToolUse` hook format:\n\n```json\n{\n  \"tool_name\": \"Bash\",\n  \"tool_input\": {\n    \"command\": \"git reset --hard HEAD~5\"\n  }\n}\n```\n\n**Required fields:**\n- `tool_name`: Must be `\"Bash\"` for dcg to process (other tools are ignored)\n- `tool_input.command`: The shell command string to evaluate\n\n### JSON Output Format (Denial)\n\nWhen a command is blocked, dcg outputs JSON to stdout:\n\n```json\n{\n  \"hookSpecificOutput\": {\n    \"hookEventName\": \"PreToolUse\",\n    \"permissionDecision\": \"deny\",\n    \"permissionDecisionReason\": \"BLOCKED by dcg\\n\\nTip: dcg explain \\\"git reset --hard HEAD~5\\\"\\n\\nReason: git reset --hard destroys uncommitted changes\\n\\nExplanation: Rewrites history and discards uncommitted changes.\\n\\nRule: core.git:reset-hard\\n\\nIf this operation is truly needed, ask the user for explicit permission and have them run the command manually.\",\n    \"ruleId\": \"core.git:reset-hard\",\n    \"packId\": \"core.git\",\n    \"severity\": \"critical\",\n    \"confidence\": 0.95,\n    \"allowOnceCode\": \"a1b2c3\",\n    \"allowOnceFullHash\": \"sha256:abc123...\",\n    \"remediation\": {\n      \"safeAlternative\": \"git stash\",\n      \"explanation\": \"Use git stash to save your changes first.\",\n      \"allowOnceCommand\": \"dcg allow-once a1b2c3\"\n    }\n  }\n}\n```\n\n**Key fields for agent parsing:**\n| Field | Type | Description |\n|-------|------|-------------|\n| `permissionDecision` | `\"allow\"` \\| `\"deny\"` | The decision |\n| `ruleId` | `string` | Stable pattern ID (e.g., `\"core.git:reset-hard\"`) for allowlisting |\n| `packId` | `string` | Pack that matched (e.g., `\"core.git\"`) |\n| `severity` | `string` | `\"critical\"`, `\"high\"`, `\"medium\"`, or `\"low\"` |\n| `confidence` | `number` | Match confidence 0.0-1.0 |\n| `allowOnceCode` | `string` | Short code for `dcg allow-once` |\n| `remediation.safeAlternative` | `string?` | Suggested safe command |\n\n### JSON Output Format (Allow)\n\nWhen a command is allowed: **no output** (silent exit 0).\n\n---\n\n## Exit Codes Reference\n\n| Code | Meaning | Agent Action |\n|------|---------|--------------|\n| `0` | Command allowed OR protocol JSON denial was emitted | Parse stdout; if empty, command was allowed |\n| `1` | Parse error or invalid input | Retry with corrected input |\n| `2` | Configuration error | Check config syntax and stderr diagnostics |\n\n**Detection logic for agents:**\n```bash\noutput=$(echo \"$hook_input\" | dcg 2>/dev/null)\nif [ -z \"$output\" ]; then\n  echo \"ALLOWED\"\nelse\n  echo \"DENIED: $output\"\nfi\n```\n\nCodex CLI uses a stricter hook parser: blocked commands return a minimal\n`hookSpecificOutput` denial on stdout with exit code 0. See\n[`docs/codex-integration.md`](docs/codex-integration.md) for the Codex-specific\nprotocol notes.\n\n---\n\n## Error Codes Reference\n\nDCG uses standardized error codes in the format `DCG-XXXX` for machine-parseable error handling.\n\n### Error Categories\n\n| Range | Category | Description |\n|-------|----------|-------------|\n| DCG-1xxx | `pattern_match` | Pattern matching and evaluation errors |\n| DCG-2xxx | `configuration` | Configuration loading and parsing errors |\n| DCG-3xxx | `runtime` | Runtime and execution errors |\n| DCG-4xxx | `external` | External integration errors |\n\n### Common Error Codes\n\n| Code | Description | Typical Cause |\n|------|-------------|---------------|\n| `DCG-1001` | Pattern compilation failed | Invalid regex syntax in pattern |\n| `DCG-1002` | Pattern match timeout | Complex pattern taking too long |\n| `DCG-2001` | Config file not found | Missing configuration file |\n| `DCG-2002` | Config parse error | Invalid TOML/JSON syntax |\n| `DCG-2004` | Allowlist load error | Invalid allowlist file |\n| `DCG-3001` | JSON parse error | Malformed JSON input |\n| `DCG-3002` | IO error | File read/write failure |\n| `DCG-4001` | External pack load failed | Invalid external pack YAML |\n\n### Error JSON Structure\n\nWhen errors are returned in JSON format, they follow this structure:\n\n```json\n{\n  \"error\": {\n    \"code\": \"DCG-3001\",\n    \"category\": \"runtime\",\n    \"message\": \"JSON parse error: unexpected token at position 15\",\n    \"context\": {\n      \"position\": 15,\n      \"input_preview\": \"{ \\\"tool_name\\\": ...\"\n    }\n  }\n}\n```\n\n**Fields:**\n- `code`: Stable error code for programmatic handling\n- `category`: Error category (`pattern_match`, `configuration`, `runtime`, `external`)\n- `message`: Human-readable error description\n- `context`: Additional details (optional, varies by error type)\n\n---\n\n## Allowlist & Bypass Instructions\n\n### Temporary Bypass (24-hour allow-once)\n\nWhen a command is blocked, the output includes an `allowOnceCode`. Use it:\n\n```bash\ndcg allow-once <code>\n```\n\nThis allows the specific command for 24 hours in the current directory scope.\n\n### Permanent Allowlist (by rule ID)\n\nAdd a rule to the project allowlist:\n\n```bash\ndcg allowlist add <ruleId> --project\n# Example: dcg allowlist add core.git:reset-hard --project\n```\n\nAllowlist files (in priority order):\n1. `.dcg/allowlist.toml` (project)\n2. `~/.config/dcg/allowlist.toml` (user)\n3. `/etc/dcg/allowlist.toml` (system)\n\n### Bypass Environment Variable\n\nFor emergency bypass (use sparingly):\n\n```bash\nDCG_BYPASS=1 <command>\n```\n\n**Warning:** This disables all protection. Log and justify any usage.\n\n---\n\n## Pattern Quick Reference\n\n### Core Git Patterns (Always Enabled)\n\n| Pattern ID | Blocks | Severity |\n|------------|--------|----------|\n| `core.git:reset-hard` | `git reset --hard` | Critical |\n| `core.git:reset-merge` | `git reset --merge` | High |\n| `core.git:checkout-discard` | `git checkout -- <file>` | High |\n| `core.git:restore-discard` | `git restore <file>` (without `--staged`) | High |\n| `core.git:clean-force` | `git clean -f`, `git clean -fd` | High |\n| `core.git:force-push` | `git push --force`, `git push -f` | High |\n| `core.git:branch-force-delete` | `git branch -d`, `--delete`, `-D`, `-f`, `-M`, `-C` | High |\n| `core.git:stash-drop` | `git stash drop`, `git stash clear` | High |\n\n### Core Filesystem Patterns (Always Enabled)\n\n| Pattern ID | Blocks | Severity |\n|------------|--------|----------|\n| `core.filesystem:rm-rf-root` | `rm -rf /`, `rm -rf ~` | Critical |\n| `core.filesystem:rm-rf-general` | `rm -rf` outside temp dirs | High |\n\n### Safe Patterns (Whitelist - Always Allowed)\n\n| Pattern | Command | Why Safe |\n|---------|---------|----------|\n| `git-checkout-branch` | `git checkout -b <branch>` | Creates new branch |\n| `git-checkout-orphan` | `git checkout --orphan <branch>` | Creates orphan branch |\n| `git-restore-staged` | `git restore --staged <file>` | Only unstages, doesn't discard |\n| `git-clean-dry-run` | `git clean -n`, `git clean --dry-run` | Preview only |\n| `rm-tmp` | `rm -rf /tmp/*`, `/var/tmp/*` | Temp directory cleanup |\n\n### Pack Enable/Disable Examples\n\n```toml\n# ~/.config/dcg/config.toml\n[packs]\nenabled = [\n    \"database.postgresql\",    # Blocks DROP TABLE, TRUNCATE\n    \"kubernetes.kubectl\",     # Blocks kubectl delete namespace\n    \"cloud.aws\",              # Blocks aws ec2 terminate-instances\n]\n\ndisabled = [\n    \"containers.docker\",      # Disable Docker protection\n]\n```\n\nList all packs: `dcg packs --verbose`\n\n---\n\n## CLI Quick Reference for Agents\n\n| Command | Purpose |\n|---------|---------|\n| `dcg explain \"<command>\"` | Detailed trace of why command is blocked/allowed |\n| `dcg allow-once <code>` | Allow a blocked command for 24 hours |\n| `dcg allowlist add <ruleId> --project` | Permanently allow a rule |\n| `dcg packs` | List enabled packs |\n| `dcg packs --verbose` | List all packs with pattern counts |\n| `dcg scan .` | Scan codebase for destructive patterns |\n| `dcg --version` | Show version and build info |\n\n---\n\n## Agent Integration Checklist\n\nWhen integrating with dcg, ensure your agent:\n\n- [ ] Parses stdout for JSON denial responses\n- [ ] Handles empty stdout as \"command allowed\"\n- [ ] Uses `ruleId` for stable allowlisting (not pattern text)\n- [ ] Displays `remediation.safeAlternative` to users when available\n- [ ] Respects `severity` for prioritization (critical > high > medium > low)\n- [ ] Uses `dcg explain` before asking users to bypass\n\n---\n\n## JSON Schema Reference\n\nFormal JSON Schema definitions (Draft 2020-12) for all dcg output formats are available in `docs/json-schema/`:\n\n| Schema | Purpose |\n|--------|---------|\n| [`hook-output.json`](docs/json-schema/hook-output.json) | PreToolUse hook denial response format |\n| [`scan-results.json`](docs/json-schema/scan-results.json) | `dcg scan` command output format |\n| [`stats-output.json`](docs/json-schema/stats-output.json) | `dcg stats` command output format |\n| [`error.json`](docs/json-schema/error.json) | Error response formats for various commands |\n\nUse these schemas for:\n- Validating dcg output in automated pipelines\n- Generating type-safe client code\n- Understanding the complete output contract\n\n<!-- end-dcg-machine-readable -->\n\n---\n\n## CI/CD Pipeline\n\n### Jobs Overview\n\n| Job | Trigger | Purpose | Blocking |\n|-----|---------|---------|----------|\n| `check` | PR, push | Format, clippy, UBS, tests | Yes |\n| `coverage` | PR, push | Coverage thresholds | Yes |\n| `memory-tests` | PR, push | Memory leak detection | Yes |\n| `benchmarks` | push to main | Performance budgets | Warn only |\n| `e2e` | PR, push | End-to-end shell tests | Yes |\n| `scan-regression` | PR, push | Scan output stability | Yes |\n| `perf-regression` | PR, push | Process-per-invocation perf | Yes |\n\n### Check Job\n\nRuns format, clippy, UBS static analysis, and unit tests. Includes:\n- `cargo fmt --check` - Code formatting\n- `cargo clippy --all-targets -- -D warnings` - Lints (pedantic + nursery enabled)\n- UBS analysis on changed Rust files (warning-only, non-blocking)\n- `cargo nextest run` - Full test suite with JUnit XML report\n\n### Coverage Job\n\nRuns `cargo llvm-cov` and enforces the thresholds configured in\n`.github/workflows/ci.yml` (`OVERALL_MIN`, `EVALUATOR_MIN`, `HOOK_MIN`).\nThese are enforced gates, not aspirational targets:\n- **Overall:** >= 70%\n- **src/evaluator.rs:** >= 65%\n- **src/hook.rs:** >= 70%\n\nIf CI thresholds change, update this section in the same change. The\n`coverage_threshold_docs` test checks that these documented values stay in sync\nwith the workflow.\n\nCoverage is uploaded to Codecov for trend tracking. Dashboard: https://codecov.io/gh/Dicklesworthstone/destructive_command_guard\n\n### Memory Tests Job\n\nRuns dedicated memory leak tests with:\n- `--test-threads=1` for accurate measurements\n- Release mode for realistic performance\n- 1-2MB growth budgets per test\n\nTests include: hook input parsing, pattern evaluation, heredoc extraction, file extractors, full pipeline, and a self-test that verifies the framework catches leaks.\n\n### Benchmarks Job\n\nRuns on push to main only (benchmarks are noisy on PRs). Checks performance budgets from `src/perf.rs`:\n- Quick reject: < 50us panic\n- Fast path: < 500us panic\n- Pattern match: < 1ms panic\n- Heredoc extract: < 2ms panic\n- Full heredoc pipeline: < 20ms panic\n- Hook evaluation deadline: 1000ms (exhaustion is indeterminate, never a silent allow)\n\n### UBS Static Analysis\n\nUltimate Bug Scanner runs on changed Rust files. Currently warning-only (non-blocking) to tune for false positives. Configuration in `.ubsignore` excludes test/bench/fuzz directories.\n\n### Dependabot\n\nAutomated dependency updates configured in `.github/dependabot.yml`:\n- **Cargo dependencies:** Weekly (Monday 9am EST), 5 PR limit\n- **GitHub Actions:** Weekly (Monday 9am EST), 3 PR limit\n- **Grouping:** Minor/patch updates grouped; serde updates separate (more careful review)\n\n### Debugging CI Failures\n\n#### Coverage Threshold Failure\n1. Check which file(s) dropped below threshold in CI output\n2. Run `cargo llvm-cov --html` locally to see uncovered lines\n3. Add tests for uncovered code paths\n4. Download `coverage-report` artifact for full details\n\n#### Memory Test Failure\n1. Download `memory-test-output` artifact\n2. Check which test failed and growth amount\n3. Run locally: `cargo test --test memory_tests --release -- --nocapture --test-threads=1`\n4. Profile with valgrind if needed\n\n#### UBS Warnings\n1. Check ubs-output.log in CI summary\n2. Review flagged issues - may be false positives\n3. If valid issues, fix them; if false positives, add to `.ubsignore`\n\n#### E2E Test Failure\n1. Download `e2e-artifacts` artifact\n2. Check `e2e_output.json` for failing test details\n3. Run locally: `./scripts/e2e_test.sh --verbose`\n4. The step summary shows the first failure with output\n\n#### Benchmark Regression\n1. Download `benchmark-results` artifact\n2. Compare against budgets in `src/perf.rs`\n3. Profile locally with `cargo bench --bench heredoc_perf`\n4. Check for algorithmic regressions in hot path\n\n---\n\n## Release Process\n\nWhen fixes are ready for release, follow this process:\n\nThe steps below describe the normal GitHub Actions path. If Actions cannot run\nor a native Windows artifact must be built locally, the more detailed\n**Local/DSR Release and Windows Deployment Runbook** near the end of this file\nis authoritative.\n\n### 1. Verify CI Passes Locally\n\n```bash\ncargo fmt --check\ncargo check --all-targets\ncargo clippy --all-targets -- -D warnings\ncargo test\n```\n\n### 2. Commit Changes\n\n```bash\ngit add -A\ngit commit -m \"fix: description of fixes\n\n- List specific fixes\n- Include any breaking changes\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\"\n```\n\n### 3. Bump Version (if needed)\n\nThe version in `Cargo.toml` determines the release tag. A version may be reused\nafter a failed *local, pre-tag* attempt. Once its tag has been pushed or a\nrelease has been published, treat that version as immutable and bump to a new\npatch version instead of moving the tag or replacing signed assets.\n\n- **Patch** (0.2.10 -> 0.2.11): Bug fixes, no new features\n- **Minor** (0.2.x -> 0.3.0): New features, backward compatible\n- **Major** (0.x -> 1.0): Breaking changes\n\n### 4. Push and Trigger Release\n\n```bash\ngit push origin main\ngit push origin main:master  # Keep master in sync\n```\n\nThe `release-automation.yml` workflow will:\n1. Detect version change in `Cargo.toml`\n2. Create an annotated git tag (e.g., `v0.2.13`)\n3. Push the tag, which triggers `dist.yml`\n\nThe `dist.yml` workflow will:\n1. Run tests and clippy\n2. Build binaries for all platforms (Linux x86/ARM, macOS Intel/Apple Silicon, Windows)\n3. Create `.tar.xz` archives with SHA256 checksums\n4. Sign artifacts with Sigstore (cosign) - creates `.sigstore.json` bundles\n5. Upload everything to GitHub Releases\n\n### 5. Verify Release\n\n```bash\ngh release list --limit 5\ngh release view v0.2.13  # Check assets were uploaded\n```\n\nExpected assets per release:\n- `dcg-{target}.tar.xz` (Unix) or `.zip` (Windows) - Binary archive\n- `<archive>.sha256` - Mandatory per-artifact checksum\n- `<archive>.sigstore.json` - Sigstore signature bundle\n- `install.sh`, `install.ps1`, and their checksum/Sigstore sidecars\n- Manual DSR releases additionally include minisign signatures, SLSA\n  provenance, a build manifest, and the pinned public verification keys\n\n### Troubleshooting Failed Releases\n\nIf CI fails:\n1. Check workflow run: `gh run list --workflow=dist.yml --limit=5`\n2. View failed job: `gh run view <run-id>`\n3. Fix issues locally, commit, and push again\n4. If no public tag or release exists yet, retry the same version; otherwise\n   create a new patch release. Never force-move a public release tag.\n\nCommon failures:\n- **Clippy errors**: Fix lints, ensure `cargo clippy -- -D warnings` passes\n- **Test failures**: Run `cargo test` to reproduce\n- **Format errors**: Run `cargo fmt` to fix\n\n---\n\n## MCP Agent Mail — Multi-Agent Coordination\n\nA mail-like layer that lets coding agents coordinate asynchronously via MCP tools and resources. Provides identities, inbox/outbox, searchable threads, and advisory file reservations with human-auditable artifacts in Git.\n\n### Why It's Useful\n\n- **Prevents conflicts:** Explicit file reservations (leases) for files/globs\n- **Token-efficient:** Messages stored in per-project archive, not in context\n- **Quick reads:** `resource://inbox/...`, `resource://thread/...`\n\n### Same Repository Workflow\n\n1. **Register identity:**\n   ```\n   ensure_project(project_key=<abs-path>)\n   register_agent(project_key, program, model)\n   ```\n\n2. **Reserve files before editing:**\n   ```\n   file_reservation_paths(project_key, agent_name, [\"src/**\"], ttl_seconds=3600, exclusive=true)\n   ```\n\n3. **Communicate with threads:**\n   ```\n   send_message(..., thread_id=\"FEAT-123\")\n   fetch_inbox(project_key, agent_name)\n   acknowledge_message(project_key, agent_name, message_id)\n   ```\n\n4. **Quick reads:**\n   ```\n   resource://inbox/{Agent}?project=<abs-path>&limit=20\n   resource://thread/{id}?project=<abs-path>&include_bodies=true\n   ```\n\n### Macros vs Granular Tools\n\n- **Prefer macros for speed:** `macro_start_session`, `macro_prepare_thread`, `macro_file_reservation_cycle`, `macro_contact_handshake`\n- **Use granular tools for control:** `register_agent`, `file_reservation_paths`, `send_message`, `fetch_inbox`, `acknowledge_message`\n\n### Common Pitfalls\n\n- `\"from_agent not registered\"`: Always `register_agent` in the correct `project_key` first\n- `\"FILE_RESERVATION_CONFLICT\"`: Adjust patterns, wait for expiry, or use non-exclusive reservation\n- **Auth errors:** If JWT+JWKS enabled, include bearer token with matching `kid`\n\n---\n\n## Beads (br) — Dependency-Aware Issue Tracking\n\nBeads provides a lightweight, dependency-aware issue database and CLI (`br` - beads_rust) for selecting \"ready work,\" setting priorities, and tracking status. It complements MCP Agent Mail's messaging and file reservations.\n\n**Important:** `br` is non-invasive—it NEVER runs git commands automatically. You must manually commit changes after `br sync --flush-only`.\n\n### Conventions\n\n- **Single source of truth:** Beads for task status/priority/dependencies; Agent Mail for conversation and audit\n- **Shared identifiers:** Use Beads issue ID (e.g., `br-123`) as Mail `thread_id` and prefix subjects with `[br-123]`\n- **Reservations:** When starting a task, call `file_reservation_paths()` with the issue ID in `reason`\n\n### Typical Agent Flow\n\n1. **Pick ready work (Beads):**\n   ```bash\n   br ready --json  # Choose highest priority, no blockers\n   ```\n\n2. **Reserve edit surface (Mail):**\n   ```\n   file_reservation_paths(project_key, agent_name, [\"src/**\"], ttl_seconds=3600, exclusive=true, reason=\"br-123\")\n   ```\n\n3. **Announce start (Mail):**\n   ```\n   send_message(..., thread_id=\"br-123\", subject=\"[br-123] Start: <title>\", ack_required=true)\n   ```\n\n4. **Work and update:** Reply in-thread with progress\n\n5. **Complete and release:**\n   ```bash\n   br close 123 --reason \"Completed\"\n   br sync --flush-only  # Export to JSONL (no git operations)\n   ```\n   ```\n   release_file_reservations(project_key, agent_name, paths=[\"src/**\"])\n   ```\n   Final Mail reply: `[br-123] Completed` with summary\n\n### Mapping Cheat Sheet\n\n| Concept | Value |\n|---------|-------|\n| Mail `thread_id` | `br-###` |\n| Mail subject | `[br-###] ...` |\n| File reservation `reason` | `br-###` |\n| Commit messages | Include `br-###` for traceability |\n\n---\n\n## bv — Graph-Aware Triage Engine\n\nbv is a graph-aware triage engine for Beads projects (`.beads/beads.jsonl`). It computes PageRank, betweenness, critical path, cycles, HITS, eigenvector, and k-core metrics deterministically.\n\n**Scope boundary:** bv handles *what to work on* (triage, priority, planning). For agent-to-agent coordination (messaging, work claiming, file reservations), use MCP Agent Mail.\n\n**CRITICAL: Use ONLY `--robot-*` flags. Bare `bv` launches an interactive TUI that blocks your session.**\n\n### The Workflow: Start With Triage\n\n**`bv --robot-triage` is your single entry point.** It returns:\n- `quick_ref`: at-a-glance counts + top 3 picks\n- `recommendations`: ranked actionable items with scores, reasons, unblock info\n- `quick_wins`: low-effort high-impact items\n- `blockers_to_clear`: items that unblock the most downstream work\n- `project_health`: status/type/priority distributions, graph metrics\n- `commands`: copy-paste shell commands for next steps\n\n```bash\nbv --robot-triage        # THE MEGA-COMMAND: start here\nbv --robot-next          # Minimal: just the single top pick + claim command\n```\n\n### Command Reference\n\n**Planning:**\n| Command | Returns |\n|---------|---------|\n| `--robot-plan` | Parallel execution tracks with `unblocks` lists |\n| `--robot-priority` | Priority misalignment detection with confidence |\n\n**Graph Analysis:**\n| Command | Returns |\n|---------|---------|\n| `--robot-insights` | Full metrics: PageRank, betweenness, HITS, eigenvector, critical path, cycles, k-core, articulation points, slack |\n| `--robot-label-health` | Per-label health: `health_level`, `velocity_score`, `staleness`, `blocked_count` |\n| `--robot-label-flow` | Cross-label dependency: `flow_matrix`, `dependencies`, `bottleneck_labels` |\n| `--robot-label-attention [--attention-limit=N]` | Attention-ranked labels |\n\n**History & Change Tracking:**\n| Command | Returns |\n|---------|---------|\n| `--robot-history` | Bead-to-commit correlations |\n| `--robot-diff --diff-since <ref>` | Changes since ref: new/closed/modified issues, cycles |\n\n**Other:**\n| Command | Returns |\n|---------|---------|\n| `--robot-burndown <sprint>` | Sprint burndown, scope changes, at-risk items |\n| `--robot-forecast <id\\|all>` | ETA predictions with dependency-aware scheduling |\n| `--robot-alerts` | Stale issues, blocking cascades, priority mismatches |\n| `--robot-suggest` | Hygiene: duplicates, missing deps, label suggestions |\n| `--robot-graph [--graph-format=json\\|dot\\|mermaid]` | Dependency graph export |\n| `--export-graph <file.html>` | Interactive HTML visualization |\n\n### Scoping & Filtering\n\n```bash\nbv --robot-plan --label backend              # Scope to label's subgraph\nbv --robot-insights --as-of HEAD~30          # Historical point-in-time\nbv --recipe actionable --robot-plan          # Pre-filter: ready to work\nbv --recipe high-impact --robot-triage       # Pre-filter: top PageRank\nbv --robot-triage --robot-triage-by-track    # Group by parallel work streams\nbv --robot-triage --robot-triage-by-label    # Group by domain\n```\n\n### Understanding Robot Output\n\n**All robot JSON includes:**\n- `data_hash` — Fingerprint of source beads.jsonl\n- `status` — Per-metric state: `computed|approx|timeout|skipped` + elapsed ms\n- `as_of` / `as_of_commit` — Present when using `--as-of`\n\n**Two-phase analysis:**\n- **Phase 1 (instant):** degree, topo sort, density\n- **Phase 2 (async, 500ms timeout):** PageRank, betweenness, HITS, eigenvector, cycles\n\n### jq Quick Reference\n\n```bash\nbv --robot-triage | jq '.quick_ref'                        # At-a-glance summary\nbv --robot-triage | jq '.recommendations[0]'               # Top recommendation\nbv --robot-plan | jq '.plan.summary.highest_impact'        # Best unblock target\nbv --robot-insights | jq '.status'                         # Check metric readiness\nbv --robot-insights | jq '.Cycles'                         # Circular deps (must fix!)\n```\n\n---\n\n## UBS — Ultimate Bug Scanner\n\n**Golden Rule:** `ubs <changed-files>` before every commit. Exit 0 = safe. Exit >0 = fix & re-run.\n\n### Commands\n\n```bash\nubs file.rs file2.rs                    # Specific files (< 1s) — USE THIS\nubs $(git diff --name-only --cached)    # Staged files — before commit\nubs --only=rust,toml src/               # Language filter (3-5x faster)\nubs --ci --fail-on-warning .            # CI mode — before PR\nubs .                                   # Whole project (ignores target/, Cargo.lock)\n```\n\n### Output Format\n\n```\nWarning  Category (N errors)\n    file.rs:42:5 - Issue description\n    Suggested fix\nExit code: 1\n```\n\nParse: `file:line:col` -> location | fix hint -> how to fix | Exit 0/1 -> pass/fail\n\n### Fix Workflow\n\n1. Read finding -> category + fix suggestion\n2. Navigate `file:line:col` -> view context\n3. Verify real issue (not false positive)\n4. Fix root cause (not symptom)\n5. Re-run `ubs <file>` -> exit 0\n6. Commit\n\n### Bug Severity\n\n- **Critical (always fix):** Memory safety, use-after-free, data races, SQL injection\n- **Important (production):** Unwrap panics, resource leaks, overflow checks\n- **Contextual (judgment):** TODO/FIXME, println! debugging\n\n---\n\n## RCH — Remote Compilation Helper\n\nRCH offloads `cargo build`, `cargo test`, `cargo clippy`, and other compilation commands to a fleet of 8 remote Contabo VPS workers instead of building locally. This prevents compilation storms from overwhelming csd when many agents run simultaneously.\n\n**RCH is installed at `~/.local/bin/rch` and is hooked into Claude Code's PreToolUse automatically.** Most of the time you don't need to do anything if you are Claude Code — builds are intercepted and offloaded transparently.\n\nTo manually offload a build:\n```bash\nrch exec -- cargo build --release\nrch exec -- cargo test\nrch exec -- cargo clippy\n```\n\nQuick commands:\n```bash\nrch doctor                    # Health check\nrch workers probe --all       # Test connectivity to all 8 workers\nrch status                    # Overview of current state\nrch queue                     # See active/waiting builds\n```\n\nIf rch or its workers are unavailable, it fails open — builds run locally as normal.\n\n**Note for Codex/GPT-5.2:** Codex does not have the automatic PreToolUse hook, but you can (and should) still manually offload compute-intensive compilation commands using `rch exec -- <command>`. This avoids local resource contention when multiple agents are building simultaneously.\n\n---\n\n## ast-grep vs ripgrep\n\n**Use `ast-grep` when structure matters.** It parses code and matches AST nodes, ignoring comments/strings, and can **safely rewrite** code.\n\n- Refactors/codemods: rename APIs, change import forms\n- Policy checks: enforce patterns across a repo\n- Editor/automation: LSP mode, `--json` output\n\n**Use `ripgrep` when text is enough.** Fastest way to grep literals/regex.\n\n- Recon: find strings, TODOs, log lines, config values\n- Pre-filter: narrow candidate files before ast-grep\n\n### Rule of Thumb\n\n- Need correctness or **applying changes** -> `ast-grep`\n- Need raw speed or **hunting text** -> `rg`\n- Often combine: `rg` to shortlist files, then `ast-grep` to match/modify\n\n### Rust Examples\n\n```bash\n# Find structured code (ignores comments)\nast-grep run -l Rust -p 'fn $NAME($$$ARGS) -> $RET { $$$BODY }'\n\n# Find all unwrap() calls\nast-grep run -l Rust -p '$EXPR.unwrap()'\n\n# Quick textual hunt\nrg -n 'println!' -t rust\n\n# Combine speed + precision\nrg -l -t rust 'unwrap\\(' | xargs ast-grep run -l Rust -p '$X.unwrap()' --json\n```\n\n---\n\n## Morph Warp Grep — AI-Powered Code Search\n\n**Use `mcp__morph-mcp__warp_grep` for exploratory \"how does X work?\" questions.** An AI agent expands your query, greps the codebase, reads relevant files, and returns precise line ranges with full context.\n\n**Use `ripgrep` for targeted searches.** When you know exactly what you're looking for.\n\n**Use `ast-grep` for structural patterns.** When you need AST precision for matching/rewriting.\n\n### When to Use What\n\n| Scenario | Tool | Why |\n|----------|------|-----|\n| \"How is pattern matching implemented?\" | `warp_grep` | Exploratory; don't know where to start |\n| \"Where is the quick reject filter?\" | `warp_grep` | Need to understand architecture |\n| \"Find all uses of `Regex::new`\" | `ripgrep` | Targeted literal search |\n| \"Find files with `println!`\" | `ripgrep` | Simple pattern |\n| \"Replace all `unwrap()` with `expect()`\" | `ast-grep` | Structural refactor |\n\n### warp_grep Usage\n\n```\nmcp__morph-mcp__warp_grep(\n  repoPath: \"/dp/destructive_command_guard\",\n  query: \"How does the safe pattern whitelist work?\"\n)\n```\n\nReturns structured results with file paths, line ranges, and extracted code snippets.\n\n### Anti-Patterns\n\n- **Don't** use `warp_grep` to find a specific function name -> use `ripgrep`\n- **Don't** use `ripgrep` to understand \"how does X work\" -> wastes time with manual reads\n- **Don't** use `ripgrep` for codemods -> risks collateral edits\n\n<!-- bv-agent-instructions-v1 -->\n\n---\n\n## Beads Workflow Integration\n\nThis project uses [beads_rust](https://github.com/Dicklesworthstone/beads_rust) (`br`) for issue tracking. Issues are stored in `.beads/` and tracked in git.\n\n**Important:** `br` is non-invasive—it NEVER executes git commands. After `br sync --flush-only`, you must manually run `git add .beads/ && git commit`.\n\n### Essential Commands\n\n```bash\n# View issues (launches TUI - avoid in automated sessions)\nbv\n\n# CLI commands for agents (use these instead)\nbr ready              # Show issues ready to work (no blockers)\nbr list --status=open # All open issues\nbr show <id>          # Full issue details with dependencies\nbr create --title=\"...\" --type=task --priority=2\nbr update <id> --status=in_progress\nbr close <id> --reason \"Completed\"\nbr close <id1> <id2>  # Close multiple issues at once\nbr sync --flush-only  # Export to JSONL (NO git operations)\n```\n\n### Workflow Pattern\n\n1. **Start**: Run `br ready` to find actionable work\n2. **Claim**: Use `br update <id> --status=in_progress`\n3. **Work**: Implement the task\n4. **Complete**: Use `br close <id>`\n5. **Sync**: Run `br sync --flush-only` then manually commit\n\n### Key Concepts\n\n- **Dependencies**: Issues can block other issues. `br ready` shows only unblocked work.\n- **Priority**: P0=critical, P1=high, P2=medium, P3=low, P4=backlog (use numbers, not words)\n- **Types**: task, bug, feature, epic, question, docs\n- **Blocking**: `br dep add <issue> <depends-on>` to add dependencies\n\n### Session Protocol\n\n**Before ending any session, run this checklist:**\n\n```bash\ngit status              # Check what changed\ngit add <files>         # Stage code changes\nbr sync --flush-only    # Export beads to JSONL\ngit add .beads/         # Stage beads changes\ngit commit -m \"...\"     # Commit everything together\ngit push                # Push to remote\n```\n\n### Best Practices\n\n- Check `br ready` at session start to find available work\n- Update status as you work (in_progress -> closed)\n- Create new issues with `br create` when you discover tasks\n- Use descriptive titles and set appropriate priority/type\n- Always `br sync --flush-only && git add .beads/` before ending session\n\n<!-- end-bv-agent-instructions -->\n\n## Landing the Plane (Session Completion)\n\n**When ending a work session**, you MUST complete ALL steps below.\n\n**MANDATORY WORKFLOW:**\n\n1. **File issues for remaining work** - Create issues for anything that needs follow-up\n2. **Run quality gates** (if code changed) - Tests, linters, builds\n3. **Update issue status** - Close finished work, update in-progress items\n4. **Sync beads** - `br sync --flush-only` to export to JSONL\n5. **Hand off** - Provide context for next session\n\n\n---\n\n## cass — Cross-Agent Session Search\n\n`cass` indexes prior agent conversations (Claude Code, Codex, Cursor, Gemini, ChatGPT, etc.) so we can reuse solved problems.\n\n**Rules:** Never run bare `cass` (TUI). Always use `--robot` or `--json`.\n\n### Examples\n\n```bash\ncass health\ncass search \"async runtime\" --robot --limit 5\ncass view /path/to/session.jsonl -n 42 --json\ncass expand /path/to/session.jsonl -n 42 -C 3 --json\ncass capabilities --json\ncass robot-docs guide\n```\n\n### Tips\n\n- Use `--fields minimal` for lean output\n- Filter by agent with `--agent`\n- Use `--days N` to limit to recent history\n\nstdout is data-only, stderr is diagnostics; exit code 0 means success.\n\nTreat cass as a way to avoid re-solving problems other agents already handled.\n\n---\n\n## Local/DSR Release and Windows Deployment Runbook\n\nUse this fallback only when GitHub Actions cannot perform the release, when a\nnative-host build is explicitly required, or when the user directs you to use\nDSR. It refines the shorter release checklist above. Do not jump straight to\n`dsr fallback`: keep source freezing, build, packaging, signing, publication,\nand public verification as separately inspectable stages.\n\n### Non-Negotiable Release Invariants\n\n1. **One immutable source identity.** The local `HEAD`, peeled release tag,\n   remote `main`, compatibility branch, build checkout, build manifest, and\n   published release must all name the same commit.\n2. **Frozen bytes before signatures.** Finish archive layout and names before\n   generating checksums, SLSA provenance, minisign signatures, or Sigstore\n   bundles. Any byte or filename change invalidates downstream metadata and\n   requires regenerating and reverifying it.\n3. **Integrity is not authenticity.** SHA256 is mandatory, but it does not\n   authenticate the publisher. Manual releases require the DSR minisign trust\n   path and the pinned local-release cosign trust path. Workflow releases use\n   GitHub Actions OIDC for Sigstore.\n4. **No destructive synchronization or cleanup.** Assume an automatic source\n   mirror may delete files until its dry-run proves otherwise. Never bypass dcg\n   to clean a checkout, output directory, key copy, or failed release. Rule 1\n   still applies to temporary files and directories.\n5. **A partial matrix must be deliberate.** A working Windows artifact does not\n   prove that every advertised target exists. Define the expected target/asset\n   matrix before building and either satisfy it or explicitly treat the release\n   as an emergency partial release with tested source-install fallback.\n\n### 1. Decide the Path and Freeze the Source\n\nFirst inspect Actions rather than waiting blindly:\n\n```bash\ngh run list --limit 20\ndsr check Dicklesworthstone/destructive_command_guard\n```\n\nIf the manual path is justified, run all release gates *before* tagging:\n\n```bash\ncargo fmt --check\ncargo check --all-targets\ncargo clippy --all-targets -- -D warnings\ncargo test\ncargo check --target x86_64-pc-windows-gnu --lib\ncargo build --release\n./scripts/e2e_test.sh --verbose\npwsh -NoProfile -File ./scripts/e2e_test.ps1 -Verbose\n```\n\nRun any additional gates relevant to the changed surface. A release candidate\nwith code changes receives the full suite; a crate-scoped or `--lib` run is not\na release substitute. Both E2E scripts discover the release binary through\n`CARGO_TARGET_DIR` and reject a stale in-repository binary. If `--binary` /\n`-Binary` is supplied explicitly, pass an absolute path: the suites change\ndirectories while testing isolated configurations. If local PowerShell is\nunavailable, run the PowerShell suite against the native release candidate on\nthe Windows build host before publication.\n\nConfirm the worktree contains only intentional release content, commit it, then\ncreate an annotated tag. Never force an existing public tag:\n\n```bash\nVERSION=vX.Y.Z\ngit status --short\ngit tag -a \"$VERSION\" -m \"Release $VERSION\"\ngit push origin main\ngit push origin main:master\ngit push origin \"$VERSION\"\n```\n\nChoose exactly one owner for the tag and release. If the local path owns them,\ndo not also let `release-automation` create the same tag in parallel.\n\nRecord and compare the identities instead of trusting labels:\n\n```bash\nHEAD_SHA=$(git rev-parse HEAD)\nTAG_SHA=$(git rev-parse \"${VERSION}^{commit}\")\ntest \"$HEAD_SHA\" = \"$TAG_SHA\"\ngit ls-remote origin refs/heads/main refs/heads/master \"refs/tags/$VERSION\" \"refs/tags/$VERSION^{}\"\n```\n\nFor an annotated tag, compare against the peeled `^{}`\nentry—not the tag-object SHA. If any identity differs, stop before building.\nDo not “repair” a published tag; make a patch release.\n\n### 2. Preflight DSR and the Native Windows Host\n\nValidate configuration, target naming, quality commands, host health, disk\nspace, and the exact build plan:\n\n```bash\ndsr repos validate --repo destructive_command_guard\ndsr quality --tool destructive_command_guard --dry-run\ndsr health all --no-cache\ndsr build destructive_command_guard \\\n  --version \"${VERSION#v}\" \\\n  --target windows/amd64 \\\n  --dry-run\n```\n\nThe installer asset name, DSR `artifact_naming`, target triple, archive format,\nand release upload name must agree. A naming mismatch can silently trigger a\nsource build instead of installing the native artifact.\n\nTreat DSR's automatic remote source sync as deletion-capable. Under this\nrepository's no-deletion rule, do not sync into an existing checkout. For a\nnative build:\n\n1. Create a brand-new checkout path on the Windows host at the exact tag.\n2. Verify that checkout's `HEAD` equals `TAG_SHA` and that its worktree is\n   clean.\n3. Temporarily point DSR's host source mapping at that fresh checkout.\n4. Use a brand-new output path and run the build with `--no-sync`:\n\n   ```bash\n   dsr build destructive_command_guard \\\n     --version \"${VERSION#v}\" \\\n     --target windows/amd64 \\\n     --no-sync \\\n     --output-dir <brand-new-output-directory>\n   ```\n\n5. Restore the previous DSR host mapping immediately after collection, even\n   when the build or artifact collection fails.\n\nDo not remove the staged checkout or output directory without the user's\nwritten permission. Record the native host, target triple, commit SHA, Rust\ntoolchain, build duration, and collected executable SHA256 in the release\nnotes/manifest. Monitor a long native build instead of starting a competing\nbuild because it appears quiet.\n\n### 3. Package the Native Artifact Correctly\n\nDSR may successfully collect `dcg.exe` even when the coordinator lacks a ZIP\ntool. That is a packaging failure, not a compile failure. In that case, package\nthe collected executable on Windows with PowerShell `Compress-Archive`.\n\nThe Windows release ZIP must contain exactly one root entry named `dcg.exe`.\nBefore signing:\n\n- Extract the ZIP into a new inspection directory.\n- Hash the extracted `dcg.exe`.\n- Confirm that hash equals the collected native PE hash recorded by DSR.\n- Run the extracted binary and confirm its version matches `VERSION`.\n- Confirm it is the native MSVC release build—not a GNU compile-check artifact,\n  debug binary, stale binary, or installer smoke fixture.\n\nNever rename arbitrary bytes to make them look like a ZIP, and never package a\ndifferent binary merely because it has the expected filename.\n\n### 4. Freeze, Checksum, and Sign the Complete Asset Set\n\nWrite down the expected assets before signing. Depending on release scope this\nincludes archives, standalone binaries, installers, the build manifest,\nper-file `.sha256` sidecars, `SHA256SUMS`, SLSA `.intoto.jsonl` provenance,\n`.minisig` files, `.sigstore.json` bundles, and public verification keys.\n\nThe order is strict:\n\n1. Finalize payload bytes and filenames.\n2. Generate per-file SHA256 sidecars and the aggregate checksum manifest.\n3. Generate and verify SLSA provenance against the frozen payload.\n4. Sign publishable payloads and metadata with DSR minisign.\n5. Generate key-based cosign bundles for the local-release trust path.\n6. Independently verify every signature and bundle.\n\nUse DSR's configured private keys directly from its protected secret location.\nPrivate keys and password material must remain mode `600` and must never be\ncopied into the repository, release directory, generic temporary directory, or\nremote build checkout. Publish only public keys and their fingerprints. If\nduplicate secret material is discovered, stop and follow Rule 1; do not set\n`DCG_BYPASS` or otherwise evade a blocked cleanup command.\n\nBefore publication, confirm that:\n\n- `install.sh`, `install.ps1`, and `README.md` agree on the current minisign\n  public key and local cosign public-key fingerprint.\n- A retired key is accepted only for the exact historical release that used\n  it, never as an unbounded fallback.\n- The cosign verifier meets the installer's patched-version floor\n  (2.6.2+ on v2 or 3.0.4+ on v3); unknown, development, and prerelease version\n  strings fail closed for signature verification.\n\nOnce signing begins, treat the directory as immutable. If a checksum generator,\nuploader, or packaging tool wants to rewrite `SHA256SUMS`, a sidecar, or an\narchive, stop and restart the checksum/signature stages from the newly frozen\nbytes.\n\n### 5. Verify Locally and on the Native Windows Machine\n\nPerform positive and negative tests before uploading:\n\n- SHA256, minisign, cosign, and SLSA verification all succeed independently.\n- A valid artifact paired with the wrong minisign signature fails.\n- A valid artifact paired with the wrong Sigstore bundle fails.\n- A modified artifact fails every applicable integrity/authenticity check.\n- `install.ps1` installs the local artifact into a fresh destination with\n  `-RequireMinisign -Verify -NoConfigure -Force`, using explicit local\n  artifact/checksum/signature/bundle inputs.\n- The installed binary hash equals the signed payload hash, reports the\n  expected version, and passes the installer self-test.\n\nRun the installer twice in a hermetic Windows home and confirm hook\nconfiguration is idempotent: one dcg-owned hook per supported integration,\ncoexisting hooks preserved, valid JSON without a UTF-8 BOM, and no stale dcg\nentry. Run `dcg doctor` and `dcg config --format json`; do not guess config\npaths, enabled packs, timeout sources, or whether two visually similar hook\nentries are actually duplicates. On native Windows the canonical user config is\n`%APPDATA%\\dcg\\config.toml`; the legacy `~/.config/dcg/config.toml` may also be\nhonored, so use the config report to identify the file that actually won.\n\nFor the `careful_company_running_windows` preset, verify the effective 3000 ms\ndefault hook budget on a cold Windows process and confirm all six preset\nsub-packs plus the curated transitive members are active. Then test\nrepresentative allow and deny cases through both PowerShell and `cmd.exe` hook\npayloads, including outbound mail/upload blocks and the structural `hfdt`\nexception (plain `hfdt` allowed; chaining, redirection, and substitution are not\nimplicitly trusted). Exercise committed `.ps1`, `.cmd`, and `.bat` fixtures with\n`dcg scan` rather than placing an intentionally blocked test string on the\nguarded operator shell's own command line.\n\nWindows PowerShell 5.1 has two diagnostic traps:\n\n- Successful native programs such as cosign and `dcg --version` may write to\n  stderr. With `$ErrorActionPreference = 'Stop'` and merged streams, PowerShell\n  can wrap this as `NativeCommandError`. Temporarily make native stderr\n  non-terminating and decide success from the native process exit code.\n- `$LASTEXITCODE` can be stale after invoking a PowerShell script in-process.\n  For installer acceptance, launch a child PowerShell process, wait for it, and\n  inspect that process object's `ExitCode`.\n\nOlder dcg versions could not replace their own running `dcg.exe`. The current\nupdater has a deferred Windows swap path, but every release must retain the\nreal-Windows running-binary update/rollback test. When recovering an older\ninstallation that lacks the fix, run the release installer directly.\n\n### 6. Inspect the Upload Plan, Then Publish\n\nNever assume an uploader is byte-preserving or complete. Run its dry-run/upload\nplan before signing when possible, and compare the selected filenames with the\nfrozen expected-asset list.\n\nAn observed DSR failure mode is regenerating aggregate checksum metadata during\nrelease assembly while omitting installers or `.sigstore.json` bundles from the\nselected upload set. If the current `dsr release` plan would mutate signed\nmetadata or omit required files, do not use it for publication. DSR can still\nprovide the native build, manifest, minisign signatures, and SLSA provenance;\npublish the frozen files with an explicit, enumerated `gh release create` /\n`gh release upload` invocation instead.\n\nPrefer assembling assets on a draft release. Never use `--clobber` on a signed\nasset and never replace an asset behind an existing public URL. If published\nbytes are wrong, withdraw the bad release as directed by the user and issue a\nnew patch version.\n\nIf a local release is now authoritative, inspect queued GitHub workflows. Cancel\nonly `dist` / release-automation runs that could race to create or replace the\nsame release. Do not cancel unrelated CI, coverage, or benchmark runs.\n\n### 7. Verify the Published Release From Scratch\n\nDownload the release into a new local directory and verify it without relying\non build-directory state:\n\n1. Compare the public asset names with the frozen expected-asset list.\n2. Verify the aggregate and per-file SHA256 data.\n3. Verify every minisign signature using the published/pinned public key.\n4. Verify every Sigstore bundle against the correct local-key or Actions-OIDC\n   trust root.\n5. Verify every SLSA subject digest against its public artifact.\n6. Confirm the release is public, non-draft, and has the intended prerelease\n   status.\n\nThen run the installer from the *public release URL* on the native Windows host\ninto a fresh destination. Pin `-Version`, require minisign, enable `-Verify`,\nand confirm the installed hash, version, self-test, `dcg doctor`, effective\nconfig, hook idempotency, and representative PowerShell/`cmd.exe` policy\nbehavior. A local-file install does not substitute for this public-path test.\n\nFinally verify the repository invariants again:\n\n```bash\ngit status --short\ngit rev-parse HEAD\ngit rev-parse \"${VERSION}^{commit}\"\ngit ls-remote origin refs/heads/main refs/heads/master \"refs/tags/$VERSION\" \"refs/tags/$VERSION^{}\"\ngh release view \"$VERSION\"\n```\n\nThe release is complete only when the source identities agree, the worktree is\nclean, all intended assets are publicly downloadable and independently\nverifiable, and a fresh native Windows installation succeeds from the public\nrelease.\n\n---\n\nNote for Codex/GPT-5.2:\n\nYou constantly bother me and stop working with concerned questions that look similar to this:\n\n```\nUnexpected changes (need guidance)\n\n- Working tree still shows edits I did not make in Cargo.toml, Cargo.lock, src/cli/commands/upgrade.rs, src/storage/sqlite.rs, tests/conformance.rs, tests/storage_deps.rs. Please advise whether to keep/commit/revert these before any further work. I did not touch them.\n\nNext steps (pick one)\n\n1. Decide how to handle the unrelated modified files above so we can resume cleanly.\n2. Triage beads_rust-orko (clippy/cargo warnings) and beads_rust-ydqr (rustfmt failures).\n3. If you want a full suite run later, fix conformance/clippy blockers and re-run cargo test --all.\n```\n\nNEVER EVER DO THAT AGAIN. The answer is literally ALWAYS the same: those are changes created by the potentially dozen of other agents working on the project at the same time. This is not only a common occurrence, it happens multiple times PER MINUTE. The way to deal with it is simple: you NEVER, under ANY CIRCUMSTANCE, stash, revert, overwrite, or otherwise disturb in ANY way the work of other agents. Just treat those changes identically to changes that you yourself made. Just fool yourself into thinking YOU made the changes and simply don't recall it for some reason.\n\n---\n\n## Note on Built-in TODO Functionality\n\nAlso, if I ask you to explicitly use your built-in TODO functionality, don't complain about this and say you need to use beads. You can use built-in TODOs if I tell you specifically to do so. Always comply with such orders.\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","title":"AGENTS.md","content":"# AGENTS.md — dcg (Destructive Command Guard)\n\n> Guidelines for AI coding agents working in this Rust codebase.\n\n---\n\n## RULE 0 - THE FUNDAMENTAL OVERRIDE PREROGATIVE\n\nIf I tell you to do something, even if it goes against what follows below, YOU MUST LISTEN TO ME. I AM IN CHARGE, NOT YOU.\n\n---\n\n## RULE NUMBER 1: NO FILE DELETION\n\n**YOU ARE NEVER ALLOWED TO DELETE A FILE WITHOUT EXPRESS PERMISSION.** Even a new file that you yourself created, such as a test code file. You have a horrible track record of deleting critically important files or otherwise throwing away tons of expensive work. As a result, you have permanently lost any and all rights to determine that a file or folder should be deleted.\n\n**YOU MUST ALWAYS ASK AND RECEIVE CLEAR, WRITTEN PERMISSION BEFORE EVER DELETING A FILE OR FOLDER OF ANY KIND.**\n\n---\n\n## Irreversible Git & Filesystem Actions — DO NOT EVER BREAK GLASS\n\n> **Note:** This project exists specifically to block these dangerous commands for AI agents. Practice what we preach.\n\n1. **Absolutely forbidden commands:** `git reset --hard`, `git clean -fd`, `rm -rf`, or any command that can delete or overwrite code/data must never be run unless the user explicitly provides the exact command and states, in the same message, that they understand and want the irreversible consequences.\n2. **No guessing:** If there is any uncertainty about what a command might delete or overwrite, stop immediately and ask the user for specific approval. \"I think it's safe\" is never acceptable.\n3. **Safer alternatives first:** When cleanup or rollbacks are needed, request permission to use non-destructive options (`git status`, `git diff`, `git stash`, copying to backups) before ever considering a destructive command.\n4. **Mandatory explicit plan:** Even after explicit user authorization, restate the command verbatim, list exactly what will be affected, and wait for a confirmation that your understanding is correct. Only then may you execute it—if anything remains ambiguous, refuse and escalate.\n5. **Document the confirmation:** When running any approved destructive command, record (in the session notes / final response) the exact user text that authorized it, the command actually run, and the execution time. If that record is absent, the operation did not happen.\n\n---\n\n## Git Branch: ONLY Use `main`, NEVER `master`\n\n**The default branch is `main`. The `master` branch exists only for legacy URL compatibility.**\n\n- **All work happens on `main`** — commits, PRs, feature branches all merge to `main`\n- **Never reference `master` in code or docs** — if you see `master` anywhere, it's a bug that needs fixing\n- **The `master` branch must stay synchronized with `main`** — after pushing to `main`, also push to `master`:\n  ```bash\n  git push origin main:master\n  ```\n\n**Why this matters:** The `dcg update` command and install URLs historically referenced `master`. If `master` falls behind `main`, users get stale code. We had a bug where `master` was **497 commits behind**, causing users to see old installer behavior.\n\n**If you see `master` referenced anywhere:**\n1. Update it to `main`\n2. Ensure `master` is synchronized: `git push origin main:master`\n\n---\n\n## Toolchain: Rust & Cargo\n\nWe only use **Cargo** in this project, NEVER any other package manager.\n\n- **Edition:** Rust 2024 (nightly required — see `rust-toolchain.toml`)\n- **Dependency versions:** Explicit versions for stability\n- **Configuration:** Cargo.toml only (single crate, not a workspace)\n- **Unsafe code:** Forbidden (`#![forbid(unsafe_code)]`)\n\n### Key Dependencies\n\n| Crate | Purpose |\n|-------|---------|\n| `serde` + `serde_json` | JSON parsing for Claude Code hook protocol |\n| `serde_yaml` | External pack YAML parsing |\n| `toml` + `toml_edit` | TOML config parsing with formatting preservation |\n| `fancy-regex` | Advanced regex with lookahead/lookbehind |\n| `regex` | `RegexSet` for heredoc detection |\n| `memchr` | SIMD-accelerated substring search |\n| `aho-corasick` | Multi-pattern string matching for keyword quick-reject |\n| `colored` | Terminal colors with TTY detection |\n| `clap` + `clap_complete` | CLI argument parsing with shell completions |\n| `chrono` | RFC 3339 timestamps |\n| `ast-grep-core` + `ast-grep-language` | AST-based pattern matching for heredoc/inline-script content |\n| `rusqlite` | Bundled upstream SQLite for best-effort telemetry history |\n| `rust-mcp-sdk` | MCP server integration (stdio transport) |\n| `tokio` | Async runtime for MCP server mode |\n| `ratatui` + `comfy-table` + `indicatif` + `console` | TUI/CLI visual polish |\n| `self_update` | Binary self-update from GitHub Releases |\n| `vergen-gix` | Build metadata embedding (build.rs) |\n| `tracing` + `tracing-subscriber` | Structured logging and diagnostics |\n| `sha2` + `hmac` | Hashing and HMAC for allow-once short codes |\n| `flate2` | Gzip compression for history export |\n\n### Release Profile\n\nThe release build optimizes for binary size:\n\n```toml\n[profile.release]\nopt-level = \"z\"     # Optimize for size (lean binary for distribution)\nlto = true          # Link-time optimization\ncodegen-units = 1   # Single codegen unit for better optimization\npanic = \"abort\"     # Smaller binary, no unwinding overhead\nstrip = true        # Remove debug symbols\n```\n\n### Feature Flags\n\n```toml\n[features]\nrayon = [\"dep:rayon\"]           # Rayon data parallelism (optional)\nrich-output = [\"dep:rich_rust\"] # Enable rich_rust for premium terminal output\nlegacy-output = []              # Keep old rendering (placeholder for gradual migration)\n```\n\n---\n\n## Code Editing Discipline\n\n### No Script-Based Changes\n\n**NEVER** run a script that processes/changes code files in this repo. Brittle regex-based transformations create far more problems than they solve.\n\n- **Always make code changes manually**, even when there are many instances\n- For many simple changes: use parallel subagents\n- For subtle/complex changes: do them methodically yourself\n\n### No File Proliferation\n\nIf you want to change something or add a feature, **revise existing code files in place**.\n\n**NEVER** create variations like:\n- `mainV2.rs`\n- `main_improved.rs`\n- `main_enhanced.rs`\n\nNew files are reserved for **genuinely new functionality** that makes zero sense to include in any existing file. The bar for creating new files is **incredibly high**.\n\n---\n\n## Backwards Compatibility\n\nWe do not care about backwards compatibility—we're in early development with no users. We want to do things the **RIGHT** way with **NO TECH DEBT**.\n\n- Never create \"compatibility shims\"\n- Never create wrapper functions for deprecated APIs\n- Just fix the code directly\n\n---\n\n## Compiler Checks (CRITICAL)\n\n**After any substantive code changes, you MUST verify no errors were introduced:**\n\n```bash\n# Check for compiler errors and warnings\ncargo check --all-targets\n\n# Check for clippy lints (pedantic + nursery are enabled)\ncargo clippy --all-targets -- -D warnings\n\n# Verify formatting\ncargo fmt --check\n```\n\nIf you see errors, **carefully understand and resolve each issue**. Read sufficient context to fix them the RIGHT way.\n\n---\n\n## Windows Support (native, `x86_64-pc-windows-msvc`)\n\ndcg ships a **native Windows** binary (built/tested on `windows-latest` with the\nnightly toolchain) and a `check (windows)` CI job. When touching anything\nplatform-sensitive, follow these conventions:\n\n- **Separate command-pattern DATA from dcg's own paths.** Destructive-command\n  patterns (`rm -rf /`, `normalize.rs` stripping `/usr/bin/git`, `/etc`, `/tmp`)\n  are DATA about Unix commands and must STAY — Windows users still run git-bash.\n  Only dcg's *own* config/state paths get Windows-ified (resolve via the `dirs`\n  crate; the system layer is `%ProgramData%\\dcg`, helper `config::system_config_dir()`).\n- **`.exe` suffix.** When constructing a path to the dcg binary, use\n  `env!(\"CARGO_BIN_EXE_dcg\")` / `assert_cmd::cargo::cargo_bin(\"dcg\")` in tests, or\n  `std::env::consts::EXE_SUFFIX` in `src`. **Never** a bare `push(\"dcg\")` — the\n  Windows CI job greps for it and fails. Use `dirs::home_dir()` (not `HOME`,\n  which is unset on Windows) and set `USERPROFILE`/`TEMP`/`TMP` alongside `HOME`\n  in test isolation.\n- **Verify Windows branches from Linux** without a Windows box: `mingw` + the\n  `x86_64-pc-windows-gnu` target are installed, so\n  `cargo check --target x86_64-pc-windows-gnu --lib` (or `--bin dcg` / `--tests`)\n  compile-checks every `#[cfg(windows)]` path. When `pwsh` is installed, use it\n  to run the PowerShell installer/test scripts; otherwise run those gates on the\n  native Windows release host.\n- **Windows packs.** `src/packs/windows/` holds the native-Windows packs\n  (`windows.filesystem`/`windows.system` default-ON on Windows, `windows.misc`/\n  `windows.powershell` opt-in). Patterns use inline `(?i)`; keyword arrays\n  may retain conventional casing variants for readability, but keyword\n  quick-rejection is ASCII case-insensitive so mixed-case Windows spellings\n  cannot skip the regex stage (see `src/packs/windows/mod.rs`). See\n  [`docs/windows.md`](docs/windows.md).\n- **The `careful_company_running_windows` preset.**\n  `src/packs/careful_company_running_windows/` holds six opt-in sub-packs\n  covering **outbound communication and data egress** (email, chat/webhooks,\n  HTTP upload, file transfer, tunnels) plus **tampering with the controls that\n  supervise the agent** (Defender/firewall/EDR, audit logs, and dcg's own\n  bypass/uninstall). It is the only pack ID with *curated transitive\n  membership*: enabling it also enables the pinned\n  `CAREFUL_COMPANY_PRESET_MEMBERS` list in `src/packs/mod.rs`\n  (`windows.*`, `database.*`, `storage.*`, `remote.*`, `backup.*`, `secrets.*`,\n  `cloud.*`). That list is deliberately explicit — do **not** convert it to\n  prefix matching, or future packs will join a security posture silently.\n  Two invariants to preserve when touching this area:\n  - **Tier order.** `windows.*` is tier 11 and the preset is tier 12, so\n    Windows packs keep claiming attribution for commands both match. Rule ids\n    (`pack_id:pattern_name`) are what allowlists key on, so reordering these\n    silently invalidates existing `windows.*` allowlist entries.\n  - **The `hfdt` trust boundary.** While any preset sub-pack is enabled,\n    `src/evaluator.rs` allows a command whose executable is `hfdt` **before any\n    pack runs** — including `core.*`. It is structural (whole-segment\n    executable match, no chains/redirection/substitution), but it does mean\n    enabling the preset *reduces* coverage for that one executable. Keep it\n    documented in `README.md` and `docs/careful-company-windows.md`.\n\n---\n\n## Testing\n\n### Testing Policy\n\nEvery module includes inline `#[cfg(test)]` unit tests alongside the implementation. Tests must cover:\n- Happy path\n- Edge cases (empty input, max values, boundary conditions)\n- Error conditions\n\nEnd-to-end tests live in `scripts/e2e_test.sh`.\n\n### Unit Tests\n\nThe test suite includes 80+ tests covering all functionality:\n\n```bash\n# Run all tests\ncargo test\n\n# Run with output\ncargo test -- --nocapture\n\n# Run specific test module\ncargo test normalize_command_tests\ncargo test safe_pattern_tests\ncargo test destructive_pattern_tests\n```\n\n### The Three Release-Blocking E2E Suites (read before touching perf or protocols)\n\n`cargo test` cannot catch the failure modes that have actually broken users.\nThree real-binary, no-mock suites exist specifically to close those gaps. All\nthree must be green before any release.\n\n| Suite | Catches | Why unit tests can't |\n|-------|---------|----------------------|\n| `scripts/e2e_harness_matrix.sh` | Wire-protocol breakage for **every** agent (Claude Code, Codex, Gemini, Copilot, Hermes, Grok, agy) | Unit tests call Rust functions; harnesses parse **bytes**. Asserts decision field + exit code + stdout/stderr separation per protocol against the real binary. |\n| `scripts/perf_baseline.py --assert-budget-ms` | **#245**: per-invocation cost silently eating the fixed hook deadline | The perf job is a *relative* ratchet — a uniform slowdown just gets re-baselined. This gate asserts cold p95 against the **shipped** `HOOK_EVALUATION_BUDGET_MS` with a hermetic HOME and scrubbed `DCG_*`. |\n| `scripts/e2e_fleet_install.sh` | Published artifact missing/unrunnable per platform; installer picking the wrong triple; checksum/signature verification silently skipped; hook config non-idempotent | Nothing in-tree proves the **public download path** works on real Linux/macOS/Windows hardware. |\n\n```bash\n# Protocol conformance for all 7 harnesses (needs a release binary + jq)\n./scripts/e2e_harness_matrix.sh --binary target/release/dcg\n\n# Absolute latency gate — the #245 guard. Budget MUST come from src/perf.rs.\npython3 scripts/perf_baseline.py --bin target/release/dcg --skip-trace \\\n  --assert-budget-ms 1000 --assert-margin-pct 50\n\n# Real installs from the PUBLIC release on every DSR host\n./scripts/e2e_fleet_install.sh --version vX.Y.Z          # whole fleet\n./scripts/e2e_fleet_install.sh --version vX.Y.Z --local-only\n```\n\nRules:\n- **Scrub ambient `DCG_*` before measuring anything.** Operators bitten by #245\n  export `DCG_HOOK_TIMEOUT_MS=5000` (an agent `settings.json` `env` block puts\n  it in every child process), so an un-scrubbed suite measures the *workaround*\n  and passes on exactly the machines that need protecting. `env -i` covers the\n  hook calls; the installer cannot use it (it needs the host PATH for\n  `curl`/`tar`/`xz`/`minisign`), so the probes also `unset` every `DCG_*` up\n  front. Assert `general.hook_timeout_source` too — a bare `>= 1000` check\n  cannot tell the shipped default from an inherited 5000.\n- **Set `DCG_SELF_HEAL_HOOK=0` before the installer runs, not after.** dcg\n  repairs a missing/stale hook entry whenever it runs in hook mode, and native\n  Windows resolves the settings path via the Win32 known-folder API, which\n  `USERPROFILE` cannot redirect — so a late disable can rewrite a real\n  machine's agent config.\n- **Never hard-code the budget in `.github/workflows/ci.yml`.** It is grepped\n  out of `HOOK_EVALUATION_BUDGET_MS`; `perf::tests::ci_enforces_absolute_latency_gate_against_shipped_budget`\n  fails if that wiring is removed or the margin is loosened past 60%.\n- Measure dcg's own cost as `full_eval − DCG_BYPASS`, never raw wall-clock:\n  process spawn (≈940ms under Windows PowerShell) sits **outside** the\n  evaluation deadline and would otherwise produce false alarms.\n- The fleet suite installs into a scratch prefix with an isolated `HOME` and\n  `--no-configure`; it never touches a host's real agent hook config.\n- A probe that dies partway must FAIL, not pass: every probe emits\n  `probe_complete` and the runner asserts the full expected case set.\n\n### End-to-End Testing\n\n```bash\n# Run the E2E test script (needs bash >= 4; macOS /bin/bash 3.2 breaks the summary)\n./scripts/e2e_test.sh\n\n# Or test manually\necho '{\"tool_name\":\"Bash\",\"tool_input\":{\"command\":\"git reset --hard\"}}' | cargo run --release\n# Should output JSON denial\n\necho '{\"tool_name\":\"Bash\",\"tool_input\":{\"command\":\"git status\"}}' | cargo run --release\n# Should output nothing (allowed)\n```\n\n### Test Categories\n\n| Module | Tests | Purpose |\n|--------|-------|---------|\n| `normalize_command_tests` | 8 | Path stripping for git/rm binaries |\n| `quick_reject_tests` | 5 | Fast-path filtering for non-git/rm commands |\n| `safe_pattern_tests` | 16 | Whitelist accuracy |\n| `destructive_pattern_tests` | 20 | Blacklist coverage |\n| `input_parsing_tests` | 8 | JSON parsing robustness |\n| `deny_output_tests` | 2 | Output format validation |\n| `integration_tests` | 4 | End-to-end pipeline |\n| `optimization_tests` | 9 | Performance paths |\n| `edge_case_tests` | 24 | Real-world edge cases |\n\n---\n\n## Third-Party Library Usage\n\nIf you aren't 100% sure how to use a third-party library, **SEARCH ONLINE** to find the latest documentation and current best practices.\n\n---\n\n## dcg (Destructive Command Guard) — This Project\n\n**This is the project you're working on.** dcg is a high-performance Claude Code hook that blocks destructive commands before they execute. It protects against dangerous git commands, filesystem operations, database queries, container commands, and more through a modular pack system.\n\n### What It Does\n\nGuards AI coding agents from executing destructive commands by intercepting Claude Code's `PreToolUse` hook protocol, evaluating commands against safe/destructive pattern lists, and denying dangerous operations with structured JSON output including remediation suggestions.\n\n### Architecture\n\n```\nJSON Input → Parse → Quick Reject (memchr) → Normalize → Safe Patterns → Destructive Patterns → Default Allow\n```\n\n### Key Files\n\n| File | Purpose |\n|------|---------|\n| `src/main.rs` | Entry point, hook I/O, CLI dispatch |\n| `src/evaluator.rs` | Pattern matching engine (safe + destructive evaluation) |\n| `src/hook.rs` | Claude Code PreToolUse hook protocol handling |\n| `src/normalize.rs` | Command normalization (path stripping, alias expansion) |\n| `src/heredoc.rs` | Heredoc and inline script extraction |\n| `src/ast_matcher.rs` | AST-based pattern matching for embedded code |\n| `src/config.rs` | Configuration loading (TOML, allowlists, pack enable/disable) |\n| `src/allowlist.rs` | Allowlist management (project, user, system scopes) |\n| `src/cli.rs` | CLI commands (explain, scan, packs, allowlist, etc.) |\n| `src/scan.rs` | Codebase scanning for destructive patterns |\n| `src/context.rs` | Contextual analysis for pattern matching |\n| `src/confidence.rs` | Match confidence scoring |\n| `src/error_codes.rs` | Standardized DCG-XXXX error codes |\n| `src/exit_codes.rs` | Process exit code definitions |\n| `src/packs/` | Modular pattern pack system (core + extensions) |\n| `src/output/` | Output formatting (JSON, colorful stderr) |\n| `src/highlight.rs` | Syntax highlighting for command display |\n| `src/logging.rs` | Tracing/logging configuration |\n| `src/perf.rs` | Performance budgets and benchmarks |\n| `src/simulate.rs` | Command simulation and dry-run support |\n| `src/mcp.rs` | MCP server integration |\n| `src/agent.rs` | Agent detection and identification |\n| `src/interactive.rs` | Interactive mode |\n| `src/git.rs` | Git-specific command analysis |\n| `src/history/` | Decision history and telemetry |\n| `src/sarif.rs` | SARIF output format for scan results |\n| `src/pending_exceptions.rs` | Pending exception management |\n| `src/lib.rs` | Library re-exports |\n| `Cargo.toml` | Dependencies and release optimizations |\n| `build.rs` | Build script for version metadata (vergen) |\n| `rust-toolchain.toml` | Nightly toolchain requirement |\n| `scripts/e2e_test.sh` | End-to-end test script (hundreds of command scenarios) |\n\n### Output Style\n\nThis tool has two output modes:\n\n- **JSON to stdout:** For Claude Code hook protocol (`hookSpecificOutput` with `permissionDecision: \"deny\"`)\n- **Colorful warning to stderr:** For human visibility when commands are blocked\n\nOutput behavior:\n- **Deny:** Colorful warning to stderr + JSON to stdout\n- **Allow:** No output (silent exit)\n- **--version/-V:** Version info with build metadata to stderr\n- **--help/-h:** Usage information to stderr\n\nColors are automatically disabled when stderr is not a TTY (e.g., piped to file).\n\n### Pattern System\n\n- **34 safe patterns** (whitelist, checked first)\n- **16 destructive patterns** (blacklist, checked second)\n- **Default allow** for unmatched commands\n\n### Adding New Patterns\n\n1. Identify the command to block/allow\n2. Write a regex using `fancy-regex` syntax (supports lookahead/lookbehind)\n3. Add to `SAFE_PATTERNS` or `DESTRUCTIVE_PATTERNS` using the macros:\n\n```rust\n// Safe pattern (whitelist)\npattern!(\"pattern-name\", r\"regex-here\")\n\n// Destructive pattern (blacklist)\ndestructive!(\n    r\"regex-here\",\n    \"Human-readable reason for blocking\"\n)\n```\n\n4. Add tests for all variants\n5. Run `cargo test` and `./scripts/e2e_test.sh`\n\n### Performance Requirements\n\nEvery Bash command passes through this hook. Performance is critical:\n\n- Quick rejection filter eliminates 99%+ of commands before regex\n- Lazy-initialized static regex patterns (compiled once, reused)\n- Sub-millisecond execution for typical commands\n- Zero allocations on the hot path for safe commands\n\n### Heredoc Detection Notes\n\n- **Rule IDs**: Heredoc patterns use stable IDs like `heredoc.python.shutil_rmtree` for allowlisting.\n- **Bounded failure**: Heredoc parse/AST failures use the configured bounded\n  fallback; disabling fallback blocks. Absolute hook-deadline exhaustion and\n  incomplete nested evaluation return `Indeterminate`, never `Allow`.\n- **Tests**: Prefer targeted tests in `src/ast_matcher.rs` and `src/heredoc.rs`.\n  - `cargo test ast_matcher`\n  - `cargo test heredoc`\n  - Add positive and negative fixtures for each new pattern.\n\n---\n\n<!-- dcg-machine-readable-v1 -->\n\n## DCG Hook Protocol (Machine-Readable Reference)\n\n> This section provides structured documentation for AI agents integrating with dcg.\n\n### JSON Input Format\n\ndcg reads from stdin in Claude Code's `PreToolUse` hook format:\n\n```json\n{\n  \"tool_name\": \"Bash\",\n  \"tool_input\": {\n    \"command\": \"git reset --hard HEAD~5\"\n  }\n}\n```\n\n**Required fields:**\n- `tool_name`: Must be `\"Bash\"` for dcg to process (other tools are ignored)\n- `tool_input.command`: The shell command string to evaluate\n\n### JSON Output Format (Denial)\n\nWhen a command is blocked, dcg outputs JSON to stdout:\n\n```json\n{\n  \"hookSpecificOutput\": {\n    \"hookEventName\": \"PreToolUse\",\n    \"permissionDecision\": \"deny\",\n    \"permissionDecisionReason\": \"BLOCKED by dcg\\n\\nTip: dcg explain \\\"git reset --hard HEAD~5\\\"\\n\\nReason: git reset --hard destroys uncommitted changes\\n\\nExplanation: Rewrites history and discards uncommitted changes.\\n\\nRule: core.git:reset-hard\\n\\nIf this operation is truly needed, ask the user for explicit permission and have them run the command manually.\",\n    \"ruleId\": \"core.git:reset-hard\",\n    \"packId\": \"core.git\",\n    \"severity\": \"critical\",\n    \"confidence\": 0.95,\n    \"allowOnceCode\": \"a1b2c3\",\n    \"allowOnceFullHash\": \"sha256:abc123...\",\n    \"remediation\": {\n      \"safeAlternative\": \"git stash\",\n      \"explanation\": \"Use git stash to save your changes first.\",\n      \"allowOnceCommand\": \"dcg allow-once a1b2c3\"\n    }\n  }\n}\n```\n\n**Key fields for agent parsing:**\n| Field | Type | Description |\n|-------|------|-------------|\n| `permissionDecision` | `\"allow\"` \\| `\"deny\"` | The decision |\n| `ruleId` | `string` | Stable pattern ID (e.g., `\"core.git:reset-hard\"`) for allowlisting |\n| `packId` | `string` | Pack that matched (e.g., `\"core.git\"`) |\n| `severity` | `string` | `\"critical\"`, `\"high\"`, `\"medium\"`, or `\"low\"` |\n| `confidence` | `number` | Match confidence 0.0-1.0 |\n| `allowOnceCode` | `string` | Short code for `dcg allow-once` |\n| `remediation.safeAlternative` | `string?` | Suggested safe command |\n\n### JSON Output Format (Allow)\n\nWhen a command is allowed: **no output** (silent exit 0).\n\n---\n\n## Exit Codes Reference\n\n| Code | Meaning | Agent Action |\n|------|---------|--------------|\n| `0` | Command allowed OR protocol JSON denial was emitted | Parse stdout; if empty, command was allowed |\n| `1` | Parse error or invalid input | Retry with corrected input |\n| `2` | Configuration error | Check config syntax and stderr diagnostics |\n\n**Detection logic for agents:**\n```bash\noutput=$(echo \"$hook_input\" | dcg 2>/dev/null)\nif [ -z \"$output\" ]; then\n  echo \"ALLOWED\"\nelse\n  echo \"DENIED: $output\"\nfi\n```\n\nCodex CLI uses a stricter hook parser: blocked commands return a minimal\n`hookSpecificOutput` denial on stdout with exit code 0. See\n[`docs/codex-integration.md`](docs/codex-integration.md) for the Codex-specific\nprotocol notes.\n\n---\n\n## Error Codes Reference\n\nDCG uses standardized error codes in the format `DCG-XXXX` for machine-parseable error handling.\n\n### Error Categories\n\n| Range | Category | Description |\n|-------|----------|-------------|\n| DCG-1xxx | `pattern_match` | Pattern matching and evaluation errors |\n| DCG-2xxx | `configuration` | Configuration loading and parsing errors |\n| DCG-3xxx | `runtime` | Runtime and execution errors |\n| DCG-4xxx | `external` | External integration errors |\n\n### Common Error Codes\n\n| Code | Description | Typical Cause |\n|------|-------------|---------------|\n| `DCG-1001` | Pattern compilation failed | Invalid regex syntax in pattern |\n| `DCG-1002` | Pattern match timeout | Complex pattern taking too long |\n| `DCG-2001` | Config file not found | Missing configuration file |\n| `DCG-2002` | Config parse error | Invalid TOML/JSON syntax |\n| `DCG-2004` | Allowlist load error | Invalid allowlist file |\n| `DCG-3001` | JSON parse error | Malformed JSON input |\n| `DCG-3002` | IO error | File read/write failure |\n| `DCG-4001` | External pack load failed | Invalid external pack YAML |\n\n### Error JSON Structure\n\nWhen errors are returned in JSON format, they follow this structure:\n\n```json\n{\n  \"error\": {\n    \"code\": \"DCG-3001\",\n    \"category\": \"runtime\",\n    \"message\": \"JSON parse error: unexpected token at position 15\",\n    \"context\": {\n      \"position\": 15,\n      \"input_preview\": \"{ \\\"tool_name\\\": ...\"\n    }\n  }\n}\n```\n\n**Fields:**\n- `code`: Stable error code for programmatic handling\n- `category`: Error category (`pattern_match`, `configuration`, `runtime`, `external`)\n- `message`: Human-readable error description\n- `context`: Additional details (optional, varies by error type)\n\n---\n\n## Allowlist & Bypass Instructions\n\n### Temporary Bypass (24-hour allow-once)\n\nWhen a command is blocked, the output includes an `allowOnceCode`. Use it:\n\n```bash\ndcg allow-once <code>\n```\n\nThis allows the specific command for 24 hours in the current directory scope.\n\n### Permanent Allowlist (by rule ID)\n\nAdd a rule to the project allowlist:\n\n```bash\ndcg allowlist add <ruleId> --project\n# Example: dcg allowlist add core.git:reset-hard --project\n```\n\nAllowlist files (in priority order):\n1. `.dcg/allowlist.toml` (project)\n2. `~/.config/dcg/allowlist.toml` (user)\n3. `/etc/dcg/allowlist.toml` (system)\n\n### Bypass Environment Variable\n\nFor emergency bypass (use sparingly):\n\n```bash\nDCG_BYPASS=1 <command>\n```\n\n**Warning:** This disables all protection. Log and justify any usage.\n\n---\n\n## Pattern Quick Reference\n\n### Core Git Patterns (Always Enabled)\n\n| Pattern ID | Blocks | Severity |\n|------------|--------|----------|\n| `core.git:reset-hard` | `git reset --hard` | Critical |\n| `core.git:reset-merge` | `git reset --merge` | High |\n| `core.git:checkout-discard` | `git checkout -- <file>` | High |\n| `core.git:restore-discard` | `git restore <file>` (without `--staged`) | High |\n| `core.git:clean-force` | `git clean -f`, `git clean -fd` | High |\n| `core.git:force-push` | `git push --force`, `git push -f` | High |\n| `core.git:branch-force-delete` | `git branch -d`, `--delete`, `-D`, `-f`, `-M`, `-C` | High |\n| `core.git:stash-drop` | `git stash drop`, `git stash clear` | High |\n\n### Core Filesystem Patterns (Always Enabled)\n\n| Pattern ID | Blocks | Severity |\n|------------|--------|----------|\n| `core.filesystem:rm-rf-root` | `rm -rf /`, `rm -rf ~` | Critical |\n| `core.filesystem:rm-rf-general` | `rm -rf` outside temp dirs | High |\n\n### Safe Patterns (Whitelist - Always Allowed)\n\n| Pattern | Command | Why Safe |\n|---------|---------|----------|\n| `git-checkout-branch` | `git checkout -b <branch>` | Creates new branch |\n| `git-checkout-orphan` | `git checkout --orphan <branch>` | Creates orphan branch |\n| `git-restore-staged` | `git restore --staged <file>` | Only unstages, doesn't discard |\n| `git-clean-dry-run` | `git clean -n`, `git clean --dry-run` | Preview only |\n| `rm-tmp` | `rm -rf /tmp/*`, `/var/tmp/*` | Temp directory cleanup |\n\n### Pack Enable/Disable Examples\n\n```toml\n# ~/.config/dcg/config.toml\n[packs]\nenabled = [\n    \"database.postgresql\",    # Blocks DROP TABLE, TRUNCATE\n    \"kubernetes.kubectl\",     # Blocks kubectl delete namespace\n    \"cloud.aws\",              # Blocks aws ec2 terminate-instances\n]\n\ndisabled = [\n    \"containers.docker\",      # Disable Docker protection\n]\n```\n\nList all packs: `dcg packs --verbose`\n\n---\n\n## CLI Quick Reference for Agents\n\n| Command | Purpose |\n|---------|---------|\n| `dcg explain \"<command>\"` | Detailed trace of why command is blocked/allowed |\n| `dcg allow-once <code>` | Allow a blocked command for 24 hours |\n| `dcg allowlist add <ruleId> --project` | Permanently allow a rule |\n| `dcg packs` | List enabled packs |\n| `dcg packs --verbose` | List all packs with pattern counts |\n| `dcg scan .` | Scan codebase for destructive patterns |\n| `dcg --version` | Show version and build info |\n\n---\n\n## Agent Integration Checklist\n\nWhen integrating with dcg, ensure your agent:\n\n- [ ] Parses stdout for JSON denial responses\n- [ ] Handles empty stdout as \"command allowed\"\n- [ ] Uses `ruleId` for stable allowlisting (not pattern text)\n- [ ] Displays `remediation.safeAlternative` to users when available\n- [ ] Respects `severity` for prioritization (critical > high > medium > low)\n- [ ] Uses `dcg explain` before asking users to bypass\n\n---\n\n## JSON Schema Reference\n\nFormal JSON Schema definitions (Draft 2020-12) for all dcg output formats are available in `docs/json-schema/`:\n\n| Schema | Purpose |\n|--------|---------|\n| [`hook-output.json`](docs/json-schema/hook-output.json) | PreToolUse hook denial response format |\n| [`scan-results.json`](docs/json-schema/scan-results.json) | `dcg scan` command output format |\n| [`stats-output.json`](docs/json-schema/stats-output.json) | `dcg stats` command output format |\n| [`error.json`](docs/json-schema/error.json) | Error response formats for various commands |\n\nUse these schemas for:\n- Validating dcg output in automated pipelines\n- Generating type-safe client code\n- Understanding the complete output contract\n\n<!-- end-dcg-machine-readable -->\n\n---\n\n## CI/CD Pipeline\n\n### Jobs Overview\n\n| Job | Trigger | Purpose | Blocking |\n|-----|---------|---------|----------|\n| `check` | PR, push | Format, clippy, UBS, tests | Yes |\n| `coverage` | PR, push | Coverage thresholds | Yes |\n| `memory-tests` | PR, push | Memory leak detection | Yes |\n| `benchmarks` | push to main | Performance budgets | Warn only |\n| `e2e` | PR, push | End-to-end shell tests | Yes |\n| `scan-regression` | PR, push | Scan output stability | Yes |\n| `perf-regression` | PR, push | Process-per-invocation perf | Yes |\n\n### Check Job\n\nRuns format, clippy, UBS static analysis, and unit tests. Includes:\n- `cargo fmt --check` - Code formatting\n- `cargo clippy --all-targets -- -D warnings` - Lints (pedantic + nursery enabled)\n- UBS analysis on changed Rust files (warning-only, non-blocking)\n- `cargo nextest run` - Full test suite with JUnit XML report\n\n### Coverage Job\n\nRuns `cargo llvm-cov` and enforces the thresholds configured in\n`.github/workflows/ci.yml` (`OVERALL_MIN`, `EVALUATOR_MIN`, `HOOK_MIN`).\nThese are enforced gates, not aspirational targets:\n- **Overall:** >= 70%\n- **src/evaluator.rs:** >= 65%\n- **src/hook.rs:** >= 70%\n\nIf CI thresholds change, update this section in the same change. The\n`coverage_threshold_docs` test checks that these documented values stay in sync\nwith the workflow.\n\nCoverage is uploaded to Codecov for trend tracking. Dashboard: https://codecov.io/gh/Dicklesworthstone/destructive_command_guard\n\n### Memory Tests Job\n\nRuns dedicated memory leak tests with:\n- `--test-threads=1` for accurate measurements\n- Release mode for realistic performance\n- 1-2MB growth budgets per test\n\nTests include: hook input parsing, pattern evaluation, heredoc extraction, file extractors, full pipeline, and a self-test that verifies the framework catches leaks.\n\n### Benchmarks Job\n\nRuns on push to main only (benchmarks are noisy on PRs). Checks performance budgets from `src/perf.rs`:\n- Quick reject: < 50us panic\n- Fast path: < 500us panic\n- Pattern match: < 1ms panic\n- Heredoc extract: < 2ms panic\n- Full heredoc pipeline: < 20ms panic\n- Hook evaluation deadline: 1000ms (exhaustion is indeterminate, never a silent allow)\n\n### UBS Static Analysis\n\nUltimate Bug Scanner runs on changed Rust files. Currently warning-only (non-blocking) to tune for false positives. Configuration in `.ubsignore` excludes test/bench/fuzz directories.\n\n### Dependabot\n\nAutomated dependency updates configured in `.github/dependabot.yml`:\n- **Cargo dependencies:** Weekly (Monday 9am EST), 5 PR limit\n- **GitHub Actions:** Weekly (Monday 9am EST), 3 PR limit\n- **Grouping:** Minor/patch updates grouped; serde updates separate (more careful review)\n\n### Debugging CI Failures\n\n#### Coverage Threshold Failure\n1. Check which file(s) dropped below threshold in CI output\n2. Run `cargo llvm-cov --html` locally to see uncovered lines\n3. Add tests for uncovered code paths\n4. Download `coverage-report` artifact for full details\n\n#### Memory Test Failure\n1. Download `memory-test-output` artifact\n2. Check which test failed and growth amount\n3. Run locally: `cargo test --test memory_tests --release -- --nocapture --test-threads=1`\n4. Profile with valgrind if needed\n\n#### UBS Warnings\n1. Check ubs-output.log in CI summary\n2. Review flagged issues - may be false positives\n3. If valid issues, fix them; if false positives, add to `.ubsignore`\n\n#### E2E Test Failure\n1. Download `e2e-artifacts` artifact\n2. Check `e2e_output.json` for failing test details\n3. Run locally: `./scripts/e2e_test.sh --verbose`\n4. The step summary shows the first failure with output\n\n#### Benchmark Regression\n1. Download `benchmark-results` artifact\n2. Compare against budgets in `src/perf.rs`\n3. Profile locally with `cargo bench --bench heredoc_perf`\n4. Check for algorithmic regressions in hot path\n\n---\n\n## Release Process\n\nWhen fixes are ready for release, follow this process:\n\nThe steps below describe the normal GitHub Actions path. If Actions cannot run\nor a native Windows artifact must be built locally, the more detailed\n**Local/DSR Release and Windows Deployment Runbook** near the end of this file\nis authoritative.\n\n### 1. Verify CI Passes Locally\n\n```bash\ncargo fmt --check\ncargo check --all-targets\ncargo clippy --all-targets -- -D warnings\ncargo test\n```\n\n### 2. Commit Changes\n\n```bash\ngit add -A\ngit commit -m \"fix: description of fixes\n\n- List specific fixes\n- Include any breaking changes\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\"\n```\n\n### 3. Bump Version (if needed)\n\nThe version in `Cargo.toml` determines the release tag. A version may be reused\nafter a failed *local, pre-tag* attempt. Once its tag has been pushed or a\nrelease has been published, treat that version as immutable and bump to a new\npatch version instead of moving the tag or replacing signed assets.\n\n- **Patch** (0.2.10 -> 0.2.11): Bug fixes, no new features\n- **Minor** (0.2.x -> 0.3.0): New features, backward compatible\n- **Major** (0.x -> 1.0): Breaking changes\n\n### 4. Push and Trigger Release\n\n```bash\ngit push origin main\ngit push origin main:master  # Keep master in sync\n```\n\nThe `release-automation.yml` workflow will:\n1. Detect version change in `Cargo.toml`\n2. Create an annotated git tag (e.g., `v0.2.13`)\n3. Push the tag, which triggers `dist.yml`\n\nThe `dist.yml` workflow will:\n1. Run tests and clippy\n2. Build binaries for all platforms (Linux x86/ARM, macOS Intel/Apple Silicon, Windows)\n3. Create `.tar.xz` archives with SHA256 checksums\n4. Sign artifacts with Sigstore (cosign) - creates `.sigstore.json` bundles\n5. Upload everything to GitHub Releases\n\n### 5. Verify Release\n\n```bash\ngh release list --limit 5\ngh release view v0.2.13  # Check assets were uploaded\n```\n\nExpected assets per release:\n- `dcg-{target}.tar.xz` (Unix) or `.zip` (Windows) - Binary archive\n- `<archive>.sha256` - Mandatory per-artifact checksum\n- `<archive>.sigstore.json` - Sigstore signature bundle\n- `install.sh`, `install.ps1`, and their checksum/Sigstore sidecars\n- Manual DSR releases additionally include minisign signatures, SLSA\n  provenance, a build manifest, and the pinned public verification keys\n\n### Troubleshooting Failed Releases\n\nIf CI fails:\n1. Check workflow run: `gh run list --workflow=dist.yml --limit=5`\n2. View failed job: `gh run view <run-id>`\n3. Fix issues locally, commit, and push again\n4. If no public tag or release exists yet, retry the same version; otherwise\n   create a new patch release. Never force-move a public release tag.\n\nCommon failures:\n- **Clippy errors**: Fix lints, ensure `cargo clippy -- -D warnings` passes\n- **Test failures**: Run `cargo test` to reproduce\n- **Format errors**: Run `cargo fmt` to fix\n\n---\n\n## MCP Agent Mail — Multi-Agent Coordination\n\nA mail-like layer that lets coding agents coordinate asynchronously via MCP tools and resources. Provides identities, inbox/outbox, searchable threads, and advisory file reservations with human-auditable artifacts in Git.\n\n### Why It's Useful\n\n- **Prevents conflicts:** Explicit file reservations (leases) for files/globs\n- **Token-efficient:** Messages stored in per-project archive, not in context\n- **Quick reads:** `resource://inbox/...`, `resource://thread/...`\n\n### Same Repository Workflow\n\n1. **Register identity:**\n   ```\n   ensure_project(project_key=<abs-path>)\n   register_agent(project_key, program, model)\n   ```\n\n2. **Reserve files before editing:**\n   ```\n   file_reservation_paths(project_key, agent_name, [\"src/**\"], ttl_seconds=3600, exclusive=true)\n   ```\n\n3. **Communicate with threads:**\n   ```\n   send_message(..., thread_id=\"FEAT-123\")\n   fetch_inbox(project_key, agent_name)\n   acknowledge_message(project_key, agent_name, message_id)\n   ```\n\n4. **Quick reads:**\n   ```\n   resource://inbox/{Agent}?project=<abs-path>&limit=20\n   resource://thread/{id}?project=<abs-path>&include_bodies=true\n   ```\n\n### Macros vs Granular Tools\n\n- **Prefer macros for speed:** `macro_start_session`, `macro_prepare_thread`, `macro_file_reservation_cycle`, `macro_contact_handshake`\n- **Use granular tools for control:** `register_agent`, `file_reservation_paths`, `send_message`, `fetch_inbox`, `acknowledge_message`\n\n### Common Pitfalls\n\n- `\"from_agent not registered\"`: Always `register_agent` in the correct `project_key` first\n- `\"FILE_RESERVATION_CONFLICT\"`: Adjust patterns, wait for expiry, or use non-exclusive reservation\n- **Auth errors:** If JWT+JWKS enabled, include bearer token with matching `kid`\n\n---\n\n## Beads (br) — Dependency-Aware Issue Tracking\n\nBeads provides a lightweight, dependency-aware issue database and CLI (`br` - beads_rust) for selecting \"ready work,\" setting priorities, and tracking status. It complements MCP Agent Mail's messaging and file reservations.\n\n**Important:** `br` is non-invasive—it NEVER runs git commands automatically. You must manually commit changes after `br sync --flush-only`.\n\n### Conventions\n\n- **Single source of truth:** Beads for task status/priority/dependencies; Agent Mail for conversation and audit\n- **Shared identifiers:** Use Beads issue ID (e.g., `br-123`) as Mail `thread_id` and prefix subjects with `[br-123]`\n- **Reservations:** When starting a task, call `file_reservation_paths()` with the issue ID in `reason`\n\n### Typical Agent Flow\n\n1. **Pick ready work (Beads):**\n   ```bash\n   br ready --json  # Choose highest priority, no blockers\n   ```\n\n2. **Reserve edit surface (Mail):**\n   ```\n   file_reservation_paths(project_key, agent_name, [\"src/**\"], ttl_seconds=3600, exclusive=true, reason=\"br-123\")\n   ```\n\n3. **Announce start (Mail):**\n   ```\n   send_message(..., thread_id=\"br-123\", subject=\"[br-123] Start: <title>\", ack_required=true)\n   ```\n\n4. **Work and update:** Reply in-thread with progress\n\n5. **Complete and release:**\n   ```bash\n   br close 123 --reason \"Completed\"\n   br sync --flush-only  # Export to JSONL (no git operations)\n   ```\n   ```\n   release_file_reservations(project_key, agent_name, paths=[\"src/**\"])\n   ```\n   Final Mail reply: `[br-123] Completed` with summary\n\n### Mapping Cheat Sheet\n\n| Concept | Value |\n|---------|-------|\n| Mail `thread_id` | `br-###` |\n| Mail subject | `[br-###] ...` |\n| File reservation `reason` | `br-###` |\n| Commit messages | Include `br-###` for traceability |\n\n---\n\n## bv — Graph-Aware Triage Engine\n\nbv is a graph-aware triage engine for Beads projects (`.beads/beads.jsonl`). It computes PageRank, betweenness, critical path, cycles, HITS, eigenvector, and k-core metrics deterministically.\n\n**Scope boundary:** bv handles *what to work on* (triage, priority, planning). For agent-to-agent coordination (messaging, work claiming, file reservations), use MCP Agent Mail.\n\n**CRITICAL: Use ONLY `--robot-*` flags. Bare `bv` launches an interactive TUI that blocks your session.**\n\n### The Workflow: Start With Triage\n\n**`bv --robot-triage` is your single entry point.** It returns:\n- `quick_ref`: at-a-glance counts + top 3 picks\n- `recommendations`: ranked actionable items with scores, reasons, unblock info\n- `quick_wins`: low-effort high-impact items\n- `blockers_to_clear`: items that unblock the most downstream work\n- `project_health`: status/type/priority distributions, graph metrics\n- `commands`: copy-paste shell commands for next steps\n\n```bash\nbv --robot-triage        # THE MEGA-COMMAND: start here\nbv --robot-next          # Minimal: just the single top pick + claim command\n```\n\n### Command Reference\n\n**Planning:**\n| Command | Returns |\n|---------|---------|\n| `--robot-plan` | Parallel execution tracks with `unblocks` lists |\n| `--robot-priority` | Priority misalignment detection with confidence |\n\n**Graph Analysis:**\n| Command | Returns |\n|---------|---------|\n| `--robot-insights` | Full metrics: PageRank, betweenness, HITS, eigenvector, critical path, cycles, k-core, articulation points, slack |\n| `--robot-label-health` | Per-label health: `health_level`, `velocity_score`, `staleness`, `blocked_count` |\n| `--robot-label-flow` | Cross-label dependency: `flow_matrix`, `dependencies`, `bottleneck_labels` |\n| `--robot-label-attention [--attention-limit=N]` | Attention-ranked labels |\n\n**History & Change Tracking:**\n| Command | Returns |\n|---------|---------|\n| `--robot-history` | Bead-to-commit correlations |\n| `--robot-diff --diff-since <ref>` | Changes since ref: new/closed/modified issues, cycles |\n\n**Other:**\n| Command | Returns |\n|---------|---------|\n| `--robot-burndown <sprint>` | Sprint burndown, scope changes, at-risk items |\n| `--robot-forecast <id\\|all>` | ETA predictions with dependency-aware scheduling |\n| `--robot-alerts` | Stale issues, blocking cascades, priority mismatches |\n| `--robot-suggest` | Hygiene: duplicates, missing deps, label suggestions |\n| `--robot-graph [--graph-format=json\\|dot\\|mermaid]` | Dependency graph export |\n| `--export-graph <file.html>` | Interactive HTML visualization |\n\n### Scoping & Filtering\n\n```bash\nbv --robot-plan --label backend              # Scope to label's subgraph\nbv --robot-insights --as-of HEAD~30          # Historical point-in-time\nbv --recipe actionable --robot-plan          # Pre-filter: ready to work\nbv --recipe high-impact --robot-triage       # Pre-filter: top PageRank\nbv --robot-triage --robot-triage-by-track    # Group by parallel work streams\nbv --robot-triage --robot-triage-by-label    # Group by domain\n```\n\n### Understanding Robot Output\n\n**All robot JSON includes:**\n- `data_hash` — Fingerprint of source beads.jsonl\n- `status` — Per-metric state: `computed|approx|timeout|skipped` + elapsed ms\n- `as_of` / `as_of_commit` — Present when using `--as-of`\n\n**Two-phase analysis:**\n- **Phase 1 (instant):** degree, topo sort, density\n- **Phase 2 (async, 500ms timeout):** PageRank, betweenness, HITS, eigenvector, cycles\n\n### jq Quick Reference\n\n```bash\nbv --robot-triage | jq '.quick_ref'                        # At-a-glance summary\nbv --robot-triage | jq '.recommendations[0]'               # Top recommendation\nbv --robot-plan | jq '.plan.summary.highest_impact'        # Best unblock target\nbv --robot-insights | jq '.status'                         # Check metric readiness\nbv --robot-insights | jq '.Cycles'                         # Circular deps (must fix!)\n```\n\n---\n\n## UBS — Ultimate Bug Scanner\n\n**Golden Rule:** `ubs <changed-files>` before every commit. Exit 0 = safe. Exit >0 = fix & re-run.\n\n### Commands\n\n```bash\nubs file.rs file2.rs                    # Specific files (< 1s) — USE THIS\nubs $(git diff --name-only --cached)    # Staged files — before commit\nubs --only=rust,toml src/               # Language filter (3-5x faster)\nubs --ci --fail-on-warning .            # CI mode — before PR\nubs .                                   # Whole project (ignores target/, Cargo.lock)\n```\n\n### Output Format\n\n```\nWarning  Category (N errors)\n    file.rs:42:5 - Issue description\n    Suggested fix\nExit code: 1\n```\n\nParse: `file:line:col` -> location | fix hint -> how to fix | Exit 0/1 -> pass/fail\n\n### Fix Workflow\n\n1. Read finding -> category + fix suggestion\n2. Navigate `file:line:col` -> view context\n3. Verify real issue (not false positive)\n4. Fix root cause (not symptom)\n5. Re-run `ubs <file>` -> exit 0\n6. Commit\n\n### Bug Severity\n\n- **Critical (always fix):** Memory safety, use-after-free, data races, SQL injection\n- **Important (production):** Unwrap panics, resource leaks, overflow checks\n- **Contextual (judgment):** TODO/FIXME, println! debugging\n\n---\n\n## RCH — Remote Compilation Helper\n\nRCH offloads `cargo build`, `cargo test`, `cargo clippy`, and other compilation commands to a fleet of 8 remote Contabo VPS workers instead of building locally. This prevents compilation storms from overwhelming csd when many agents run simultaneously.\n\n**RCH is installed at `~/.local/bin/rch` and is hooked into Claude Code's PreToolUse automatically.** Most of the time you don't need to do anything if you are Claude Code — builds are intercepted and offloaded transparently.\n\nTo manually offload a build:\n```bash\nrch exec -- cargo build --release\nrch exec -- cargo test\nrch exec -- cargo clippy\n```\n\nQuick commands:\n```bash\nrch doctor                    # Health check\nrch workers probe --all       # Test connectivity to all 8 workers\nrch status                    # Overview of current state\nrch queue                     # See active/waiting builds\n```\n\nIf rch or its workers are unavailable, it fails open — builds run locally as normal.\n\n**Note for Codex/GPT-5.2:** Codex does not have the automatic PreToolUse hook, but you can (and should) still manually offload compute-intensive compilation commands using `rch exec -- <command>`. This avoids local resource contention when multiple agents are building simultaneously.\n\n---\n\n## ast-grep vs ripgrep\n\n**Use `ast-grep` when structure matters.** It parses code and matches AST nodes, ignoring comments/strings, and can **safely rewrite** code.\n\n- Refactors/codemods: rename APIs, change import forms\n- Policy checks: enforce patterns across a repo\n- Editor/automation: LSP mode, `--json` output\n\n**Use `ripgrep` when text is enough.** Fastest way to grep literals/regex.\n\n- Recon: find strings, TODOs, log lines, config values\n- Pre-filter: narrow candidate files before ast-grep\n\n### Rule of Thumb\n\n- Need correctness or **applying changes** -> `ast-grep`\n- Need raw speed or **hunting text** -> `rg`\n- Often combine: `rg` to shortlist files, then `ast-grep` to match/modify\n\n### Rust Examples\n\n```bash\n# Find structured code (ignores comments)\nast-grep run -l Rust -p 'fn $NAME($$$ARGS) -> $RET { $$$BODY }'\n\n# Find all unwrap() calls\nast-grep run -l Rust -p '$EXPR.unwrap()'\n\n# Quick textual hunt\nrg -n 'println!' -t rust\n\n# Combine speed + precision\nrg -l -t rust 'unwrap\\(' | xargs ast-grep run -l Rust -p '$X.unwrap()' --json\n```\n\n---\n\n## Morph Warp Grep — AI-Powered Code Search\n\n**Use `mcp__morph-mcp__warp_grep` for exploratory \"how does X work?\" questions.** An AI agent expands your query, greps the codebase, reads relevant files, and returns precise line ranges with full context.\n\n**Use `ripgrep` for targeted searches.** When you know exactly what you're looking for.\n\n**Use `ast-grep` for structural patterns.** When you need AST precision for matching/rewriting.\n\n### When to Use What\n\n| Scenario | Tool | Why |\n|----------|------|-----|\n| \"How is pattern matching implemented?\" | `warp_grep` | Exploratory; don't know where to start |\n| \"Where is the quick reject filter?\" | `warp_grep` | Need to understand architecture |\n| \"Find all uses of `Regex::new`\" | `ripgrep` | Targeted literal search |\n| \"Find files with `println!`\" | `ripgrep` | Simple pattern |\n| \"Replace all `unwrap()` with `expect()`\" | `ast-grep` | Structural refactor |\n\n### warp_grep Usage\n\n```\nmcp__morph-mcp__warp_grep(\n  repoPath: \"/dp/destructive_command_guard\",\n  query: \"How does the safe pattern whitelist work?\"\n)\n```\n\nReturns structured results with file paths, line ranges, and extracted code snippets.\n\n### Anti-Patterns\n\n- **Don't** use `warp_grep` to find a specific function name -> use `ripgrep`\n- **Don't** use `ripgrep` to understand \"how does X work\" -> wastes time with manual reads\n- **Don't** use `ripgrep` for codemods -> risks collateral edits\n\n<!-- bv-agent-instructions-v1 -->\n\n---\n\n## Beads Workflow Integration\n\nThis project uses [beads_rust](https://github.com/Dicklesworthstone/beads_rust) (`br`) for issue tracking. Issues are stored in `.beads/` and tracked in git.\n\n**Important:** `br` is non-invasive—it NEVER executes git commands. After `br sync --flush-only`, you must manually run `git add .beads/ && git commit`.\n\n### Essential Commands\n\n```bash\n# View issues (launches TUI - avoid in automated sessions)\nbv\n\n# CLI commands for agents (use these instead)\nbr ready              # Show issues ready to work (no blockers)\nbr list --status=open # All open issues\nbr show <id>          # Full issue details with dependencies\nbr create --title=\"...\" --type=task --priority=2\nbr update <id> --status=in_progress\nbr close <id> --reason \"Completed\"\nbr close <id1> <id2>  # Close multiple issues at once\nbr sync --flush-only  # Export to JSONL (NO git operations)\n```\n\n### Workflow Pattern\n\n1. **Start**: Run `br ready` to find actionable work\n2. **Claim**: Use `br update <id> --status=in_progress`\n3. **Work**: Implement the task\n4. **Complete**: Use `br close <id>`\n5. **Sync**: Run `br sync --flush-only` then manually commit\n\n### Key Concepts\n\n- **Dependencies**: Issues can block other issues. `br ready` shows only unblocked work.\n- **Priority**: P0=critical, P1=high, P2=medium, P3=low, P4=backlog (use numbers, not words)\n- **Types**: task, bug, feature, epic, question, docs\n- **Blocking**: `br dep add <issue> <depends-on>` to add dependencies\n\n### Session Protocol\n\n**Before ending any session, run this checklist:**\n\n```bash\ngit status              # Check what changed\ngit add <files>         # Stage code changes\nbr sync --flush-only    # Export beads to JSONL\ngit add .beads/         # Stage beads changes\ngit commit -m \"...\"     # Commit everything together\ngit push                # Push to remote\n```\n\n### Best Practices\n\n- Check `br ready` at session start to find available work\n- Update status as you work (in_progress -> closed)\n- Create new issues with `br create` when you discover tasks\n- Use descriptive titles and set appropriate priority/type\n- Always `br sync --flush-only && git add .beads/` before ending session\n\n<!-- end-bv-agent-instructions -->\n\n## Landing the Plane (Session Completion)\n\n**When ending a work session**, you MUST complete ALL steps below.\n\n**MANDATORY WORKFLOW:**\n\n1. **File issues for remaining work** - Create issues for anything that needs follow-up\n2. **Run quality gates** (if code changed) - Tests, linters, builds\n3. **Update issue status** - Close finished work, update in-progress items\n4. **Sync beads** - `br sync --flush-only` to export to JSONL\n5. **Hand off** - Provide context for next session\n\n\n---\n\n## cass — Cross-Agent Session Search\n\n`cass` indexes prior agent conversations (Claude Code, Codex, Cursor, Gemini, ChatGPT, etc.) so we can reuse solved problems.\n\n**Rules:** Never run bare `cass` (TUI). Always use `--robot` or `--json`.\n\n### Examples\n\n```bash\ncass health\ncass search \"async runtime\" --robot --limit 5\ncass view /path/to/session.jsonl -n 42 --json\ncass expand /path/to/session.jsonl -n 42 -C 3 --json\ncass capabilities --json\ncass robot-docs guide\n```\n\n### Tips\n\n- Use `--fields minimal` for lean output\n- Filter by agent with `--agent`\n- Use `--days N` to limit to recent history\n\nstdout is data-only, stderr is diagnostics; exit code 0 means success.\n\nTreat cass as a way to avoid re-solving problems other agents already handled.\n\n---\n\n## Local/DSR Release and Windows Deployment Runbook\n\nUse this fallback only when GitHub Actions cannot perform the release, when a\nnative-host build is explicitly required, or when the user directs you to use\nDSR. It refines the shorter release checklist above. Do not jump straight to\n`dsr fallback`: keep source freezing, build, packaging, signing, publication,\nand public verification as separately inspectable stages.\n\n### Non-Negotiable Release Invariants\n\n1. **One immutable source identity.** The local `HEAD`, peeled release tag,\n   remote `main`, compatibility branch, build checkout, build manifest, and\n   published release must all name the same commit.\n2. **Frozen bytes before signatures.** Finish archive layout and names before\n   generating checksums, SLSA provenance, minisign signatures, or Sigstore\n   bundles. Any byte or filename change invalidates downstream metadata and\n   requires regenerating and reverifying it.\n3. **Integrity is not authenticity.** SHA256 is mandatory, but it does not\n   authenticate the publisher. Manual releases require the DSR minisign trust\n   path and the pinned local-release cosign trust path. Workflow releases use\n   GitHub Actions OIDC for Sigstore.\n4. **No destructive synchronization or cleanup.** Assume an automatic source\n   mirror may delete files until its dry-run proves otherwise. Never bypass dcg\n   to clean a checkout, output directory, key copy, or failed release. Rule 1\n   still applies to temporary files and directories.\n5. **A partial matrix must be deliberate.** A working Windows artifact does not\n   prove that every advertised target exists. Define the expected target/asset\n   matrix before building and either satisfy it or explicitly treat the release\n   as an emergency partial release with tested source-install fallback.\n\n### 1. Decide the Path and Freeze the Source\n\nFirst inspect Actions rather than waiting blindly:\n\n```bash\ngh run list --limit 20\ndsr check Dicklesworthstone/destructive_command_guard\n```\n\nIf the manual path is justified, run all release gates *before* tagging:\n\n```bash\ncargo fmt --check\ncargo check --all-targets\ncargo clippy --all-targets -- -D warnings\ncargo test\ncargo check --target x86_64-pc-windows-gnu --lib\ncargo build --release\n./scripts/e2e_test.sh --verbose\npwsh -NoProfile -File ./scripts/e2e_test.ps1 -Verbose\n```\n\nRun any additional gates relevant to the changed surface. A release candidate\nwith code changes receives the full suite; a crate-scoped or `--lib` run is not\na release substitute. Both E2E scripts discover the release binary through\n`CARGO_TARGET_DIR` and reject a stale in-repository binary. If `--binary` /\n`-Binary` is supplied explicitly, pass an absolute path: the suites change\ndirectories while testing isolated configurations. If local PowerShell is\nunavailable, run the PowerShell suite against the native release candidate on\nthe Windows build host before publication.\n\nConfirm the worktree contains only intentional release content, commit it, then\ncreate an annotated tag. Never force an existing public tag:\n\n```bash\nVERSION=vX.Y.Z\ngit status --short\ngit tag -a \"$VERSION\" -m \"Release $VERSION\"\ngit push origin main\ngit push origin main:master\ngit push origin \"$VERSION\"\n```\n\nChoose exactly one owner for the tag and release. If the local path owns them,\ndo not also let `release-automation` create the same tag in parallel.\n\nRecord and compare the identities instead of trusting labels:\n\n```bash\nHEAD_SHA=$(git rev-parse HEAD)\nTAG_SHA=$(git rev-parse \"${VERSION}^{commit}\")\ntest \"$HEAD_SHA\" = \"$TAG_SHA\"\ngit ls-remote origin refs/heads/main refs/heads/master \"refs/tags/$VERSION\" \"refs/tags/$VERSION^{}\"\n```\n\nFor an annotated tag, compare against the peeled `^{}`\nentry—not the tag-object SHA. If any identity differs, stop before building.\nDo not “repair” a published tag; make a patch release.\n\n### 2. Preflight DSR and the Native Windows Host\n\nValidate configuration, target naming, quality commands, host health, disk\nspace, and the exact build plan:\n\n```bash\ndsr repos validate --repo destructive_command_guard\ndsr quality --tool destructive_command_guard --dry-run\ndsr health all --no-cache\ndsr build destructive_command_guard \\\n  --version \"${VERSION#v}\" \\\n  --target windows/amd64 \\\n  --dry-run\n```\n\nThe installer asset name, DSR `artifact_naming`, target triple, archive format,\nand release upload name must agree. A naming mismatch can silently trigger a\nsource build instead of installing the native artifact.\n\nTreat DSR's automatic remote source sync as deletion-capable. Under this\nrepository's no-deletion rule, do not sync into an existing checkout. For a\nnative build:\n\n1. Create a brand-new checkout path on the Windows host at the exact tag.\n2. Verify that checkout's `HEAD` equals `TAG_SHA` and that its worktree is\n   clean.\n3. Temporarily point DSR's host source mapping at that fresh checkout.\n4. Use a brand-new output path and run the build with `--no-sync`:\n\n   ```bash\n   dsr build destructive_command_guard \\\n     --version \"${VERSION#v}\" \\\n     --target windows/amd64 \\\n     --no-sync \\\n     --output-dir <brand-new-output-directory>\n   ```\n\n5. Restore the previous DSR host mapping immediately after collection, even\n   when the build or artifact collection fails.\n\nDo not remove the staged checkout or output directory without the user's\nwritten permission. Record the native host, target triple, commit SHA, Rust\ntoolchain, build duration, and collected executable SHA256 in the release\nnotes/manifest. Monitor a long native build instead of starting a competing\nbuild because it appears quiet.\n\n### 3. Package the Native Artifact Correctly\n\nDSR may successfully collect `dcg.exe` even when the coordinator lacks a ZIP\ntool. That is a packaging failure, not a compile failure. In that case, package\nthe collected executable on Windows with PowerShell `Compress-Archive`.\n\nThe Windows release ZIP must contain exactly one root entry named `dcg.exe`.\nBefore signing:\n\n- Extract the ZIP into a new inspection directory.\n- Hash the extracted `dcg.exe`.\n- Confirm that hash equals the collected native PE hash recorded by DSR.\n- Run the extracted binary and confirm its version matches `VERSION`.\n- Confirm it is the native MSVC release build—not a GNU compile-check artifact,\n  debug binary, stale binary, or installer smoke fixture.\n\nNever rename arbitrary bytes to make them look like a ZIP, and never package a\ndifferent binary merely because it has the expected filename.\n\n### 4. Freeze, Checksum, and Sign the Complete Asset Set\n\nWrite down the expected assets before signing. Depending on release scope this\nincludes archives, standalone binaries, installers, the build manifest,\nper-file `.sha256` sidecars, `SHA256SUMS`, SLSA `.intoto.jsonl` provenance,\n`.minisig` files, `.sigstore.json` bundles, and public verification keys.\n\nThe order is strict:\n\n1. Finalize payload bytes and filenames.\n2. Generate per-file SHA256 sidecars and the aggregate checksum manifest.\n3. Generate and verify SLSA provenance against the frozen payload.\n4. Sign publishable payloads and metadata with DSR minisign.\n5. Generate key-based cosign bundles for the local-release trust path.\n6. Independently verify every signature and bundle.\n\nUse DSR's configured private keys directly from its protected secret location.\nPrivate keys and password material must remain mode `600` and must never be\ncopied into the repository, release directory, generic temporary directory, or\nremote build checkout. Publish only public keys and their fingerprints. If\nduplicate secret material is discovered, stop and follow Rule 1; do not set\n`DCG_BYPASS` or otherwise evade a blocked cleanup command.\n\nBefore publication, confirm that:\n\n- `install.sh`, `install.ps1`, and `README.md` agree on the current minisign\n  public key and local cosign public-key fingerprint.\n- A retired key is accepted only for the exact historical release that used\n  it, never as an unbounded fallback.\n- The cosign verifier meets the installer's patched-version floor\n  (2.6.2+ on v2 or 3.0.4+ on v3); unknown, development, and prerelease version\n  strings fail closed for signature verification.\n\nOnce signing begins, treat the directory as immutable. If a checksum generator,\nuploader, or packaging tool wants to rewrite `SHA256SUMS`, a sidecar, or an\narchive, stop and restart the checksum/signature stages from the newly frozen\nbytes.\n\n### 5. Verify Locally and on the Native Windows Machine\n\nPerform positive and negative tests before uploading:\n\n- SHA256, minisign, cosign, and SLSA verification all succeed independently.\n- A valid artifact paired with the wrong minisign signature fails.\n- A valid artifact paired with the wrong Sigstore bundle fails.\n- A modified artifact fails every applicable integrity/authenticity check.\n- `install.ps1` installs the local artifact into a fresh destination with\n  `-RequireMinisign -Verify -NoConfigure -Force`, using explicit local\n  artifact/checksum/signature/bundle inputs.\n- The installed binary hash equals the signed payload hash, reports the\n  expected version, and passes the installer self-test.\n\nRun the installer twice in a hermetic Windows home and confirm hook\nconfiguration is idempotent: one dcg-owned hook per supported integration,\ncoexisting hooks preserved, valid JSON without a UTF-8 BOM, and no stale dcg\nentry. Run `dcg doctor` and `dcg config --format json`; do not guess config\npaths, enabled packs, timeout sources, or whether two visually similar hook\nentries are actually duplicates. On native Windows the canonical user config is\n`%APPDATA%\\dcg\\config.toml`; the legacy `~/.config/dcg/config.toml` may also be\nhonored, so use the config report to identify the file that actually won.\n\nFor the `careful_company_running_windows` preset, verify the effective 3000 ms\ndefault hook budget on a cold Windows process and confirm all six preset\nsub-packs plus the curated transitive members are active. Then test\nrepresentative allow and deny cases through both PowerShell and `cmd.exe` hook\npayloads, including outbound mail/upload blocks and the structural `hfdt`\nexception (plain `hfdt` allowed; chaining, redirection, and substitution are not\nimplicitly trusted). Exercise committed `.ps1`, `.cmd`, and `.bat` fixtures with\n`dcg scan` rather than placing an intentionally blocked test string on the\nguarded operator shell's own command line.\n\nWindows PowerShell 5.1 has two diagnostic traps:\n\n- Successful native programs such as cosign and `dcg --version` may write to\n  stderr. With `$ErrorActionPreference = 'Stop'` and merged streams, PowerShell\n  can wrap this as `NativeCommandError`. Temporarily make native stderr\n  non-terminating and decide success from the native process exit code.\n- `$LASTEXITCODE` can be stale after invoking a PowerShell script in-process.\n  For installer acceptance, launch a child PowerShell process, wait for it, and\n  inspect that process object's `ExitCode`.\n\nOlder dcg versions could not replace their own running `dcg.exe`. The current\nupdater has a deferred Windows swap path, but every release must retain the\nreal-Windows running-binary update/rollback test. When recovering an older\ninstallation that lacks the fix, run the release installer directly.\n\n### 6. Inspect the Upload Plan, Then Publish\n\nNever assume an uploader is byte-preserving or complete. Run its dry-run/upload\nplan before signing when possible, and compare the selected filenames with the\nfrozen expected-asset list.\n\nAn observed DSR failure mode is regenerating aggregate checksum metadata during\nrelease assembly while omitting installers or `.sigstore.json` bundles from the\nselected upload set. If the current `dsr release` plan would mutate signed\nmetadata or omit required files, do not use it for publication. DSR can still\nprovide the native build, manifest, minisign signatures, and SLSA provenance;\npublish the frozen files with an explicit, enumerated `gh release create` /\n`gh release upload` invocation instead.\n\nPrefer assembling assets on a draft release. Never use `--clobber` on a signed\nasset and never replace an asset behind an existing public URL. If published\nbytes are wrong, withdraw the bad release as directed by the user and issue a\nnew patch version.\n\nIf a local release is now authoritative, inspect queued GitHub workflows. Cancel\nonly `dist` / release-automation runs that could race to create or replace the\nsame release. Do not cancel unrelated CI, coverage, or benchmark runs.\n\n### 7. Verify the Published Release From Scratch\n\nDownload the release into a new local directory and verify it without relying\non build-directory state:\n\n1. Compare the public asset names with the frozen expected-asset list.\n2. Verify the aggregate and per-file SHA256 data.\n3. Verify every minisign signature using the published/pinned public key.\n4. Verify every Sigstore bundle against the correct local-key or Actions-OIDC\n   trust root.\n5. Verify every SLSA subject digest against its public artifact.\n6. Confirm the release is public, non-draft, and has the intended prerelease\n   status.\n\nThen run the installer from the *public release URL* on the native Windows host\ninto a fresh destination. Pin `-Version`, require minisign, enable `-Verify`,\nand confirm the installed hash, version, self-test, `dcg doctor`, effective\nconfig, hook idempotency, and representative PowerShell/`cmd.exe` policy\nbehavior. A local-file install does not substitute for this public-path test.\n\nFinally verify the repository invariants again:\n\n```bash\ngit status --short\ngit rev-parse HEAD\ngit rev-parse \"${VERSION}^{commit}\"\ngit ls-remote origin refs/heads/main refs/heads/master \"refs/tags/$VERSION\" \"refs/tags/$VERSION^{}\"\ngh release view \"$VERSION\"\n```\n\nThe release is complete only when the source identities agree, the worktree is\nclean, all intended assets are publicly downloadable and independently\nverifiable, and a fresh native Windows installation succeeds from the public\nrelease.\n\n---\n\nNote for Codex/GPT-5.2:\n\nYou constantly bother me and stop working with concerned questions that look similar to this:\n\n```\nUnexpected changes (need guidance)\n\n- Working tree still shows edits I did not make in Cargo.toml, Cargo.lock, src/cli/commands/upgrade.rs, src/storage/sqlite.rs, tests/conformance.rs, tests/storage_deps.rs. Please advise whether to keep/commit/revert these before any further work. I did not touch them.\n\nNext steps (pick one)\n\n1. Decide how to handle the unrelated modified files above so we can resume cleanly.\n2. Triage beads_rust-orko (clippy/cargo warnings) and beads_rust-ydqr (rustfmt failures).\n3. If you want a full suite run later, fix conformance/clippy blockers and re-run cargo test --all.\n```\n\nNEVER EVER DO THAT AGAIN. The answer is literally ALWAYS the same: those are changes created by the potentially dozen of other agents working on the project at the same time. This is not only a common occurrence, it happens multiple times PER MINUTE. The way to deal with it is simple: you NEVER, under ANY CIRCUMSTANCE, stash, revert, overwrite, or otherwise disturb in ANY way the work of other agents. Just treat those changes identically to changes that you yourself made. Just fool yourself into thinking YOU made the changes and simply don't recall it for some reason.\n\n---\n\n## Note on Built-in TODO Functionality\n\nAlso, if I ask you to explicitly use your built-in TODO functionality, don't complain about this and say you need to use beads. You can use built-in TODOs if I tell you specifically to do so. Always comply with such orders.\n","category":"root","tokens":16965}]}