# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview A Claude Code and OpenCode plugin that blocks destructive git and filesystem commands before execution. It works as a PreToolUse hook that intercepts Bash commands and denies dangerous operations like `git reset --hard`, `rm -rf`, and `git checkout -- `. ## Commands - **Setup**: `bun install` - **All checks**: `bun run check` (runs lint, typecheck, knip, ast-grep scan, tests) - **Single test**: `bun test tests/file.test.ts` - **Lint**: `bun run lint` (uses Biome) - **Type check**: `bun run typecheck` - **Dead code**: `bun run knip` - **AST scan**: `bun run sg:scan` - **Build**: `bun run build` ## Architecture The hook receives JSON input on stdin containing `tool_name` and `tool_input`. For `Bash` tools, it analyzes the command and outputs JSON with `permissionDecision: "deny"` to block dangerous operations. **Entry points**: - `src/bin/cc-safety-net.ts` — Claude Code CLI (reads stdin JSON) - `src/index.ts` — OpenCode plugin export **Core analysis flow**: 1. `cc-safety-net.ts:main()` parses JSON input, extracts command 2. `analyze.ts:analyzeCommand()` splits command on shell operators (`;`, `&&`, `|`, etc.) 3. `analyzeSegment()` tokenizes each segment, strips wrappers (sudo, env), identifies the command 4. Dispatches to `rules-git.ts:analyzeGit()` or `rules-rm.ts:analyzeRm()` based on command 5. Checks custom rules via `rules-custom.ts:checkCustomRules()` if configured **Key modules** (`src/core/`): - `shell.ts`: Shell parsing (`splitShellCommands`, `shlexSplit`, `stripWrappers`, `shortOpts`) - `rules-git.ts`: Git subcommand analysis (checkout, restore, reset, clean, push, branch, stash) - `rules-rm.ts`: rm analysis (allows rm -rf within cwd except when cwd is $HOME; temp paths always allowed; strict mode blocks non-temp) - `config.ts`: Config loading, validation, merging (user `~/.cc-safety-net/config.json` + project `.safety-net.json`) - `rules-custom.ts`: Custom rule matching (`checkCustomRules()`) - `audit.ts`: Audit logging for blocked commands - `verify-config.ts`: Config validator **Test utilities** (`tests/helpers.ts`): - `assertBlocked()`, `assertAllowed()` helpers for testing command analysis **Advanced detection**: - Recursively analyzes shell wrappers (`bash -c '...'`) up to 5 levels deep - Detects destructive commands in interpreter one-liners (`python -c`, `node -e`, `ruby -e`, `perl -e`) - Handles `xargs` and `parallel` with template expansion and dynamic input detection - Detects `find -delete` and `find -exec rm` patterns - Redacts secrets (tokens, passwords, API keys) in block messages and audit logs - Audit logging: blocked commands logged to `~/.cc-safety-net/logs/.jsonl` ## Code Style (TypeScript) - Use Bun instead of Node.js for running, testing, and building - Biome for linting and formatting - All functions require type annotations - Use `type | null` syntax (not `undefined` where possible) - Use kebab-case for file names (`rules-git.ts`, not `rulesGit.ts`) ## Commit Conventions When committing changes to files in `commands/`, `hooks/`, or `.opencode/`, use only `fix` or `feat` commit types. These directories contain user-facing skill definitions and hook configurations that represent features or fixes to the plugin's capabilities. ## Environment Variables - `SAFETY_NET_STRICT=1`: Strict mode (fail-closed on unparseable hook input/commands) - `SAFETY_NET_PARANOID=1`: Paranoid mode (enables all paranoid checks) - `SAFETY_NET_PARANOID_RM=1`: Paranoid rm (blocks non-temp `rm -rf` even within cwd) - `SAFETY_NET_PARANOID_INTERPRETERS=1`: Paranoid interpreters (blocks interpreter one-liners) ## Custom Rules Users can define additional blocking rules in two scopes (merged, project overrides user): - **User scope**: `~/.cc-safety-net/config.json` (applies to all projects) - **Project scope**: `.safety-net.json` (in project root) Rules are additive only—cannot bypass built-in protections. Invalid config silently falls back to built-in rules only. ## Testing Use `AGENT=1 bun test` to run tests. ## Bun Best Practices - Use `bun ` instead of `node ` or `ts-node ` - Use `bun test` instead of `jest` or `vitest` - Use `bun build` instead of `webpack` or `esbuild` - Use `bun install` instead of `npm install` - Use `bun run