freeze · garrytan — скилл для Claude Code: что делает и как установить
Хук блокирует Edit, Write и NotebookEdit за пределами выбранной папки. Отказ, а не предупреждение.
npx skills add garrytan/gstack --skill freeze -a claude-codeЧто делает freeze
Скилл спрашивает, какую папку считать границей, и записывает путь через freeze-state.sh. Дальше на каждый вызов Edit, Write и NotebookEdit срабатывает хук check-freeze.sh: он достаёт file_path из входа инструмента или notebook_path у блокнота Jupyter и сравнивает с границей. Не совпало — правка блокируется решением permissionDecision: deny. Не предупреждение, именно отказ.
Логика fail-closed. Если хук не разобрал payload, изменение отклоняется: граница, которая пропускает непонятное, перестаёт быть границей. Symlink сверяется по конечному компоненту, поэтому ссылка внутри папки, ведущая наружу, проверяется по цели. Замыкающий слэш не даёт /src совпасть с /src-old, пробелы в пути поддерживаются. Состояние лежит в файле и живёт дольше разговора — закрытие сессии его не снимает.
Хук висит только на редактировании файлов, так что Read, Bash, Glob и Grep работают как обычно. Проверьте это до того, как положитесь на скилл: sed или Set-Content из Bash спокойно правят файлы за границей. Это защита от случайных правок, а не граница безопасности. Снять ограничение — /unfreeze, сдвинуть — снова /freeze.
Какие задачи решает
- не дать агенту править файлы вне
src/ - зафиксировать границу правок на долгую сессию
- поймать случайную запись в соседний пакет монорепозитория
- убедиться, что symlink не уводит правку за пределы папки
- снять ограничение, когда работа в папке закончена
Примеры запросов агенту
- `/freeze` — ограничь правки папкой `packages/api/`
- Залочь редактирование на `src/` до конца сессии
- `/unfreeze` — снимаем границу
Как установить freeze
1Через Skills CLI (Vercel)
npx skills add garrytan/gstack --skill freeze -a claude-code2Вручную: положить файлы
~/.claude/skills/freeze/SKILL.mdПапка скилла целиком; для одного проекта — .claude/skills/freeze/
1Через Skills CLI (Vercel)
npx skills add garrytan/gstack --skill freeze -a codex2Вручную: положить файлы
.agents/skills/freeze/SKILL.mdДля всех проектов — ~/.agents/skills/
1Через Skills CLI (Vercel)
npx skills add garrytan/gstack --skill freeze -a cursor2Вручную: положить файлы
.cursor/skills/freeze/SKILL.mdCursor читает и .agents/skills/, и .claude/skills/
1GitHub CLI
gh skill install garrytan/gstack freeze2Вручную: положить файлы
.github/skills/freeze/SKILL.md1Через Skills CLI (Vercel)
npx skills add garrytan/gstack --skill freeze -a gemini-cli2Командой платформы
gemini skills install https://github.com/garrytan/gstack --path freezeВручную: положить файлы
.devin/skills/freeze/SKILL.mdСтарый путь .windsurf/skills/ тоже читается
Через Skills CLI (Vercel)
npx skills add garrytan/gstack --skill freeze -a opencodeClaude.ai
Упакуйте папку в zip и загрузите в Settings → Capabilities → Skills
Из того же набора12
Весь набор →Другие версии freeze
Похожие
Вопросы о freeze
Как установить freeze в Claude Code?
Одной командой: npx skills add garrytan/gstack --skill freeze -a claude-code. После неё скилл лежит в ~/.claude/skills/freeze/SKILL.md.
Что делает freeze?
Запирает правки внутри одной папки: Edit, Write и NotebookEdit за её пределами получают отказ от хука. Граница держится до /unfreeze.
Правки через Bash тоже блокируются?
Нет. Хук стоит только на Edit, Write и NotebookEdit, а sed или Set-Content из Bash файлы за границей меняют. Скилл страхует от случайных правок, барьером безопасности он не является.
Исходный текст
SKILL.md · MIT
---
name: freeze
version: 0.1.0
description: Restrict file edits to a specific directory for the session. (gstack)
triggers:
- freeze edits to directory
- lock editing scope
- restrict file changes
allowed-tools:
- Bash
- Read
- AskUserQuestion
hooks:
PreToolUse:
- 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"
hooks:
- type: command
command: 'bash -c "exec bash \"$HOME/.claude/skills/gstack/freeze/bin/check-freeze.sh\""'
statusMessage: "Checking freeze boundary..."
---
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
<!-- Regenerate: bun run gen:skill-docs -->
# /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).
```bash
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
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`. Symlinks are resolved
through their FINAL component, so an in-boundary symlink pointing outside the
boundary is checked against its target.
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 `/src` from 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 `sed` or `Set-Content` can still modify files outside the boundary
- To deactivate, run `/unfreeze`; ending or killing a conversation does not remove persisted state
© garrytan · MIT · garrytan/gstack