Freeze boundary hook had four verified bugs: the grep-first JSON extractor truncated at escaped quotes and failed OPEN on unparseable payloads; the deny JSON was printf-interpolated so a quote- or newline-bearing path silently no-oped the block; the freeze path read stripped INTERNAL spaces (a boundary like ~/My Project could never match); and the path resolver skipped the final component, letting an in-boundary symlink write through to an out-of-boundary target. Fixes, structurally: one shared sourced helper (careful/bin/hook-extract.sh) now owns JSON extraction and JSON-encoded decision envelopes for BOTH hooks -- the two-copy drift is how freeze kept a broken extractor after careful's was fixed. Freeze is now deny-tier fail-closed (unparseable payload denies, parsed-but-no-file_path still allows), trims only leading/trailing whitespace, and resolves symlinks through the final path component. Careful gains a HIGH tier (hard deny, simple commands only): recursive delete of /, ~, or $HOME, and force-push to the repo's default branch. Compound commands always fall through to the MEDIUM ask; --force-with-lease is never HIGH. Documented as a best-effort advisory hard-stop, not a policy boundary. Plus additive-only project patterns (~/.gstack/careful-patterns.txt + per-project file): config can only ADD warn rules, never suppress a baseline family. test/hook-scripts.test.ts: 89 tests incl. malformed-payload deny, parseable deny JSON for hostile paths, space-bearing boundaries, symlink escape, HIGH tier splits, additive invariant, invalid-regex resilience. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
3.8 KiB
name, version, description, triggers, allowed-tools, hooks
| name | version | description | triggers | allowed-tools | hooks | |||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| careful | 0.1.0 | Safety guardrails for destructive commands. (gstack) |
|
|
|
When to invoke this skill
Warns before rm -rf, DROP TABLE, force-push, git reset --hard, kubectl delete, and similar destructive operations. User can override each warning. Use when touching prod, debugging live systems, or working in a shared environment. Use when asked to "be careful", "safety mode", "prod mode", or "careful mode".
/careful — Destructive Command Guardrails
Safety mode is now active. Every bash command will be checked for destructive patterns before running. If a destructive command is detected, you'll be warned and can choose to proceed or cancel.
mkdir -p ~/.gstack/analytics
echo '{"skill":"careful","ts":"'$(date -u +%Y-%m-%dT%H:%M:%SZ)'","repo":"'$(basename "$(git rev-parse --show-toplevel 2>/dev/null)" 2>/dev/null || echo "unknown")'"}' >> ~/.gstack/analytics/skill-usage.jsonl 2>/dev/null || true
What's protected
| Pattern | Example | Risk |
|---|---|---|
rm -rf / rm -r / rm --recursive |
rm -rf /var/data |
Recursive delete |
DROP TABLE / DROP DATABASE |
DROP TABLE users; |
Data loss |
TRUNCATE |
TRUNCATE orders; |
Data loss |
git push --force / -f |
git push -f origin main |
History rewrite |
git reset --hard |
git reset --hard HEAD~3 |
Uncommitted work loss |
git checkout . / git restore . |
git checkout . |
Uncommitted work loss |
kubectl delete |
kubectl delete pod |
Production impact |
docker rm -f / docker system prune |
docker system prune -a |
Container/image loss |
Safe exceptions
These patterns are allowed without warning:
rm -rf node_modules/.next/dist/__pycache__/.cache/build/.turbo/coverage
How it works
The hook reads the command from the tool input JSON, checks it against the
patterns above, and returns a hookSpecificOutput payload with
permissionDecision: "ask" and a warning reason if a match is found (the
decision must be nested under hookSpecificOutput — Claude Code ignores a
top-level permissionDecision). You can always override a MEDIUM warning and
proceed.
HIGH tier (hard deny)
A tiny set of catastrophic commands is denied outright while /careful is active, not just warned:
rm -r/-Rtargeting exactly/,~, or$HOMEgit push --force/-fto the repo's default branch
HIGH only fires on SIMPLE commands (no ;, &&, ||, |, newline) — string
matching cannot resolve what a compound command does, so compound shapes fall
through to the ordinary MEDIUM ask. --force-with-lease is deliberately not
matched (it's the safe force variant). This is a best-effort advisory
hard-stop, not a policy boundary: /careful is opt-in and session-scoped, so
the escape hatch is ending the /careful session.
Project patterns (additive only)
Add your own warn rules — one POSIX ERE per line, # comments allowed — in:
~/.gstack/careful-patterns.txt(all projects)~/.gstack/projects/<slug>/careful-patterns.txt(this project)
Matching lines warn with [careful] Project rule matched: <pattern>. Config
can only ADD rules: the files are consulted after the built-in families, so no
file content can suppress or weaken a baseline warning. Invalid regex lines
are skipped.
To deactivate, end the conversation or start a new one. Hooks are session-scoped.