freeze
GitHub限制文件编辑操作仅限指定目录,防止意外修改其他代码。通过拦截Edit/Write工具请求并检查路径边界实现安全沙箱机制。
触发场景
安装
npx skills add garrytan/gstack --skill freeze -g -y
SKILL.md
Frontmatter
{
"name": "freeze",
"hooks": {
"PreToolUse": [
{
"hooks": [
{
"type": "command",
"command": "bash -c \"exec bash \\\"$HOME\/.claude\/skills\/gstack\/freeze\/bin\/check-freeze.sh\\\"\"",
"statusMessage": "Checking freeze boundary..."
}
],
"matcher": "Edit"
},
{
"hooks": [
{
"type": "command",
"command": "bash -c \"exec bash \\\"$HOME\/.claude\/skills\/gstack\/freeze\/bin\/check-freeze.sh\\\"\"",
"statusMessage": "Checking freeze boundary..."
}
],
"matcher": "Write"
},
{
"hooks": [
{
"type": "command",
"command": "bash -c \"exec bash \\\"$HOME\/.claude\/skills\/gstack\/freeze\/bin\/check-freeze.sh\\\"\"",
"statusMessage": "Checking freeze boundary..."
}
],
"matcher": "NotebookEdit"
}
]
},
"version": "0.1.0",
"triggers": [
"freeze edits to directory",
"lock editing scope",
"restrict file changes"
],
"description": "Restrict file edits to a specific directory for the session. (gstack)",
"allowed-tools": [
"Bash",
"Read",
"AskUserQuestion"
]
}
/freeze — Restrict Edits to a Directory
Lock file edits to a specific directory. Any Edit, Write or NotebookEdit operation targeting a file outside the allowed path will be blocked (not just warned).
GSTACK_STATE_ROOT=$(~/.claude/skills/gstack/bin/gstack-paths --get GSTACK_STATE_ROOT); : "${GSTACK_STATE_ROOT:?gstack-paths failed; reinstall with ./setup or /gstack-upgrade}"
mkdir -p "$GSTACK_STATE_ROOT"/analytics
echo '{"skill":"freeze","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_STATE_ROOT"/analytics/skill-usage.jsonl 2>/dev/null || true
Setup
Ask the user which directory to restrict edits to. Use AskUserQuestion:
- Question: "Which directory should I restrict edits to? Files outside this path will be blocked from editing."
- Text input (not multiple choice) — the user types a path.
Once the user provides a directory path:
Set the user-selected boundary with the shared state writer. It resolves the physical absolute path and serializes replacement with investigation cleanup:
bash "$HOME/.claude/skills/gstack/freeze/bin/freeze-state.sh" set "<user-provided-path>"
Only report success if the helper succeeds. On FREEZE_BUSY or unexpected state, preserve it and ask the user to inspect recovery after any active writer finishes; never write or delete the state file directly.
Tell the user: "Edits are now restricted to <path>/. Any Edit, Write or
NotebookEdit outside this directory will be blocked. To change the boundary, run /freeze
again. To remove it, run /unfreeze."
How it works
The hook reads file_path from the Edit/Write tool input JSON, or
notebook_path from a NotebookEdit (Jupyter notebook) call (shared
real-JSON extractor with /careful — one copy, sourced by both hooks), then
checks whether the path starts with the freeze directory. If not, it returns a
hookSpecificOutput payload with permissionDecision: "deny" to block the
operation (nested under hookSpecificOutput — Claude Code ignores a top-level
permissionDecision).
Polarity is fail-closed: a tool payload the hook cannot parse is DENIED, not
allowed — a boundary that fails open is not a boundary. A payload that parses
but has neither path field (a non-file tool) is allowed. A deny names the
tool, the path field, the boundary and /unfreeze. The path is resolved before
the check: ~, .. and relative paths, and symlinks at every depth, even
through folders that do not exist yet. A path the hook cannot place (a symlink
loop, a line break, a Windows drive-relative path, over 4096 characters) is
denied.
The freeze boundary persists until explicitly removed via the state file. The hook script reads it on every Edit/Write/NotebookEdit invocation. Boundaries containing spaces are supported.
Notes
- The trailing
/on the freeze directory prevents/srcfrom matching/src-old - Freeze applies to Edit, Write and NotebookEdit only — Read, Bash, PowerShell, Glob, Grep are unaffected
- This prevents accidental edits, not a security boundary — Bash or PowerShell commands like
sedorSet-Contentcan still modify files outside the boundary - To deactivate, run
/unfreeze; ending or killing a conversation does not remove persisted state
版本历史
-
82db89a
当前 2026-11-03 06:43
修复路径解析漏洞,确保新文件夹路径无法逃逸;完善符号链接和相对路径的规范化检查;增加对超长路径和链接链的长度限制以优化性能和安全。
-
2d42e4e
2026-10-19 13:43
v1.91.47.0: 增加对 PowerShell 工具和 NotebookEdit 的支持,修复了 Windows 平台及笔记本编辑场景下的边界检查缺失问题。
- 01593aa 2026-09-28 05:42
-
28d59ad
2026-08-20 05:28
修复了边界检查的多个bug(如JSON提取截断、路径空格处理、符号链接逃逸),实现了fail-closed安全策略,并与其他hook共享提取器。
- a325940 2026-07-25 11:04


