cc-safe-setup 11.7.0 → 11.8.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.
- package/README.md +15 -1
- package/package.json +1 -1
- package/.claude/session-snapshot.md +0 -25
- package/cc-safe-setup-export.json +0 -321
- package/docs/README.ja.md +0 -64
- package/docs/ROADMAP.md +0 -83
- package/docs/builder.html +0 -283
- package/docs/by-example.html +0 -234
- package/docs/cheatsheet.html +0 -187
- package/docs/ecosystem.html +0 -223
- package/docs/faq.html +0 -244
- package/docs/hooks-cheatsheet.html +0 -319
- package/docs/hub.html +0 -155
- package/docs/index-legacy.html +0 -685
- package/docs/index.html +0 -271
- package/docs/matrix.html +0 -139
- package/docs/migration-guide.html +0 -198
- package/docs/settings-reference.html +0 -317
- package/docs/troubleshooting.html +0 -189
- package/examples/go/destructive_guard.go +0 -69
- package/examples/python/__pycache__/destructive_guard.cpython-312.pyc +0 -0
- package/examples/python/__pycache__/secret_guard.cpython-312.pyc +0 -0
- package/examples/rust/destructive_guard.rs +0 -72
- package/examples/typescript/destructive-guard.ts +0 -64
|
@@ -1,317 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>Claude Code settings.json Complete Reference</title>
|
|
7
|
-
<meta name="description" content="Every settings.json field explained with examples. Hooks, permissions, env vars — the definitive reference.">
|
|
8
|
-
<style>
|
|
9
|
-
*{box-sizing:border-box;margin:0;padding:0}
|
|
10
|
-
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:#0d1117;color:#c9d1d9;padding:1.5rem;line-height:1.6}
|
|
11
|
-
.c{max-width:820px;margin:0 auto}
|
|
12
|
-
h1{color:#f0f6fc;font-size:1.4rem;margin-bottom:.3rem}
|
|
13
|
-
h2{color:#f0f6fc;font-size:1.05rem;margin:1.3rem 0 .4rem;padding-bottom:.3rem;border-bottom:1px solid #21262d}
|
|
14
|
-
h3{color:#c9d1d9;font-size:.88rem;margin:.7rem 0 .2rem}
|
|
15
|
-
.sub{color:#8b949e;font-size:.83rem;margin-bottom:1rem}
|
|
16
|
-
a{color:#58a6ff;text-decoration:none}
|
|
17
|
-
code{background:#161b22;padding:.12rem .25rem;border-radius:3px;font-size:.82rem}
|
|
18
|
-
pre{background:#161b22;border:1px solid #30363d;border-radius:6px;padding:.6rem;font-size:.78rem;color:#e6edf3;overflow-x:auto;margin:.3rem 0;position:relative}
|
|
19
|
-
.copy{position:absolute;top:.3rem;right:.3rem;background:#21262d;border:1px solid #30363d;color:#8b949e;padding:.15rem .4rem;border-radius:3px;cursor:pointer;font-size:.65rem}
|
|
20
|
-
.copy:hover{color:#f0f6fc}
|
|
21
|
-
table{width:100%;border-collapse:collapse;margin:.4rem 0;font-size:.8rem}
|
|
22
|
-
th,td{padding:.35rem .5rem;border:1px solid #21262d;text-align:left}
|
|
23
|
-
th{background:#161b22;color:#f0f6fc}
|
|
24
|
-
.note{background:#161b22;border-left:3px solid #58a6ff;padding:.4rem .7rem;margin:.4rem 0;font-size:.8rem;color:#8b949e}
|
|
25
|
-
.warn{border-left-color:#d29922}
|
|
26
|
-
.field{background:#161b22;border:1px solid #30363d;border-radius:6px;padding:.6rem;margin:.4rem 0}
|
|
27
|
-
.field-name{font-weight:700;color:#f0f6fc;font-family:monospace;font-size:.85rem}
|
|
28
|
-
.field-type{color:#d29922;font-size:.7rem;margin-left:.4rem}
|
|
29
|
-
.field-desc{color:#8b949e;font-size:.8rem;margin:.2rem 0}
|
|
30
|
-
.footer{text-align:center;color:#484f58;font-size:.7rem;margin-top:2rem;padding-top:1rem;border-top:1px solid #21262d}
|
|
31
|
-
.toc{columns:2;font-size:.8rem;margin:.5rem 0}
|
|
32
|
-
.toc a{display:block;padding:.15rem 0}
|
|
33
|
-
</style>
|
|
34
|
-
</head>
|
|
35
|
-
<body>
|
|
36
|
-
<div class="c">
|
|
37
|
-
|
|
38
|
-
<h1>settings.json Reference</h1>
|
|
39
|
-
<p class="sub">Every field, every option, with practical examples. <a href="https://docs.anthropic.com/en/docs/claude-code/settings">Official docs</a></p>
|
|
40
|
-
|
|
41
|
-
<div class="toc">
|
|
42
|
-
<a href="#locations">File Locations</a>
|
|
43
|
-
<a href="#hooks">hooks</a>
|
|
44
|
-
<a href="#permissions">permissions</a>
|
|
45
|
-
<a href="#env">env</a>
|
|
46
|
-
<a href="#model">model</a>
|
|
47
|
-
<a href="#projects">projects</a>
|
|
48
|
-
<a href="#examples">Full Examples</a>
|
|
49
|
-
</div>
|
|
50
|
-
|
|
51
|
-
<h2 id="locations">File Locations</h2>
|
|
52
|
-
|
|
53
|
-
<table>
|
|
54
|
-
<tr><th>File</th><th>Scope</th><th>Priority</th></tr>
|
|
55
|
-
<tr><td><code>~/.claude/settings.json</code></td><td>Global (all projects)</td><td>Lowest</td></tr>
|
|
56
|
-
<tr><td><code>.claude/settings.json</code></td><td>Project (in repo)</td><td>Medium</td></tr>
|
|
57
|
-
<tr><td><code>.claude/settings.local.json</code></td><td>Project local (gitignored)</td><td>Highest</td></tr>
|
|
58
|
-
</table>
|
|
59
|
-
|
|
60
|
-
<div class="note">
|
|
61
|
-
Project settings merge with global. Higher priority files override lower ones for the same key. For hooks, they are <strong>combined</strong>, not replaced.
|
|
62
|
-
</div>
|
|
63
|
-
|
|
64
|
-
<h2 id="hooks">hooks</h2>
|
|
65
|
-
|
|
66
|
-
<div class="field">
|
|
67
|
-
<span class="field-name">hooks</span> <span class="field-type">object</span>
|
|
68
|
-
<div class="field-desc">Shell scripts that run at lifecycle points. The core of safety configuration.</div>
|
|
69
|
-
</div>
|
|
70
|
-
|
|
71
|
-
<h3>Structure</h3>
|
|
72
|
-
<pre><code>{
|
|
73
|
-
"hooks": {
|
|
74
|
-
"EVENT": [
|
|
75
|
-
{
|
|
76
|
-
"matcher": "REGEX",
|
|
77
|
-
"hooks": [
|
|
78
|
-
{
|
|
79
|
-
"type": "command",
|
|
80
|
-
"command": "bash path/to/hook.sh"
|
|
81
|
-
}
|
|
82
|
-
]
|
|
83
|
-
}
|
|
84
|
-
]
|
|
85
|
-
}
|
|
86
|
-
}</code><button class="copy" onclick="cp(this)">Copy</button></pre>
|
|
87
|
-
|
|
88
|
-
<h3>Events</h3>
|
|
89
|
-
<table>
|
|
90
|
-
<tr><th>Event</th><th>When</th><th>stdin JSON</th></tr>
|
|
91
|
-
<tr><td><code>PreToolUse</code></td><td>Before tool executes</td><td><code>tool_name</code>, <code>tool_input</code></td></tr>
|
|
92
|
-
<tr><td><code>PostToolUse</code></td><td>After tool completes</td><td><code>tool_name</code>, <code>tool_input</code>, <code>tool_result</code></td></tr>
|
|
93
|
-
<tr><td><code>Stop</code></td><td>Claude finishes responding</td><td><code>stop_reason</code></td></tr>
|
|
94
|
-
<tr><td><code>SubagentStop</code></td><td>Subagent finishes</td><td>Subagent context</td></tr>
|
|
95
|
-
<tr><td><code>UserPromptSubmit</code></td><td>User sends a message</td><td>Prompt content</td></tr>
|
|
96
|
-
</table>
|
|
97
|
-
|
|
98
|
-
<h3>Matcher</h3>
|
|
99
|
-
<table>
|
|
100
|
-
<tr><th>Value</th><th>Matches</th></tr>
|
|
101
|
-
<tr><td><code>""</code></td><td>All tools</td></tr>
|
|
102
|
-
<tr><td><code>"Bash"</code></td><td>Shell commands only</td></tr>
|
|
103
|
-
<tr><td><code>"Edit"</code></td><td>File edits only</td></tr>
|
|
104
|
-
<tr><td><code>"Write"</code></td><td>File writes only</td></tr>
|
|
105
|
-
<tr><td><code>"Read"</code></td><td>File reads only</td></tr>
|
|
106
|
-
<tr><td><code>"Edit|Write"</code></td><td>Any file modification</td></tr>
|
|
107
|
-
<tr><td><code>"Bash|Edit|Write"</code></td><td>Multiple tools (regex OR)</td></tr>
|
|
108
|
-
</table>
|
|
109
|
-
|
|
110
|
-
<h3>Exit Codes</h3>
|
|
111
|
-
<table>
|
|
112
|
-
<tr><th>Code</th><th>Effect</th></tr>
|
|
113
|
-
<tr><td><code>0</code></td><td>Allow (default)</td></tr>
|
|
114
|
-
<tr><td><code>2</code></td><td>Block the action</td></tr>
|
|
115
|
-
<tr><td><code>1</code></td><td>Hook error (ignored, action proceeds)</td></tr>
|
|
116
|
-
</table>
|
|
117
|
-
|
|
118
|
-
<h3>stdout Override</h3>
|
|
119
|
-
<pre><code>// Auto-approve
|
|
120
|
-
echo '{"decision":"approve","reason":"Safe command"}'
|
|
121
|
-
|
|
122
|
-
// Block with reason
|
|
123
|
-
echo '{"decision":"block","reason":"Too dangerous"}'</code></pre>
|
|
124
|
-
|
|
125
|
-
<h3>Practical Example</h3>
|
|
126
|
-
<pre><code>{
|
|
127
|
-
"hooks": {
|
|
128
|
-
"PreToolUse": [
|
|
129
|
-
{
|
|
130
|
-
"matcher": "Bash",
|
|
131
|
-
"hooks": [
|
|
132
|
-
{"type": "command", "command": "bash ~/.claude/hooks/destructive-guard.sh"},
|
|
133
|
-
{"type": "command", "command": "bash ~/.claude/hooks/branch-guard.sh"},
|
|
134
|
-
{"type": "command", "command": "bash ~/.claude/hooks/secret-guard.sh"}
|
|
135
|
-
]
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
"matcher": "Edit|Write",
|
|
139
|
-
"hooks": [
|
|
140
|
-
{"type": "command", "command": "bash ~/.claude/hooks/scope-guard.sh"}
|
|
141
|
-
]
|
|
142
|
-
}
|
|
143
|
-
],
|
|
144
|
-
"PostToolUse": [
|
|
145
|
-
{
|
|
146
|
-
"matcher": "Edit|Write",
|
|
147
|
-
"hooks": [
|
|
148
|
-
{"type": "command", "command": "bash ~/.claude/hooks/syntax-check.sh"}
|
|
149
|
-
]
|
|
150
|
-
},
|
|
151
|
-
{
|
|
152
|
-
"matcher": "",
|
|
153
|
-
"hooks": [
|
|
154
|
-
{"type": "command", "command": "bash ~/.claude/hooks/context-monitor.sh"}
|
|
155
|
-
]
|
|
156
|
-
}
|
|
157
|
-
],
|
|
158
|
-
"Stop": [
|
|
159
|
-
{
|
|
160
|
-
"matcher": "",
|
|
161
|
-
"hooks": [
|
|
162
|
-
{"type": "command", "command": "bash ~/.claude/hooks/api-error-alert.sh"}
|
|
163
|
-
]
|
|
164
|
-
}
|
|
165
|
-
]
|
|
166
|
-
}
|
|
167
|
-
}</code><button class="copy" onclick="cp(this)">Copy</button></pre>
|
|
168
|
-
|
|
169
|
-
<h2 id="permissions">permissions</h2>
|
|
170
|
-
|
|
171
|
-
<div class="field">
|
|
172
|
-
<span class="field-name">permissions</span> <span class="field-type">object</span>
|
|
173
|
-
<div class="field-desc">Allow/deny rules for tool usage without prompting.</div>
|
|
174
|
-
</div>
|
|
175
|
-
|
|
176
|
-
<pre><code>{
|
|
177
|
-
"permissions": {
|
|
178
|
-
"allow": [
|
|
179
|
-
"Bash(npm test)",
|
|
180
|
-
"Bash(git status)",
|
|
181
|
-
"Bash(git log *)",
|
|
182
|
-
"Read(*)",
|
|
183
|
-
"Bash(ls *)"
|
|
184
|
-
],
|
|
185
|
-
"deny": [
|
|
186
|
-
"Bash(rm -rf *)",
|
|
187
|
-
"Bash(sudo *)",
|
|
188
|
-
"Bash(git push * --force)"
|
|
189
|
-
]
|
|
190
|
-
}
|
|
191
|
-
}</code><button class="copy" onclick="cp(this)">Copy</button></pre>
|
|
192
|
-
|
|
193
|
-
<div class="note warn">
|
|
194
|
-
<strong>Gotcha:</strong> Permissions use glob patterns, not regex. <code>*</code> matches anything. Claude adds flags like <code>-C /path</code> that can break exact matches — use hooks for reliable blocking.
|
|
195
|
-
</div>
|
|
196
|
-
|
|
197
|
-
<h2 id="env">env</h2>
|
|
198
|
-
|
|
199
|
-
<div class="field">
|
|
200
|
-
<span class="field-name">env</span> <span class="field-type">object</span>
|
|
201
|
-
<div class="field-desc">Environment variables passed to Claude Code and hooks.</div>
|
|
202
|
-
</div>
|
|
203
|
-
|
|
204
|
-
<pre><code>{
|
|
205
|
-
"env": {
|
|
206
|
-
"CC_TOKEN_BUDGET": "20",
|
|
207
|
-
"CC_MAX_LINE_LENGTH": "120",
|
|
208
|
-
"CC_DISK_WARN_PCT": "90",
|
|
209
|
-
"CC_ALLOWLIST_FILE": "~/.claude/allowlist.txt"
|
|
210
|
-
}
|
|
211
|
-
}</code><button class="copy" onclick="cp(this)">Copy</button></pre>
|
|
212
|
-
|
|
213
|
-
<h2 id="model">model</h2>
|
|
214
|
-
|
|
215
|
-
<div class="field">
|
|
216
|
-
<span class="field-name">model</span> <span class="field-type">string</span>
|
|
217
|
-
<div class="field-desc">Default model for Claude Code sessions.</div>
|
|
218
|
-
</div>
|
|
219
|
-
|
|
220
|
-
<pre><code>{
|
|
221
|
-
"model": "claude-sonnet-4-6"
|
|
222
|
-
}</code></pre>
|
|
223
|
-
|
|
224
|
-
<table>
|
|
225
|
-
<tr><th>Model</th><th>Best for</th></tr>
|
|
226
|
-
<tr><td><code>claude-opus-4-6</code></td><td>Complex reasoning, architecture</td></tr>
|
|
227
|
-
<tr><td><code>claude-sonnet-4-6</code></td><td>Fast daily coding (default)</td></tr>
|
|
228
|
-
<tr><td><code>claude-haiku-4-5</code></td><td>Quick tasks, high volume</td></tr>
|
|
229
|
-
</table>
|
|
230
|
-
|
|
231
|
-
<h2 id="projects">Project-Level Settings</h2>
|
|
232
|
-
|
|
233
|
-
<pre><code>// .claude/settings.json (commit to repo)
|
|
234
|
-
{
|
|
235
|
-
"hooks": {
|
|
236
|
-
"PreToolUse": [{
|
|
237
|
-
"matcher": "Bash",
|
|
238
|
-
"hooks": [{
|
|
239
|
-
"type": "command",
|
|
240
|
-
"command": "bash .claude/hooks/guard.sh"
|
|
241
|
-
}]
|
|
242
|
-
}]
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// .claude/settings.local.json (gitignored, personal)
|
|
247
|
-
{
|
|
248
|
-
"permissions": {
|
|
249
|
-
"allow": ["Bash(npm test)"]
|
|
250
|
-
}
|
|
251
|
-
}</code><button class="copy" onclick="cp(this)">Copy</button></pre>
|
|
252
|
-
|
|
253
|
-
<div class="note">
|
|
254
|
-
Use relative paths in project settings (<code>.claude/hooks/guard.sh</code>) so they work for all team members. Use <code>npx cc-safe-setup --team</code> to set this up automatically.
|
|
255
|
-
</div>
|
|
256
|
-
|
|
257
|
-
<h2 id="examples">Full Working Examples</h2>
|
|
258
|
-
|
|
259
|
-
<h3>Minimal Safe Setup</h3>
|
|
260
|
-
<pre><code>{
|
|
261
|
-
"hooks": {
|
|
262
|
-
"PreToolUse": [{
|
|
263
|
-
"matcher": "Bash",
|
|
264
|
-
"hooks": [
|
|
265
|
-
{"type": "command", "command": "bash ~/.claude/hooks/destructive-guard.sh"},
|
|
266
|
-
{"type": "command", "command": "bash ~/.claude/hooks/branch-guard.sh"},
|
|
267
|
-
{"type": "command", "command": "bash ~/.claude/hooks/secret-guard.sh"}
|
|
268
|
-
]
|
|
269
|
-
}]
|
|
270
|
-
}
|
|
271
|
-
}</code><button class="copy" onclick="cp(this)">Copy</button></pre>
|
|
272
|
-
|
|
273
|
-
<h3>Node.js Project</h3>
|
|
274
|
-
<pre><code>{
|
|
275
|
-
"hooks": {
|
|
276
|
-
"PreToolUse": [
|
|
277
|
-
{"matcher": "Bash", "hooks": [
|
|
278
|
-
{"type": "command", "command": "bash ~/.claude/hooks/destructive-guard.sh"},
|
|
279
|
-
{"type": "command", "command": "bash ~/.claude/hooks/branch-guard.sh"},
|
|
280
|
-
{"type": "command", "command": "bash ~/.claude/hooks/secret-guard.sh"},
|
|
281
|
-
{"type": "command", "command": "bash ~/.claude/hooks/auto-approve-build.sh"}
|
|
282
|
-
]},
|
|
283
|
-
{"matcher": "Edit|Write", "hooks": [
|
|
284
|
-
{"type": "command", "command": "bash ~/.claude/hooks/syntax-check.sh"}
|
|
285
|
-
]}
|
|
286
|
-
]
|
|
287
|
-
},
|
|
288
|
-
"permissions": {
|
|
289
|
-
"allow": ["Bash(npm test)", "Bash(npm run lint)", "Read(*)"]
|
|
290
|
-
}
|
|
291
|
-
}</code><button class="copy" onclick="cp(this)">Copy</button></pre>
|
|
292
|
-
|
|
293
|
-
<h3>Maximum Safety (Autonomous)</h3>
|
|
294
|
-
<pre><code>// Generated by: npx cc-safe-setup --profile strict
|
|
295
|
-
// 33 hooks for autonomous/production use
|
|
296
|
-
// Run: npx cc-safe-setup --shield</code></pre>
|
|
297
|
-
|
|
298
|
-
<div class="footer">
|
|
299
|
-
<a href="hooks-cheatsheet.html">Cheat Sheet</a> ·
|
|
300
|
-
<a href="builder.html">Builder</a> ·
|
|
301
|
-
<a href="faq.html">FAQ</a> ·
|
|
302
|
-
<a href="by-example.html">Examples</a> ·
|
|
303
|
-
<a href="migration-guide.html">Migration</a> ·
|
|
304
|
-
<a href="https://github.com/yurukusa/cc-safe-setup">GitHub</a>
|
|
305
|
-
</div>
|
|
306
|
-
</div>
|
|
307
|
-
|
|
308
|
-
<script>
|
|
309
|
-
function cp(btn) {
|
|
310
|
-
const code = btn.parentElement.querySelector('code').textContent;
|
|
311
|
-
navigator.clipboard.writeText(code);
|
|
312
|
-
btn.textContent = 'Copied!';
|
|
313
|
-
setTimeout(() => btn.textContent = 'Copy', 1500);
|
|
314
|
-
}
|
|
315
|
-
</script>
|
|
316
|
-
</body>
|
|
317
|
-
</html>
|
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>Claude Code Troubleshooting — Fix Any Problem in 2 Minutes</title>
|
|
7
|
-
<meta name="description" content="Hook not firing? Claude ignoring rules? Permission prompt spam? Fix every common Claude Code problem.">
|
|
8
|
-
<style>
|
|
9
|
-
*{box-sizing:border-box;margin:0;padding:0}
|
|
10
|
-
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;background:#0d1117;color:#c9d1d9;padding:1.5rem;line-height:1.6}
|
|
11
|
-
.c{max-width:800px;margin:0 auto}
|
|
12
|
-
h1{color:#f0f6fc;font-size:1.4rem;margin-bottom:.3rem}
|
|
13
|
-
h2{color:#f0f6fc;font-size:1rem;margin:1.2rem 0 .4rem}
|
|
14
|
-
.sub{color:#8b949e;font-size:.83rem;margin-bottom:1rem}
|
|
15
|
-
a{color:#58a6ff;text-decoration:none}
|
|
16
|
-
code{background:#161b22;padding:.12rem .25rem;border-radius:3px;font-size:.82rem}
|
|
17
|
-
pre{background:#161b22;border:1px solid #30363d;border-radius:6px;padding:.5rem;font-size:.78rem;color:#e6edf3;overflow-x:auto;margin:.3rem 0}
|
|
18
|
-
.problem{background:#161b22;border:1px solid #30363d;border-radius:8px;margin:.6rem 0;overflow:hidden}
|
|
19
|
-
.problem-header{padding:.6rem .8rem;cursor:pointer;font-weight:600;color:#f0f6fc;font-size:.88rem;display:flex;align-items:center;gap:.5rem}
|
|
20
|
-
.problem-header:hover{background:#21262d}
|
|
21
|
-
.problem-icon{font-size:1rem}
|
|
22
|
-
.problem-body{padding:0 .8rem .6rem;font-size:.82rem;display:none}
|
|
23
|
-
.problem.open .problem-body{display:block}
|
|
24
|
-
.step{background:#0d1117;border-radius:4px;padding:.4rem .6rem;margin:.3rem 0;border-left:3px solid #30363d}
|
|
25
|
-
.step-yes{border-left-color:#238636}
|
|
26
|
-
.step-no{border-left-color:#da3633}
|
|
27
|
-
.step-fix{border-left-color:#58a6ff}
|
|
28
|
-
.footer{text-align:center;color:#484f58;font-size:.7rem;margin-top:2rem;padding-top:1rem;border-top:1px solid #21262d}
|
|
29
|
-
.quick{background:#161b22;border:1px solid #30363d;border-radius:6px;padding:.6rem;margin:.5rem 0;font-size:.82rem}
|
|
30
|
-
</style>
|
|
31
|
-
</head>
|
|
32
|
-
<body>
|
|
33
|
-
<div class="c">
|
|
34
|
-
|
|
35
|
-
<h1>Troubleshooting</h1>
|
|
36
|
-
<p class="sub">Click your problem. Follow the steps. Fixed in 2 minutes.</p>
|
|
37
|
-
|
|
38
|
-
<div class="quick">
|
|
39
|
-
<strong>Quick fix for most problems:</strong> <code>npx cc-safe-setup --quickfix</code>
|
|
40
|
-
</div>
|
|
41
|
-
|
|
42
|
-
<div class="problem" onclick="this.classList.toggle('open')">
|
|
43
|
-
<div class="problem-header"><span class="problem-icon">🔇</span> My hook doesn't fire</div>
|
|
44
|
-
<div class="problem-body">
|
|
45
|
-
<div class="step">1. Is the hook file executable? <code>ls -la ~/.claude/hooks/your-hook.sh</code></div>
|
|
46
|
-
<div class="step-fix">Fix: <code>chmod +x ~/.claude/hooks/your-hook.sh</code></div>
|
|
47
|
-
|
|
48
|
-
<div class="step">2. Does it have a shebang? First line must be <code>#!/bin/bash</code></div>
|
|
49
|
-
<div class="step-fix">Fix: Add <code>#!/bin/bash</code> as the very first line</div>
|
|
50
|
-
|
|
51
|
-
<div class="step">3. Is it registered in settings.json?</div>
|
|
52
|
-
<pre>cat ~/.claude/settings.json | python3 -m json.tool | grep your-hook</pre>
|
|
53
|
-
<div class="step-fix">Fix: <code>npx cc-safe-setup --shield</code> (auto-registers all hooks)</div>
|
|
54
|
-
|
|
55
|
-
<div class="step">4. Is the matcher correct? <code>"Bash"</code> won't fire for Edit/Write</div>
|
|
56
|
-
<div class="step-fix">Use <code>""</code> (empty) to match all tools, or <code>"Edit|Write"</code> for file ops</div>
|
|
57
|
-
|
|
58
|
-
<div class="step">5. Is jq installed? <code>which jq</code></div>
|
|
59
|
-
<div class="step-fix">Install: <code>brew install jq</code> (macOS) or <code>sudo apt install jq</code> (Linux)</div>
|
|
60
|
-
|
|
61
|
-
<div class="step">6. Test it manually:</div>
|
|
62
|
-
<pre>echo '{"tool_input":{"command":"rm -rf /"}}' | bash ~/.claude/hooks/your-hook.sh; echo "Exit: $?"</pre>
|
|
63
|
-
</div>
|
|
64
|
-
</div>
|
|
65
|
-
|
|
66
|
-
<div class="problem" onclick="this.classList.toggle('open')">
|
|
67
|
-
<div class="problem-header"><span class="problem-icon">🚫</span> My hook blocks everything</div>
|
|
68
|
-
<div class="problem-body">
|
|
69
|
-
<div class="step">Your regex pattern is too broad. Test with a safe command:</div>
|
|
70
|
-
<pre>echo '{"tool_input":{"command":"ls -la"}}' | bash ~/.claude/hooks/your-hook.sh; echo "Exit: $?"</pre>
|
|
71
|
-
<div class="step">If it exits 2 for <code>ls</code>, your grep pattern matches too much.</div>
|
|
72
|
-
<div class="step-fix">Check the <code>grep -qE</code> pattern in your hook. Add <code>\b</code> word boundaries.</div>
|
|
73
|
-
<div class="step-fix">Example: <code>grep -qE '\brm\s+.*-rf\s+/'</code> instead of <code>grep -q 'rm'</code></div>
|
|
74
|
-
</div>
|
|
75
|
-
</div>
|
|
76
|
-
|
|
77
|
-
<div class="problem" onclick="this.classList.toggle('open')">
|
|
78
|
-
<div class="problem-header"><span class="problem-icon">📋</span> Claude ignores CLAUDE.md rules</div>
|
|
79
|
-
<div class="problem-body">
|
|
80
|
-
<div class="step">This is normal — CLAUDE.md rules degrade as context fills up.</div>
|
|
81
|
-
<div class="step-fix"><strong>Solution: Convert critical rules to hooks.</strong></div>
|
|
82
|
-
<pre># Example: "Don't push to main" as a hook instead of a rule
|
|
83
|
-
npx cc-safe-setup # Installs branch-guard</pre>
|
|
84
|
-
<div class="step">For any rule that must be enforced 100%, create a hook:</div>
|
|
85
|
-
<pre>npx cc-safe-setup --create "your rule in plain English"</pre>
|
|
86
|
-
<div class="step-fix">CLAUDE.md is for guidelines. Hooks are for hard constraints. Use both.</div>
|
|
87
|
-
</div>
|
|
88
|
-
</div>
|
|
89
|
-
|
|
90
|
-
<div class="problem" onclick="this.classList.toggle('open')">
|
|
91
|
-
<div class="problem-header"><span class="problem-icon">🔔</span> Too many permission prompts</div>
|
|
92
|
-
<div class="problem-body">
|
|
93
|
-
<div class="step">Install auto-approve hooks for safe commands:</div>
|
|
94
|
-
<pre>npx cc-safe-setup --install-example auto-approve-build # npm test, cargo build
|
|
95
|
-
npx cc-safe-setup --install-example auto-approve-python # pytest, mypy
|
|
96
|
-
npx cc-safe-setup --install-example auto-approve-git-read # git status, git log
|
|
97
|
-
npx cc-safe-setup --install-example compound-command-approver # cd && git log</pre>
|
|
98
|
-
<div class="step">Or add permissions in settings.json:</div>
|
|
99
|
-
<pre>"permissions": {"allow": ["Bash(npm test)", "Bash(git status)", "Read(*)"]}</pre>
|
|
100
|
-
<div class="step-fix">The <code>--profile standard</code> includes auto-approve hooks for common commands.</div>
|
|
101
|
-
</div>
|
|
102
|
-
</div>
|
|
103
|
-
|
|
104
|
-
<div class="problem" onclick="this.classList.toggle('open')">
|
|
105
|
-
<div class="problem-header"><span class="problem-icon">💾</span> settings.json won't parse</div>
|
|
106
|
-
<div class="problem-body">
|
|
107
|
-
<div class="step">Validate:</div>
|
|
108
|
-
<pre>python3 -c "import json; json.load(open('$HOME/.claude/settings.json'))"</pre>
|
|
109
|
-
<div class="step-fix">Common causes: trailing commas, comments (JSON doesn't allow them), unescaped quotes</div>
|
|
110
|
-
<div class="step">Auto-fix:</div>
|
|
111
|
-
<pre>npx cc-safe-setup --quickfix</pre>
|
|
112
|
-
<div class="step-fix">If totally broken: <code>echo '{}' > ~/.claude/settings.json</code> then re-run setup</div>
|
|
113
|
-
</div>
|
|
114
|
-
</div>
|
|
115
|
-
|
|
116
|
-
<div class="problem" onclick="this.classList.toggle('open')">
|
|
117
|
-
<div class="problem-header"><span class="problem-icon">🔄</span> Claude keeps retrying the same failed command</div>
|
|
118
|
-
<div class="problem-body">
|
|
119
|
-
<div class="step">Install the error memory guard:</div>
|
|
120
|
-
<pre>npx cc-safe-setup --install-example error-memory-guard</pre>
|
|
121
|
-
<div class="step-fix">After 3 failures of the same command, it blocks and says "try a different approach".</div>
|
|
122
|
-
<div class="step">Also useful: loop detector</div>
|
|
123
|
-
<pre>npx cc-safe-setup --install-example loop-detector</pre>
|
|
124
|
-
</div>
|
|
125
|
-
</div>
|
|
126
|
-
|
|
127
|
-
<div class="problem" onclick="this.classList.toggle('open')">
|
|
128
|
-
<div class="problem-header"><span class="problem-icon">💸</span> Session costs too much</div>
|
|
129
|
-
<div class="problem-body">
|
|
130
|
-
<div class="step">Install token budget guard:</div>
|
|
131
|
-
<pre>npx cc-safe-setup --install-example token-budget-guard</pre>
|
|
132
|
-
<div class="step-fix">Warns at $10, blocks at $50 (configurable via <code>CC_TOKEN_BUDGET</code> and <code>CC_TOKEN_BLOCK</code>)</div>
|
|
133
|
-
<div class="step">Monitor with:</div>
|
|
134
|
-
<pre>npx cc-safe-setup --analyze</pre>
|
|
135
|
-
</div>
|
|
136
|
-
</div>
|
|
137
|
-
|
|
138
|
-
<div class="problem" onclick="this.classList.toggle('open')">
|
|
139
|
-
<div class="problem-header"><span class="problem-icon">🧠</span> Context fills up too fast</div>
|
|
140
|
-
<div class="problem-body">
|
|
141
|
-
<div class="step">Three hooks help:</div>
|
|
142
|
-
<pre>npx cc-safe-setup --install-example output-length-guard # Warn on large outputs
|
|
143
|
-
npx cc-safe-setup --install-example large-read-guard # Warn before cat on large files
|
|
144
|
-
npx cc-safe-setup --install-example compact-reminder # Suggest /compact after N calls</pre>
|
|
145
|
-
<div class="step-fix">The context-monitor hook (installed by default) warns at 40%, 25%, 20%, 15%.</div>
|
|
146
|
-
</div>
|
|
147
|
-
</div>
|
|
148
|
-
|
|
149
|
-
<div class="problem" onclick="this.classList.toggle('open')">
|
|
150
|
-
<div class="problem-header"><span class="problem-icon">👥</span> Team members have different hook setups</div>
|
|
151
|
-
<div class="problem-body">
|
|
152
|
-
<div class="step">Use project-level hooks:</div>
|
|
153
|
-
<pre>npx cc-safe-setup --team
|
|
154
|
-
git add .claude/
|
|
155
|
-
git commit -m "chore: add team safety hooks"</pre>
|
|
156
|
-
<div class="step-fix">Hooks are copied to <code>.claude/hooks/</code> with relative paths. Works on any machine.</div>
|
|
157
|
-
<div class="step">Generate CI to enforce:</div>
|
|
158
|
-
<pre>npx cc-safe-setup --generate-ci</pre>
|
|
159
|
-
</div>
|
|
160
|
-
</div>
|
|
161
|
-
|
|
162
|
-
<div class="problem" onclick="this.classList.toggle('open')">
|
|
163
|
-
<div class="problem-header"><span class="problem-icon">🔀</span> Hooks from different tools conflict</div>
|
|
164
|
-
<div class="problem-body">
|
|
165
|
-
<div class="step">Analyze what you have:</div>
|
|
166
|
-
<pre>npx cc-safe-setup --migrate-from manual # See all existing hooks
|
|
167
|
-
npx cc-safe-setup --health # Check hook health</pre>
|
|
168
|
-
<div class="step-fix">Hooks in the same group run sequentially. If one consumes stdin, the next gets nothing.</div>
|
|
169
|
-
<div class="step">Fix: Put each hook in a separate matcher group in settings.json.</div>
|
|
170
|
-
</div>
|
|
171
|
-
</div>
|
|
172
|
-
|
|
173
|
-
<div class="quick" style="margin-top:1rem">
|
|
174
|
-
<strong>Still stuck?</strong>
|
|
175
|
-
<code>npx cc-safe-setup --doctor</code> — full diagnosis<br>
|
|
176
|
-
<code>npx cc-safe-setup --quickfix</code> — auto-fix common issues<br>
|
|
177
|
-
<a href="faq.html">FAQ</a> — 15 questions answered
|
|
178
|
-
</div>
|
|
179
|
-
|
|
180
|
-
<div class="footer">
|
|
181
|
-
<a href="hooks-cheatsheet.html">Cheat Sheet</a> ·
|
|
182
|
-
<a href="builder.html">Builder</a> ·
|
|
183
|
-
<a href="faq.html">FAQ</a> ·
|
|
184
|
-
<a href="settings-reference.html">Settings Ref</a> ·
|
|
185
|
-
<a href="https://github.com/yurukusa/cc-safe-setup">GitHub</a>
|
|
186
|
-
</div>
|
|
187
|
-
</div>
|
|
188
|
-
</body>
|
|
189
|
-
</html>
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
// destructive_guard.go — Claude Code PreToolUse hook in Go
|
|
2
|
-
//
|
|
3
|
-
// Blocks rm -rf /, git reset --hard, git clean -fd, and similar
|
|
4
|
-
// destructive commands. Exit code 2 = block, 0 = allow.
|
|
5
|
-
//
|
|
6
|
-
// Build: go build -o destructive-guard destructive_guard.go
|
|
7
|
-
// Usage in settings.json:
|
|
8
|
-
// {"type": "command", "command": "/path/to/destructive-guard"}
|
|
9
|
-
package main
|
|
10
|
-
|
|
11
|
-
import (
|
|
12
|
-
"encoding/json"
|
|
13
|
-
"fmt"
|
|
14
|
-
"io"
|
|
15
|
-
"os"
|
|
16
|
-
"regexp"
|
|
17
|
-
"strings"
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
type HookInput struct {
|
|
21
|
-
ToolInput struct {
|
|
22
|
-
Command string `json:"command"`
|
|
23
|
-
} `json:"tool_input"`
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
var dangerousPatterns = []*regexp.Regexp{
|
|
27
|
-
regexp.MustCompile(`\brm\s+.*-rf\s+(/|~/?\s*$|\.\./)`),
|
|
28
|
-
regexp.MustCompile(`\bgit\s+reset\s+--hard`),
|
|
29
|
-
regexp.MustCompile(`\bgit\s+clean\s+-[a-zA-Z]*f`),
|
|
30
|
-
regexp.MustCompile(`\bgit\s+checkout\s+--force`),
|
|
31
|
-
regexp.MustCompile(`\bchmod\s+(-R\s+)?777\s+/`),
|
|
32
|
-
regexp.MustCompile(`\bfind\s+/\s+-delete`),
|
|
33
|
-
regexp.MustCompile(`Remove-Item.*-Recurse.*-Force`),
|
|
34
|
-
regexp.MustCompile(`--no-preserve-root`),
|
|
35
|
-
regexp.MustCompile(`\bsudo\s+mkfs\b`),
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
func main() {
|
|
39
|
-
data, err := io.ReadAll(os.Stdin)
|
|
40
|
-
if err != nil {
|
|
41
|
-
os.Exit(0) // Don't block on read error
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
var input HookInput
|
|
45
|
-
if err := json.Unmarshal(data, &input); err != nil {
|
|
46
|
-
os.Exit(0) // Don't block on parse error
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
cmd := input.ToolInput.Command
|
|
50
|
-
if cmd == "" {
|
|
51
|
-
os.Exit(0)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Skip if command is in an echo/printf context
|
|
55
|
-
lower := strings.ToLower(cmd)
|
|
56
|
-
if strings.HasPrefix(strings.TrimSpace(lower), "echo ") ||
|
|
57
|
-
strings.HasPrefix(strings.TrimSpace(lower), "printf ") {
|
|
58
|
-
os.Exit(0)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
for _, pattern := range dangerousPatterns {
|
|
62
|
-
if pattern.MatchString(cmd) {
|
|
63
|
-
fmt.Fprintf(os.Stderr, "BLOCKED: Dangerous command detected\nCommand: %s\n", cmd)
|
|
64
|
-
os.Exit(2)
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
os.Exit(0)
|
|
69
|
-
}
|
|
Binary file
|
|
Binary file
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
// destructive_guard.rs — Claude Code PreToolUse hook in Rust
|
|
2
|
-
//
|
|
3
|
-
// Blocks rm -rf /, git reset --hard, git clean -fd, and similar
|
|
4
|
-
// destructive commands. Exit code 2 = block, 0 = allow.
|
|
5
|
-
//
|
|
6
|
-
// Build: rustc destructive_guard.rs -o destructive-guard
|
|
7
|
-
// Usage: {"type": "command", "command": "/path/to/destructive-guard"}
|
|
8
|
-
|
|
9
|
-
use std::io::{self, Read};
|
|
10
|
-
use std::process;
|
|
11
|
-
|
|
12
|
-
fn main() {
|
|
13
|
-
let mut input = String::new();
|
|
14
|
-
if io::stdin().read_to_string(&mut input).is_err() {
|
|
15
|
-
process::exit(0);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// Simple JSON parsing without serde (zero dependencies)
|
|
19
|
-
let cmd = extract_command(&input);
|
|
20
|
-
if cmd.is_empty() {
|
|
21
|
-
process::exit(0);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Skip echo/printf context
|
|
25
|
-
let trimmed = cmd.trim_start().to_lowercase();
|
|
26
|
-
if trimmed.starts_with("echo ") || trimmed.starts_with("printf ") {
|
|
27
|
-
process::exit(0);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
let patterns: &[&str] = &[
|
|
31
|
-
"rm -rf /",
|
|
32
|
-
"rm -rf ~/",
|
|
33
|
-
"rm -rf ../",
|
|
34
|
-
"rm -rf .",
|
|
35
|
-
"git reset --hard",
|
|
36
|
-
"git clean -f",
|
|
37
|
-
"git checkout --force",
|
|
38
|
-
"chmod 777 /",
|
|
39
|
-
"find / -delete",
|
|
40
|
-
"--no-preserve-root",
|
|
41
|
-
"sudo mkfs",
|
|
42
|
-
];
|
|
43
|
-
|
|
44
|
-
for pattern in patterns {
|
|
45
|
-
if cmd.to_lowercase().contains(&pattern.to_lowercase()) {
|
|
46
|
-
eprintln!("BLOCKED: Dangerous command detected");
|
|
47
|
-
eprintln!("Command: {}", cmd);
|
|
48
|
-
process::exit(2);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
process::exit(0);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
fn extract_command(json: &str) -> String {
|
|
56
|
-
// Extract .tool_input.command from JSON without a parser
|
|
57
|
-
if let Some(pos) = json.find("\"command\"") {
|
|
58
|
-
let rest = &json[pos + 9..];
|
|
59
|
-
if let Some(start) = rest.find('"') {
|
|
60
|
-
let value_start = start + 1;
|
|
61
|
-
let mut end = value_start;
|
|
62
|
-
let bytes = rest.as_bytes();
|
|
63
|
-
while end < bytes.len() {
|
|
64
|
-
if bytes[end] == b'"' && (end == 0 || bytes[end - 1] != b'\\') {
|
|
65
|
-
return rest[value_start..end].replace("\\\"", "\"").replace("\\\\", "\\");
|
|
66
|
-
}
|
|
67
|
-
end += 1;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
String::new()
|
|
72
|
-
}
|