cc-safety-net 0.9.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +335 -122
  2. package/dist/bin/cc-safety-net.js +7974 -4618
  3. package/dist/bin/commands/doctor.d.ts +11 -2
  4. package/dist/bin/commands/explain.d.ts +16 -2
  5. package/dist/bin/commands/hook.d.ts +14 -0
  6. package/dist/bin/commands/index.d.ts +67 -3
  7. package/dist/bin/commands/rule.d.ts +14 -0
  8. package/dist/bin/commands/statusline.d.ts +10 -2
  9. package/dist/bin/commands/types.d.ts +11 -0
  10. package/dist/bin/doctor/config.d.ts +1 -1
  11. package/dist/bin/doctor/hooks.d.ts +2 -1
  12. package/dist/bin/doctor/system-info.d.ts +6 -2
  13. package/dist/bin/doctor/types.d.ts +26 -1
  14. package/dist/bin/explain/config.d.ts +3 -1
  15. package/dist/bin/hook/common.d.ts +20 -0
  16. package/dist/bin/hook/config-edit.d.ts +11 -0
  17. package/dist/bin/hook/constants.d.ts +6 -0
  18. package/dist/bin/hook/install/kimi-cli.d.ts +3 -0
  19. package/dist/bin/hook/install/types.d.ts +4 -0
  20. package/dist/bin/hook/install.d.ts +3 -0
  21. package/dist/bin/hook/integrations.d.ts +12 -0
  22. package/dist/bin/hook/kimi-cli.d.ts +1 -0
  23. package/dist/bin/integration-metadata.d.ts +68 -0
  24. package/dist/bin/rule/doc.d.ts +1 -0
  25. package/dist/bin/rule/format.d.ts +21 -0
  26. package/dist/bin/rule/index.d.ts +1 -0
  27. package/dist/bin/rule/migrate.d.ts +6 -0
  28. package/dist/bin/rule/verify.d.ts +9 -0
  29. package/dist/builtin-commands/templates/cc-safety-net.d.ts +1 -0
  30. package/dist/core/analyze/analyze-command.d.ts +0 -10
  31. package/dist/core/analyze/awk.d.ts +3 -0
  32. package/dist/core/analyze/child-analyzer.d.ts +16 -0
  33. package/dist/core/analyze/child-command.d.ts +15 -0
  34. package/dist/core/analyze/find.d.ts +8 -6
  35. package/dist/core/analyze/index.d.ts +4 -0
  36. package/dist/core/{rules-rm.d.ts → analyze/rm.d.ts} +0 -1
  37. package/dist/core/analyze/shell-git-env.d.ts +10 -0
  38. package/dist/core/analyze/xargs.d.ts +0 -1
  39. package/dist/core/audit.d.ts +3 -0
  40. package/dist/core/config.d.ts +5 -3
  41. package/dist/core/env.d.ts +39 -1
  42. package/dist/core/format.d.ts +1 -0
  43. package/dist/core/git/config.d.ts +1 -0
  44. package/dist/core/git/env.d.ts +12 -0
  45. package/dist/core/git/index.d.ts +3 -0
  46. package/dist/core/git/parse.d.ts +9 -0
  47. package/dist/core/git/rules.d.ts +8 -0
  48. package/dist/core/git/worktree-relaxation.d.ts +11 -0
  49. package/dist/core/{worktree.d.ts → git/worktree.d.ts} +1 -5
  50. package/dist/core/rules/custom-rule-validation.d.ts +5 -0
  51. package/dist/core/rules/policy/config-file.d.ts +19 -0
  52. package/dist/core/rules/policy/index.d.ts +6 -0
  53. package/dist/core/rules/policy/lockfile.d.ts +5 -0
  54. package/dist/core/rules/policy/paths.d.ts +31 -0
  55. package/dist/core/rules/policy/resolver.d.ts +16 -0
  56. package/dist/core/rules/policy/scope-policy.d.ts +18 -0
  57. package/dist/core/rules/policy/sources.d.ts +28 -0
  58. package/dist/core/rules/policy/sync.d.ts +10 -0
  59. package/dist/core/rules/policy/types.d.ts +77 -0
  60. package/dist/core/rules/rulebook.d.ts +28 -0
  61. package/dist/core/shell/command.d.ts +2 -0
  62. package/dist/core/shell/index.d.ts +4 -0
  63. package/dist/core/shell/options.d.ts +3 -0
  64. package/dist/core/shell/segments.d.ts +6 -0
  65. package/dist/core/shell/shared.d.ts +4 -0
  66. package/dist/core/{shell.d.ts → shell/wrappers.d.ts} +0 -6
  67. package/dist/index.d.ts +1 -1
  68. package/dist/index.js +4205 -2231
  69. package/dist/{features → opencode}/builtin-commands/commands.d.ts +1 -1
  70. package/dist/opencode/builtin-commands/index.d.ts +2 -0
  71. package/dist/{features → opencode}/builtin-commands/types.d.ts +1 -1
  72. package/dist/pi/builtin-commands/commands.d.ts +15 -0
  73. package/dist/pi/builtin-commands/index.d.ts +1 -0
  74. package/dist/pi/index.d.ts +5 -0
  75. package/dist/pi/index.js +6405 -0
  76. package/dist/pi/tool-use.d.ts +20 -0
  77. package/dist/types.d.ts +32 -2
  78. package/package.json +16 -8
  79. package/dist/bin/commands/claude-code.d.ts +0 -2
  80. package/dist/bin/commands/copilot-cli.d.ts +0 -2
  81. package/dist/bin/commands/custom-rules-doc.d.ts +0 -2
  82. package/dist/bin/commands/gemini-cli.d.ts +0 -2
  83. package/dist/bin/commands/verify-config.d.ts +0 -2
  84. package/dist/bin/custom-rules-doc.d.ts +0 -1
  85. package/dist/bin/verify-config.d.ts +0 -12
  86. package/dist/core/analyze.d.ts +0 -21
  87. package/dist/core/rules-git.d.ts +0 -20
  88. package/dist/features/builtin-commands/index.d.ts +0 -2
  89. package/dist/features/builtin-commands/templates/set-custom-rules.d.ts +0 -1
  90. package/dist/features/builtin-commands/templates/verify-custom-rules.d.ts +0 -1
  91. /package/dist/bin/{hooks → hook}/claude-code.d.ts +0 -0
  92. /package/dist/bin/{hooks → hook}/copilot-cli.d.ts +0 -0
  93. /package/dist/bin/{hooks → hook}/gemini-cli.d.ts +0 -0
  94. /package/dist/core/{rules-custom.d.ts → rules/custom.d.ts} +0 -0
package/README.md CHANGED
@@ -1,13 +1,15 @@
1
- # Claude Code Safety Net
1
+ # CC Safety Net
2
2
 
3
- [![CI](https://github.com/kenryu42/claude-code-safety-net/actions/workflows/ci.yml/badge.svg)](https://github.com/kenryu42/claude-code-safety-net/actions/workflows/ci.yml)
4
- [![codecov](https://codecov.io/github/kenryu42/claude-code-safety-net/branch/main/graph/badge.svg?token=C9QTION6ZF)](https://codecov.io/github/kenryu42/claude-code-safety-net)
5
- [![Version](https://img.shields.io/github/v/tag/kenryu42/claude-code-safety-net?label=version&color=blue)](https://github.com/kenryu42/claude-code-safety-net)
3
+ [![CI](https://github.com/kenryu42/cc-safety-net/actions/workflows/ci.yml/badge.svg)](https://github.com/kenryu42/cc-safety-net/actions/workflows/ci.yml)
4
+ [![codecov](https://codecov.io/github/kenryu42/cc-safety-net/branch/main/graph/badge.svg?token=C9QTION6ZF)](https://codecov.io/github/kenryu42/cc-safety-net)
5
+ [![Version](https://img.shields.io/github/v/tag/kenryu42/cc-safety-net?label=version&color=blue)](https://github.com/kenryu42/cc-safety-net)
6
+ [![Codex](https://img.shields.io/badge/Codex-white)](#codex-installation)
6
7
  [![Claude Code](https://img.shields.io/badge/Claude%20Code-D27656)](#claude-code-installation)
7
- [![OpenCode](https://img.shields.io/badge/OpenCode-black)](#opencode-installation)
8
- [![Gemini CLI](https://img.shields.io/badge/Gemini%20CLI-678AE3)](#gemini-cli-installation)
9
8
  [![Copilot CLI](https://img.shields.io/badge/Copilot%20CLI-4EA5C9)](#github-copilot-cli-installation)
10
- [![Codex](https://img.shields.io/badge/Codex-white)](#codex-installation)
9
+ [![Gemini CLI](https://img.shields.io/badge/Gemini%20CLI-678AE3)](#gemini-cli-installation)
10
+ [![Kimi CLI](https://img.shields.io/badge/Kimi%20CLI-5587FF)](#kimi-cli-installation)
11
+ [![OpenCode](https://img.shields.io/badge/OpenCode-black)](#opencode-installation)
12
+ [![Pi](https://img.shields.io/badge/Pi%20Coding-22262E)](#pi-installation)
11
13
  [![License: MIT](https://img.shields.io/badge/License-MIT-red.svg)](https://opensource.org/licenses/MIT)
12
14
 
13
15
  <div align="center">
@@ -16,7 +18,7 @@
16
18
 
17
19
  </div>
18
20
 
19
- A Claude Code plugin that acts as a safety net, catching destructive git and filesystem commands before they execute.
21
+ A Coding Agent CLI plugin that acts as a safety net, catching destructive git and filesystem commands before they execute.
20
22
 
21
23
  ## Contents
22
24
 
@@ -25,14 +27,14 @@ A Claude Code plugin that acts as a safety net, catching destructive git and fil
25
27
  - [What About Sandboxing?](#what-about-sandboxing)
26
28
  - [Prerequisites](#prerequisites)
27
29
  - [Quick Start](#quick-start)
30
+ - [Codex Installation](#codex-installation)
28
31
  - [Claude Code Installation](#claude-code-installation)
29
- - [OpenCode Installation](#opencode-installation)
30
32
  - [Gemini CLI Installation](#gemini-cli-installation)
31
33
  - [GitHub Copilot CLI Installation](#github-copilot-cli-installation)
32
- - [Codex Installation](#codex-installation)
34
+ - [Kimi CLI Installation](#kimi-cli-installation)
35
+ - [OpenCode Installation](#opencode-installation)
36
+ - [Pi Installation](#pi-installation)
33
37
  - [Status Line Integration](#status-line-integration)
34
- - [Setup via Slash Command](#setup-via-slash-command)
35
- - [Manual Setup](#manual-setup)
36
38
  - [Emoji Mode Indicators](#emoji-mode-indicators)
37
39
  - [Diagnostics](#diagnostics)
38
40
  - [Explain (Debug Analysis)](#explain-debug-analysis)
@@ -40,12 +42,12 @@ A Claude Code plugin that acts as a safety net, catching destructive git and fil
40
42
  - [Commands Allowed](#commands-allowed)
41
43
  - [What Happens When Blocked](#what-happens-when-blocked)
42
44
  - [Testing the Hook](#testing-the-hook)
43
- - [Development](#development)
44
- - [Custom Rules (Experimental)](#custom-rules-experimental)
45
+ - [Breaking Change: Custom Rules Migration](#breaking-change-custom-rules-migration)
46
+ - [Custom Rules](#custom-rules)
45
47
  - [Config File Location](#config-file-location)
46
48
  - [Rule Schema](#rule-schema)
47
49
  - [Matching Behavior](#matching-behavior)
48
- - [Examples](#examples)
50
+ - [Rule Examples](#rule-examples)
49
51
  - [Error Handling](#error-handling)
50
52
  - [Advanced Features](#advanced-features)
51
53
  - [Strict Mode](#strict-mode)
@@ -55,6 +57,7 @@ A Claude Code plugin that acts as a safety net, catching destructive git and fil
55
57
  - [Interpreter One-Liner Detection](#interpreter-one-liner-detection)
56
58
  - [Secret Redaction](#secret-redaction)
57
59
  - [Audit Logging](#audit-logging)
60
+ - [Development](#development)
58
61
  - [License](#license)
59
62
 
60
63
  ## Why This Exists
@@ -69,12 +72,12 @@ Claude Code's `.claude/settings.json` supports [deny rules](https://code.claude.
69
72
 
70
73
  ### At a Glance
71
74
 
72
- | | Permission Deny Rules | Safety Net |
75
+ | | Permission Deny Rules | CC Safety Net |
73
76
  |---|---|---|
74
77
  | **Setup** | Manual configuration required | Works out of the box |
75
78
  | **Parsing** | Wildcard pattern matching | Semantic command analysis |
76
79
  | **Execution order** | Runs second | Runs first (PreToolUse hook) |
77
- | **Shell wrappers** | Not handled automatically (must match wrapper forms) | Recursively analyzed (5 levels) |
80
+ | **Shell wrappers** | Not handled automatically (must match wrapper forms) | Recursively analyzed (up to 10 levels) |
78
81
  | **Interpreter one-liners** | Not handled automatically (must match interpreter forms) | Detected and blocked |
79
82
 
80
83
  ### Permission Rules Have Known Bypass Vectors
@@ -89,9 +92,9 @@ Even with wildcard matching, Bash permission patterns are intentionally limited
89
92
  | Extra whitespace | `rm -rf /` (double space) bypasses pattern |
90
93
  | Shell wrappers | `sh -c "rm -rf /"` bypasses `Bash(rm:*)` entirely |
91
94
 
92
- ### Safety Net Handles What Patterns Can't
95
+ ### CC Safety Net Handles What Patterns Can't
93
96
 
94
- | Scenario | Permission Rules | Safety Net |
97
+ | Scenario | Permission Rules | CC Safety Net |
95
98
  |----------|------------------|------------|
96
99
  | `git checkout -b feature` (safe) | Blocked by `Bash(git checkout:*)` | Allowed |
97
100
  | `git checkout -- file` (dangerous) | Blocked by `Bash(git checkout:*)` | Blocked |
@@ -102,17 +105,17 @@ Even with wildcard matching, Bash permission patterns are intentionally limited
102
105
 
103
106
  ### Defense in Depth
104
107
 
105
- PreToolUse hooks run [**before**](https://code.claude.com/docs/en/iam#additional-permission-control-with-hooks) the permission system. This means Safety Net inspects every command first, regardless of your permission configuration. Even if you misconfigure deny rules, Safety Net provides a fallback layer of protection.
108
+ PreToolUse hooks run [**before**](https://code.claude.com/docs/en/iam#additional-permission-control-with-hooks) the permission system. This means CC Safety Net inspects every command first, regardless of your permission configuration. Even if you misconfigure deny rules, CC Safety Net provides a fallback layer of protection.
106
109
 
107
- **Use both together**: Permission deny rules for quick, user-configurable blocks; Safety Net for robust, bypass-resistant protection that works out of the box.
110
+ **Use both together**: Permission deny rules for quick, user-configurable blocks; CC Safety Net for robust, bypass-resistant protection that works out of the box.
108
111
 
109
112
  ## What About Sandboxing?
110
113
 
111
- Claude Code offers [native sandboxing](https://code.claude.com/docs/en/sandboxing) that provides OS-level filesystem and network isolation. Here's how it compares to Safety Net:
114
+ Claude Code offers [native sandboxing](https://code.claude.com/docs/en/sandboxing) that provides OS-level filesystem and network isolation. Here's how it compares to CC Safety Net:
112
115
 
113
116
  ### Different Layers of Protection
114
117
 
115
- | | Sandboxing | Safety Net |
118
+ | | Sandboxing | CC Safety Net |
116
119
  |---|---|---|
117
120
  | **Enforcement** | OS-level (Seatbelt/bubblewrap) | Application-level (PreToolUse hook) |
118
121
  | **Approach** | Containment — restricts filesystem + network access | Command analysis — blocks destructive operations |
@@ -128,7 +131,7 @@ Sandboxing restricts filesystem + network access, but it doesn't understand whet
128
131
  > [!NOTE]
129
132
  > Whether they're auto-run or require confirmation depends on your sandbox mode (auto-allow vs regular permissions), and network access still depends on your allowed-domain policy. Claude Code can also retry a command outside the sandbox via `dangerouslyDisableSandbox` (with user permission); this can be disabled with `allowUnsandboxedCommands: false`.
130
133
 
131
- | Command | Sandboxing | Safety Net |
134
+ | Command | Sandboxing | CC Safety Net |
132
135
  |---------|------------|------------|
133
136
  | `git reset --hard` | Allowed (within cwd) | **Blocked** |
134
137
  | `git checkout -- .` | Allowed (within cwd) | **Blocked** |
@@ -145,16 +148,16 @@ Sandboxing is the better choice when your primary concern is:
145
148
  - **Prompt injection attacks** — Reduces exfiltration risk by restricting outbound domains (depends on your allowed-domain policy)
146
149
  - **Malicious dependencies** — Limits filesystem writes and network access by default (subject to your sandbox configuration)
147
150
  - **Untrusted code execution** — OS-level containment is stronger than pattern matching
148
- - **Network control** — Safety Net has no network protection
151
+ - **Network control** — CC Safety Net has no network protection
149
152
 
150
153
  ### Recommended: Use Both
151
154
 
152
155
  They protect against different threats:
153
156
 
154
157
  - **Sandboxing** contains blast radius — even if something goes wrong, damage is limited to cwd and approved network domains
155
- - **Safety Net** prevents footguns — catches git-specific mistakes that are technically "safe" from the sandbox's perspective
158
+ - **CC Safety Net** prevents footguns — catches git-specific mistakes that are technically "safe" from the sandbox's perspective
156
159
 
157
- Running both together provides defense-in-depth. Sandboxing handles unknown threats; Safety Net handles known destructive patterns that sandboxing permits.
160
+ Running both together provides defense-in-depth. Sandboxing handles unknown threats; CC Safety Net handles known destructive patterns that sandboxing permits.
158
161
 
159
162
  ## Prerequisites
160
163
 
@@ -162,39 +165,40 @@ Running both together provides defense-in-depth. Sandboxing handles unknown thre
162
165
 
163
166
  ## Quick Start
164
167
 
165
- ### Claude Code Installation
168
+ ### Codex Installation
166
169
 
167
- ```bash
168
- /plugin marketplace add kenryu42/cc-marketplace
169
- /plugin install safety-net@cc-marketplace
170
- /reload-plugins
171
- ```
170
+ 1. Enable Codex plugin hooks in `~/.codex/config.toml`:
172
171
 
173
- ### Claude Code Auto-Update
172
+ ```toml
173
+ [features]
174
+ plugin_hooks = true
175
+ ```
174
176
 
175
- 1. Run `/plugin` → Select `Marketplaces` → Choose `cc-marketplace` → Enable auto-update
177
+ 2. Add the marketplace:
176
178
 
177
- ---
179
+ ```bash
180
+ codex plugin marketplace add kenryu42/cc-marketplace
181
+ ```
178
182
 
179
- ### OpenCode Installation
183
+ 3. Start Codex.
184
+ 4. In the TUI, run `/plugins`.
185
+ 5. Use arrow keys to select `[cc-marketplace]`.
186
+ 6. Press Enter to install the plugin.
187
+ 7. run `/hooks` and select the safety-net PreToolUse hook and press `t` to trust it.
180
188
 
181
- **Option A: Let an LLM do it**
189
+ ---
182
190
 
183
- Paste this into any LLM agent (Claude Code, OpenCode, Cursor, etc.):
191
+ ### Claude Code Installation
184
192
 
193
+ ```bash
194
+ /plugin marketplace add kenryu42/cc-marketplace
195
+ /plugin install safety-net@cc-marketplace
196
+ /reload-plugins
185
197
  ```
186
- Install the cc-safety-net plugin in `~/.config/opencode/opencode.json` (or `.jsonc`) according to the schema at: https://opencode.ai/config.json
187
- ```
188
-
189
- **Option B: Manual setup**
190
198
 
191
- 1. **Add the plugin to your config** `~/.config/opencode/opencode.json` (or `.jsonc`):
199
+ ### Claude Code Auto-Update
192
200
 
193
- ```json
194
- {
195
- "plugin": ["cc-safety-net"]
196
- }
197
- ```
201
+ 1. Run `/plugin` → Select `Marketplaces` → Choose `cc-marketplace` → Enable auto-update
198
202
 
199
203
  ---
200
204
 
@@ -212,36 +216,42 @@ gemini extensions install https://github.com/kenryu42/gemini-safety-net
212
216
  /plugin install kenryu42/copilot-safety-net
213
217
  ```
214
218
 
215
- > [!NOTE]
216
- > After installing the plugin, you need to restart your Copilot CLI for it to take effect.
219
+ ---
220
+
221
+ ### Kimi CLI Installation
222
+
223
+ Install CC Safety Net into your Kimi CLI config:
224
+
225
+ ```bash
226
+ npx -y cc-safety-net hook install --kimi-cli
227
+ ```
217
228
 
218
229
  ---
219
230
 
220
- ### Codex Installation
221
231
 
222
- 1. Enable Codex plugin hooks in `~/.codex/config.toml`:
232
+ ### OpenCode Installation
223
233
 
224
- ```toml
225
- [features]
226
- plugin_hooks = true
227
- ```
234
+ Install CC Safety Net with OpenCode's native plugin command:
228
235
 
229
- 2. Add the marketplace:
236
+ ```bash
237
+ opencode plugin -g cc-safety-net
238
+ ```
230
239
 
231
- ```bash
232
- codex plugin marketplace add kenryu42/cc-marketplace
233
- ```
240
+ ---
234
241
 
235
- 3. Start Codex.
236
- 4. In the TUI, run `/plugins`.
237
- 5. Use arrow keys to select `[cc-marketplace]`.
238
- 6. Press Enter to install the plugin.
242
+ ### Pi Installation
243
+
244
+ Install CC Safety Net with Pi's package installer:
245
+
246
+ ```bash
247
+ pi install npm:cc-safety-net
248
+ ```
239
249
 
240
250
  ---
241
251
 
242
252
  ## Status Line Integration
243
253
 
244
- Safety Net can display its status in Claude Code's status line, showing whether protection is active and which modes are enabled.
254
+ CC Safety Net can display its status in Claude Code's status line, showing whether protection is active and which modes are enabled.
245
255
 
246
256
  Add the following to your `~/.claude/settings.json`:
247
257
 
@@ -251,7 +261,7 @@ Add the following to your `~/.claude/settings.json`:
251
261
  {
252
262
  "statusLine": {
253
263
  "type": "command",
254
- "command": "bunx cc-safety-net --statusline"
264
+ "command": "bunx cc-safety-net statusline --claude-code"
255
265
  }
256
266
  }
257
267
  ```
@@ -262,7 +272,7 @@ Add the following to your `~/.claude/settings.json`:
262
272
  {
263
273
  "statusLine": {
264
274
  "type": "command",
265
- "command": "BUN_BE_BUN=1 claude x cc-safety-net --statusline"
275
+ "command": "BUN_BE_BUN=1 claude x cc-safety-net statusline --claude-code"
266
276
  }
267
277
  }
268
278
  ```
@@ -277,20 +287,20 @@ Add the following to your `~/.claude/settings.json`:
277
287
  {
278
288
  "statusLine": {
279
289
  "type": "command",
280
- "command": "npx -y cc-safety-net --statusline"
290
+ "command": "npx -y cc-safety-net statusline --claude-code"
281
291
  }
282
292
  }
283
293
  ```
284
294
 
285
295
  **Piping with existing status line:**
286
296
 
287
- If you already have a status line command, you can pipe Safety Net at the end:
297
+ If you already have a status line command, you can pipe CC Safety Net at the end:
288
298
 
289
299
  ```json
290
300
  {
291
301
  "statusLine": {
292
302
  "type": "command",
293
- "command": "your-existing-command | bunx cc-safety-net --statusline"
303
+ "command": "your-existing-command | bunx cc-safety-net statusline --claude-code"
294
304
  }
295
305
  }
296
306
  ```
@@ -303,16 +313,16 @@ The status line displays different emojis based on the current configuration:
303
313
 
304
314
  | Status | Display | Meaning |
305
315
  |--------|---------|---------|
306
- | Plugin disabled | `🛡️ Safety Net ❌` | Safety Net plugin is not enabled |
307
- | Default mode | `🛡️ Safety Net ✅` | Protection active with default settings |
308
- | Strict mode | `🛡️ Safety Net 🔒` | `SAFETY_NET_STRICT=1` — fail-closed on unparseable commands |
309
- | Paranoid mode | `🛡️ Safety Net 👁️` | `SAFETY_NET_PARANOID=1` — all paranoid checks enabled |
310
- | Paranoid RM only | `🛡️ Safety Net 🗑️` | `SAFETY_NET_PARANOID_RM=1` — blocks `rm -rf` even within cwd |
311
- | Paranoid interpreters only | `🛡️ Safety Net 🐚` | `SAFETY_NET_PARANOID_INTERPRETERS=1` — blocks interpreter one-liners |
312
- | Worktree mode | `🛡️ Safety Net 🌳` | `SAFETY_NET_WORKTREE=1` — relax local git discards inside linked worktrees |
313
- | Strict + Paranoid | `🛡️ Safety Net 🔒👁️` | Both strict and paranoid modes enabled |
316
+ | Plugin disabled | `🛡️ CC Safety Net ❌` | CC Safety Net plugin is not enabled |
317
+ | Default mode | `🛡️ CC Safety Net ✅` | Protection active with default settings |
318
+ | Strict mode | `🛡️ CC Safety Net 🔒` | `CC_SAFETY_NET_STRICT=1` — fail-closed on unparseable commands |
319
+ | Paranoid mode | `🛡️ CC Safety Net 👁️` | `CC_SAFETY_NET_PARANOID=1` — all paranoid checks enabled |
320
+ | Paranoid RM only | `🛡️ CC Safety Net 🗑️` | `CC_SAFETY_NET_PARANOID_RM=1` — blocks `rm -rf` even within cwd |
321
+ | Paranoid interpreters only | `🛡️ CC Safety Net 🐚` | `CC_SAFETY_NET_PARANOID_INTERPRETERS=1` — blocks interpreter one-liners |
322
+ | Worktree mode | `🛡️ CC Safety Net 🌳` | `CC_SAFETY_NET_WORKTREE=1` — relax local git discards inside linked worktrees |
323
+ | Strict + Paranoid | `🛡️ CC Safety Net 🔒👁️` | Both strict and paranoid modes enabled |
314
324
 
315
- Multiple mode emojis are combined when multiple environment variables are set.
325
+ Multiple mode emojis are combined when multiple environment variables are set. Mode flags use `CC_SAFETY_NET_*` names; legacy `SAFETY_NET_*` names are still accepted.
316
326
 
317
327
  ## Diagnostics
318
328
 
@@ -331,7 +341,7 @@ The doctor command checks:
331
341
  | Hook Integration | Verifies the plugin is properly configured for each supported platform |
332
342
  | Self-Test | Runs sample commands to confirm blocking works correctly |
333
343
  | Configuration | Validates custom rules in user and project configs |
334
- | Environment | Shows status of mode flags (SAFETY_NET_STRICT, SAFETY_NET_PARANOID, etc.) |
344
+ | Environment | Shows status of mode flags (`CC_SAFETY_NET_STRICT`, `CC_SAFETY_NET_PARANOID`, etc.; legacy `SAFETY_NET_*` also listed when set) |
335
345
  | Recent Activity | Summarizes blocked commands from the last 7 days |
336
346
  | System Info | Displays versions of all relevant tools |
337
347
  | Update Check | Checks if a newer version is available |
@@ -345,7 +355,7 @@ The doctor command checks:
345
355
 
346
356
  ## Explain (Debug Analysis)
347
357
 
348
- Trace how Safety Net analyzes a command step-by-step. Useful for debugging why a command is blocked or allowed, or when developing custom rules.
358
+ Trace how CC Safety Net analyzes a command step-by-step. Useful for debugging why a command is blocked or allowed, or when developing custom rules.
349
359
 
350
360
  ```bash
351
361
  npx cc-safety-net explain "git reset --hard"
@@ -377,6 +387,8 @@ npx cc-safety-net explain --cwd /tmp "git status"
377
387
  | git checkout \<ref\> \<path\> | May overwrite working tree when Git disambiguates ref vs pathspec |
378
388
  | git restore files | Discards uncommitted changes |
379
389
  | git restore --worktree | Explicitly discards working tree changes |
390
+ | git switch --discard-changes | Discards uncommitted changes when switching branches |
391
+ | git switch --force / -f | Discards uncommitted changes (force switch) |
380
392
  | git reset --hard | Destroys all uncommitted changes |
381
393
  | git reset --merge | Can lose uncommitted changes |
382
394
  | git clean -f | Removes untracked files permanently |
@@ -385,13 +397,16 @@ npx cc-safety-net explain --cwd /tmp "git status"
385
397
  | git stash drop | Permanently deletes stashed changes |
386
398
  | git stash clear | Deletes ALL stashed changes |
387
399
  | git worktree remove --force | Force-deletes worktree without checking for changes |
388
- | rm -rf (paths outside cwd) | Recursive file deletion outside the current directory |
400
+ | rm -rf (destructive targets) | Recursive file deletion of root, home, parent, absolute, or non-temp paths outside cwd |
389
401
  | rm -rf / or ~ or $HOME | Root/home deletion is extremely dangerous |
390
402
  | find ... -delete | Permanently removes files matching criteria |
391
403
  | xargs rm -rf | Dynamic input makes targets unpredictable |
392
404
  | xargs \<shell\> -c | Can execute arbitrary commands |
393
405
  | parallel rm -rf | Dynamic input makes targets unpredictable |
394
406
  | parallel \<shell\> -c | Can execute arbitrary commands |
407
+ | dd writing to block devices | Can overwrite disks or partitions |
408
+ | mkfs on block devices | Formats disks or partitions |
409
+ | shred | Permanently destroys file contents |
395
410
 
396
411
  ## Commands Allowed
397
412
 
@@ -408,7 +423,7 @@ npx cc-safety-net explain --cwd /tmp "git status"
408
423
  | rm -rf /var/tmp/... | System temp directory |
409
424
  | rm -rf $TMPDIR/... | User's temp directory |
410
425
  | rm -rf ./... (within cwd) | Limited to current working directory |
411
- | git restore / checkout -- / reset --hard / clean -f (in linked worktree) | Relaxed only when `SAFETY_NET_WORKTREE=1` and cwd is a linked worktree |
426
+ | git restore / checkout -- / reset --hard / clean -f (in linked worktree) | Relaxed only when `CC_SAFETY_NET_WORKTREE=1` and cwd is a linked worktree |
412
427
 
413
428
  ## What Happens When Blocked
414
429
 
@@ -416,7 +431,7 @@ When a destructive command is detected, the plugin blocks the tool execution and
416
431
 
417
432
  Example output:
418
433
  ```text
419
- BLOCKED by Safety Net
434
+ BLOCKED by CC Safety Net
420
435
 
421
436
  Reason: git checkout -- discards uncommitted changes permanently. Use 'git stash' first.
422
437
 
@@ -437,29 +452,109 @@ git checkout -- README.md
437
452
  git checkout -b test-branch
438
453
  ```
439
454
 
440
- ## Development
455
+ ## Breaking Change: Custom Rules Migration
441
456
 
442
- See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to this project.
457
+ > [!WARNING]
458
+ > The custom rules system has moved from legacy inline config files to a rulebook-based layout. Legacy inline config files (`.safety-net.json` and `~/.cc-safety-net/config.json`) are **no longer loaded at runtime**. If they contain rules, commands now **fail closed** (stay blocked) until you migrate.
459
+
460
+ ### Who Is Affected
461
+
462
+ - **Affected**: users who previously defined custom rules in `.safety-net.json` (project scope) or `~/.cc-safety-net/config.json` (user scope).
463
+ - **Not affected**: users with no custom rules. All built-in destructive-command protections are unchanged and continue to work out of the box.
464
+
465
+ ### What Breaks
466
+
467
+ | Legacy file state | New behavior |
468
+ |-------------------|--------------|
469
+ | Empty legacy file | Silently ignored — built-in rules only |
470
+ | Legacy file with rules | Fail closed until migrated with `rule migrate` |
471
+ | Invalid legacy file | Fail closed until fixed and migrated, or removed |
443
472
 
444
- ## Custom Rules (Experimental)
473
+ "Fail closed" means commands stay blocked until the legacy rules are migrated to the new layout.
474
+
475
+ ### How to Migrate
476
+
477
+ ```bash
478
+ # Convert legacy inline rules into the new rulebook layout
479
+ npx -y cc-safety-net rule migrate
480
+
481
+ # Optionally delete verified legacy files after migration
482
+ npx -y cc-safety-net rule migrate --cleanup
483
+
484
+ # Validate the migrated rules
485
+ npx -y cc-safety-net rule verify
486
+ npx -y cc-safety-net rule test
487
+ ```
488
+
489
+ ### Before / After
490
+
491
+ **Before** — a single inline config with rules embedded:
492
+
493
+ ```text
494
+ .safety-net.json # project rules (inline)
495
+ ~/.cc-safety-net/config.json # user rules (inline)
496
+ ```
497
+
498
+ **After** — `rule migrate` creates a rulebook-based layout automatically:
499
+
500
+ ```text
501
+ .cc-safety-net/rules/rule.json # project rulebook sources + overrides
502
+ .cc-safety-net/rules/project-rules/rulebook.json # migrated project rules
503
+ ~/.cc-safety-net/rules/rule.json # user rulebook sources + overrides
504
+ ~/.cc-safety-net/rules/user-rules/rulebook.json # migrated user rules
505
+ ```
506
+
507
+ See [Custom Rules](#custom-rules) for the full authoring guide and [Error Handling](#error-handling) for fail-closed details.
508
+
509
+ ## Custom Rules
445
510
 
446
511
  Beyond the built-in protections, you can define your own blocking rules to enforce team conventions or project-specific safety policies.
447
512
 
448
513
  > [!TIP]
449
- > Use the `set-custom-rules` skill to create custom rules interactively with natural language.
450
- >
514
+ > The best way to create custom rules is to use the `/cc-safety-net` skill to create custom rules interactively with natural language.
515
+
516
+ ### Examples
517
+
518
+ ```
519
+ /cc-safety-net read my package.json and suggest blocking rules
520
+ /cc-safety-net set up rules to block all terraform destroy commands
521
+ /cc-safety-net verify my rules and fix any errors
522
+ ```
523
+
524
+ > [!NOTE]
451
525
  > If your agent does not support skills, prompt it with:
452
- > ```text
453
- > run npx cc-safety-net --custom-rules-doc and help me set up custom rules
454
526
  > ```
527
+ > run npx -y cc-safety-net rule doc and help me set up custom rules
528
+ > ```
529
+
530
+ ### Create Rules Manually
455
531
 
456
- ### Quick Example
532
+ Create a starter project rule config and rulebook:
457
533
 
458
- Create `.safety-net.json` in your project root:
534
+ ```bash
535
+ npx -y cc-safety-net rule init
536
+ ```
537
+
538
+ This creates `.cc-safety-net/rules/rule.json`:
459
539
 
460
540
  ```json
461
541
  {
462
542
  "version": 1,
543
+ "rules": ["project-rules"],
544
+ "overrides": {}
545
+ }
546
+ ```
547
+
548
+ Rule definitions live in `.cc-safety-net/rules/project-rules/rulebook.json`:
549
+
550
+ ```json
551
+ {
552
+ "rulebook_version": 1,
553
+ "name": "project-rules",
554
+ "version": "1.0.0",
555
+ "description": "Project-specific CC Safety Net rules.",
556
+ "author": "project",
557
+ "allowed_commands": ["git"],
463
558
  "rules": [
464
559
  {
465
560
  "name": "block-git-add-all",
@@ -468,25 +563,48 @@ Create `.safety-net.json` in your project root:
468
563
  "block_args": ["-A", "--all", "."],
469
564
  "reason": "Use 'git add <specific-files>' instead of blanket add."
470
565
  }
566
+ ],
567
+ "tests": [
568
+ {
569
+ "command": "git add -A",
570
+ "expect": "blocked",
571
+ "rule": "block-git-add-all"
572
+ },
573
+ {
574
+ "command": "git add README.md",
575
+ "expect": "allowed"
576
+ }
471
577
  ]
472
578
  }
473
579
  ```
474
580
 
581
+ After editing rulebooks, run:
582
+
583
+ ```bash
584
+ npx -y cc-safety-net rule sync
585
+ npx -y cc-safety-net rule verify
586
+ npx -y cc-safety-net rule test
587
+ ```
588
+
475
589
  Now `git add -A`, `git add --all`, and `git add .` will be blocked with your custom message.
476
590
 
477
591
  ### Config File Location
478
592
 
479
593
  Config files are loaded from two scopes and merged:
480
594
 
481
- 1. **User scope**: `~/.cc-safety-net/config.json` (always loaded if exists)
482
- 2. **Project scope**: `.safety-net.json` in the current working directory (loaded if exists)
595
+ 1. **User scope**: `~/.cc-safety-net/rules/rule.json` (use `rule init --global`)
596
+ 2. **Project scope**: `.cc-safety-net/rules/rule.json` in the current working directory
597
+
598
+ Local rulebook sources are bare names like `project-rules`. GitHub rulebook sources use `owner/repo#ref/<rulebook-name>` and point to `.cc-safety-net/rules/<rulebook-name>/rulebook.json` in that repository.
599
+
600
+ Legacy inline config files (`.safety-net.json` and `~/.cc-safety-net/config.json`) are no longer loaded at runtime. Empty legacy files are ignored, but legacy files with rules and invalid legacy files fail closed until migrated or fixed. Convert existing legacy rules with `npx -y cc-safety-net rule migrate`; use `npx -y cc-safety-net rule migrate --cleanup` if you also want to delete verified legacy files after migration. See [Breaking Change: Custom Rules Migration](#breaking-change-custom-rules-migration) for the full upgrade guide.
483
601
 
484
602
  **Merging behavior**:
485
- - Rules from both scopes are combined
486
- - If the same rule name exists in both scopes, **project scope wins**
487
- - Rule name comparison is case-insensitive (`MyRule` and `myrule` are considered duplicates)
603
+ - Rulebooks from both scopes are combined
604
+ - Duplicate active rulebook names are invalid
605
+ - Project overrides win over user overrides for the same `<rulebook-name>/<rule-name>` key
488
606
 
489
- This allows you to define personal defaults in user scope while letting projects override specific rules.
607
+ This allows you to define personal defaults in user scope while letting projects disable or replace reasons for specific rules.
490
608
 
491
609
  If no config file is found in either location, only built-in rules apply.
492
610
 
@@ -495,18 +613,44 @@ If no config file is found in either location, only built-in rules apply.
495
613
  | Field | Type | Required | Description |
496
614
  |-------|------|----------|-------------|
497
615
  | `version` | integer | Yes | Schema version (must be `1`) |
498
- | `rules` | array | No | List of custom blocking rules (defaults to empty) |
616
+ | `rules` | array | No | List of rulebook source strings (defaults to empty) |
617
+ | `overrides` | object | No | Rule overrides keyed by `<rulebook-name>/<rule-name>` |
618
+
619
+ Override values are either `"off"` to disable a rule or `{ "reason": "..." }` to replace the rule reason.
620
+
621
+ ### Rulebook Schema
622
+
623
+ | Field | Type | Required | Description |
624
+ |-------|------|----------|-------------|
625
+ | `rulebook_version` | integer | Yes | Rulebook schema version (must be `1`) |
626
+ | `name` | string | Yes | Rulebook name; must match the local directory name or GitHub source name |
627
+ | `version` | string | Yes | Rulebook version |
628
+ | `description` | string | No | Human-readable description |
629
+ | `author` | string | No | Rulebook author |
630
+ | `allowed_commands` | array | Yes | Commands this rulebook is allowed to define rules for |
631
+ | `rules` | array | Yes | Custom blocking rules |
632
+ | `tests` | array | Yes | Rulebook fixtures |
499
633
 
500
634
  ### Rule Schema
501
635
 
502
636
  | Field | Type | Required | Description |
503
637
  |-------|------|----------|-------------|
504
- | `name` | string | Yes | Unique identifier (letters, numbers, hyphens, underscores; max 64 chars) |
505
- | `command` | string | Yes | Base command to match (e.g., `git`, `npm`, `docker`) |
638
+ | `name` | string | Yes | Unique within the rulebook (letters, numbers, hyphens, underscores; max 64 chars) |
639
+ | `command` | string | Yes | Base command to match; must be listed in `allowed_commands` |
506
640
  | `subcommand` | string | No | Subcommand to match (e.g., `add`, `install`). If omitted, matches any. |
507
641
  | `block_args` | array | Yes | Arguments that trigger the block (at least one required) |
508
642
  | `reason` | string | Yes | Message shown when blocked (max 256 chars) |
509
643
 
644
+ ### Fixture Schema
645
+
646
+ | Field | Type | Required | Description |
647
+ |-------|------|----------|-------------|
648
+ | `command` | string | Yes | Shell command fixture |
649
+ | `expect` | string | Yes | Either `blocked` or `allowed` |
650
+ | `rule` | string | For blocked fixtures | Rule expected to block the command |
651
+
652
+ Every rule must have at least one blocked fixture. Add allowed fixtures for close-but-safe commands.
653
+
510
654
  ### Matching Behavior
511
655
 
512
656
  - **Commands** are normalized to basename (`/usr/bin/git` → `git`)
@@ -521,13 +665,28 @@ If no config file is found in either location, only built-in rules apply.
521
665
 
522
666
  - **Short option expansion**: `-Cfoo` is treated as `-C -f -o -o`, not `-C foo`. Blocking `-f` may false-positive on attached option values.
523
667
 
524
- ### Examples
668
+ ### Rule Examples
525
669
 
526
670
  #### Block global npm installs
527
671
 
672
+ `.cc-safety-net/rules/rule.json`:
673
+
528
674
  ```json
529
675
  {
530
676
  "version": 1,
677
+ "rules": ["project-rules"],
678
+ "overrides": {}
679
+ }
680
+ ```
681
+
682
+ `.cc-safety-net/rules/project-rules/rulebook.json`:
683
+
684
+ ```json
685
+ {
686
+ "rulebook_version": 1,
687
+ "name": "project-rules",
688
+ "version": "1.0.0",
689
+ "allowed_commands": ["npm"],
531
690
  "rules": [
532
691
  {
533
692
  "name": "block-npm-global",
@@ -536,6 +695,17 @@ If no config file is found in either location, only built-in rules apply.
536
695
  "block_args": ["-g", "--global"],
537
696
  "reason": "Global npm installs can cause version conflicts. Use npx or local install."
538
697
  }
698
+ ],
699
+ "tests": [
700
+ {
701
+ "command": "npm install -g typescript",
702
+ "expect": "blocked",
703
+ "rule": "block-npm-global"
704
+ },
705
+ {
706
+ "command": "npm install typescript",
707
+ "expect": "allowed"
708
+ }
539
709
  ]
540
710
  }
541
711
  ```
@@ -544,7 +714,10 @@ If no config file is found in either location, only built-in rules apply.
544
714
 
545
715
  ```json
546
716
  {
547
- "version": 1,
717
+ "rulebook_version": 1,
718
+ "name": "project-rules",
719
+ "version": "1.0.0",
720
+ "allowed_commands": ["docker"],
548
721
  "rules": [
549
722
  {
550
723
  "name": "block-docker-system-prune",
@@ -553,6 +726,17 @@ If no config file is found in either location, only built-in rules apply.
553
726
  "block_args": ["prune"],
554
727
  "reason": "docker system prune removes all unused data. Use targeted cleanup instead."
555
728
  }
729
+ ],
730
+ "tests": [
731
+ {
732
+ "command": "docker system prune",
733
+ "expect": "blocked",
734
+ "rule": "block-docker-system-prune"
735
+ },
736
+ {
737
+ "command": "docker ps",
738
+ "expect": "allowed"
739
+ }
556
740
  ]
557
741
  }
558
742
  ```
@@ -561,7 +745,10 @@ If no config file is found in either location, only built-in rules apply.
561
745
 
562
746
  ```json
563
747
  {
564
- "version": 1,
748
+ "rulebook_version": 1,
749
+ "name": "project-rules",
750
+ "version": "1.0.0",
751
+ "allowed_commands": ["git", "npm"],
565
752
  "rules": [
566
753
  {
567
754
  "name": "block-git-add-all",
@@ -577,33 +764,47 @@ If no config file is found in either location, only built-in rules apply.
577
764
  "block_args": ["-g", "--global"],
578
765
  "reason": "Use npx or local install instead of global."
579
766
  }
767
+ ],
768
+ "tests": [
769
+ {
770
+ "command": "git add -A",
771
+ "expect": "blocked",
772
+ "rule": "block-git-add-all"
773
+ },
774
+ {
775
+ "command": "npm install -g typescript",
776
+ "expect": "blocked",
777
+ "rule": "block-npm-global"
778
+ }
580
779
  ]
581
780
  }
582
781
  ```
583
782
 
584
783
  ### Error Handling
585
784
 
586
- Custom rules use **silent fallback** error handling. If your config file is invalid, the safety net silently falls back to built-in rules only:
785
+ Rulebook-backed custom rules fail closed when configured rulebooks cannot be loaded safely:
587
786
 
588
787
  | Scenario | Behavior |
589
788
  |----------|----------|
590
789
  | Config file not found | Silent — use built-in rules only |
591
- | Empty config file | Silent use built-in rules only |
592
- | Invalid JSON syntax | Silent — use built-in rules only |
593
- | Missing required field | Silent use built-in rules only |
594
- | Invalid field format | Silent use built-in rules only |
595
- | Duplicate rule name | Silent use built-in rules only |
790
+ | Invalid rule config | Fail closed until fixed |
791
+ | Empty legacy config | Silent — use built-in rules only |
792
+ | Legacy config with rules and no migrated rule config | Fail closed until `rule migrate` creates the new rule config |
793
+ | Invalid legacy config | Fail closed until fixed or removed |
794
+ | Missing or stale lock/cache | Fail closed until `rule sync` repairs it |
795
+ | Invalid local rulebook | Fail closed until the rulebook is fixed and synced |
796
+ | Invalid GitHub rulebook | Fail closed until the source is fixed or removed |
596
797
 
597
798
 
598
799
  > [!IMPORTANT]
599
- > If you add or modify custom rules manually, always validate them with `npx -y cc-safety-net --verify-config` or the `verify-custom-rules` skill in your coding agent.
800
+ > If you add or modify custom rules manually, always validate them with `npx -y cc-safety-net rule verify` and `npx -y cc-safety-net rule test`.
600
801
 
601
802
  ### Block Output Format
602
803
 
603
804
  When a custom rule blocks a command, the output includes the rule name:
604
805
 
605
806
  ```text
606
- BLOCKED by Safety Net
807
+ BLOCKED by CC Safety Net
607
808
 
608
809
  Reason: [block-git-add-all] Use 'git add <specific-files>' instead of blanket add.
609
810
 
@@ -612,14 +813,17 @@ Command: git add -A
612
813
 
613
814
  ## Advanced Features
614
815
 
816
+ Mode and debug flags use **`CC_SAFETY_NET_*`** environment variables. Older **`SAFETY_NET_*`** names (without the `CC_` prefix) still work for strict, paranoid, and worktree toggles.
817
+
615
818
  ### Strict Mode
616
819
 
617
- By default, unparseable commands are allowed through. Enable strict mode to fail-closed
618
- when the hook input or shell command cannot be safely analyzed (e.g., invalid JSON,
619
- unterminated quotes, malformed `bash -c` wrappers):
820
+ Malformed or missing hook input JSON always fails closed. By default, ambiguous shell
821
+ command parsing is allowed through. Enable strict mode to fail closed when a shell
822
+ command cannot be safely analyzed (e.g., unterminated quotes or malformed `bash -c`
823
+ wrappers):
620
824
 
621
825
  ```bash
622
- export SAFETY_NET_STRICT=1
826
+ export CC_SAFETY_NET_STRICT=1
623
827
  ```
624
828
 
625
829
  ### Paranoid Mode
@@ -629,11 +833,11 @@ You can enable it globally or via focused toggles:
629
833
 
630
834
  ```bash
631
835
  # Enable all paranoid checks
632
- export SAFETY_NET_PARANOID=1
836
+ export CC_SAFETY_NET_PARANOID=1
633
837
 
634
838
  # Or enable specific paranoid checks
635
- export SAFETY_NET_PARANOID_RM=1
636
- export SAFETY_NET_PARANOID_INTERPRETERS=1
839
+ export CC_SAFETY_NET_PARANOID_RM=1
840
+ export CC_SAFETY_NET_PARANOID_INTERPRETERS=1
637
841
  ```
638
842
 
639
843
  Paranoid behavior:
@@ -650,7 +854,7 @@ local-discard rules when (and only when) the command is proven to run inside a
650
854
  linked worktree:
651
855
 
652
856
  ```bash
653
- export SAFETY_NET_WORKTREE=1
857
+ export CC_SAFETY_NET_WORKTREE=1
654
858
  ```
655
859
 
656
860
  When enabled, these commands are allowed inside a linked worktree:
@@ -691,6 +895,7 @@ The guard recursively analyzes commands wrapped in shells:
691
895
  ```bash
692
896
  bash -c 'git reset --hard' # Blocked
693
897
  sh -lc 'rm -rf /' # Blocked
898
+ bash -c 'git stash drop' # Blocked
694
899
  ```
695
900
 
696
901
  ### Interpreter One-Liner Detection
@@ -699,6 +904,10 @@ Detects destructive commands hidden in Python/Node/Ruby/Perl one-liners:
699
904
 
700
905
  ```bash
701
906
  python -c 'import os; os.system("rm -rf /")' # Blocked
907
+ python -c 'import os; os.system("git stash drop")' # Blocked
908
+ python -c 'import os; os.system("dd if=/dev/zero of=/dev/sda")' # Blocked
909
+ python -c 'import os; os.system("mkfs.ext4 /dev/sda1")' # Blocked
910
+ python -c 'import os; os.system("shred -u secret.txt")' # Blocked
702
911
  ```
703
912
 
704
913
  ### Secret Redaction
@@ -715,6 +924,10 @@ All blocked commands are logged to `~/.cc-safety-net/logs/<session_id>.jsonl` fo
715
924
 
716
925
  Sensitive data in log entries is automatically redacted.
717
926
 
927
+ ## Development
928
+
929
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to contribute to this project.
930
+
718
931
  ## License
719
932
 
720
933
  MIT