| name | freeze |
| description | Hard-block Edit/Write outside a chosen directory. Use to scope-lock edits during a focused fix or refactor. Pair with /unfreeze to release. |
| allowed-tools | ["Bash","Read","AskUserQuestion"] |
| hooks | {"PreToolUse":[{"matcher":"Edit","hooks":[{"type":"command","command":"bash ${CLAUDE_PROJECT_DIR}/.claude/skills/freeze/check-freeze.sh"}]},{"matcher":"Write","hooks":[{"type":"command","command":"bash ${CLAUDE_PROJECT_DIR}/.claude/skills/freeze/check-freeze.sh"}]},{"matcher":"NotebookEdit","hooks":[{"type":"command","command":"bash ${CLAUDE_PROJECT_DIR}/.claude/skills/freeze/check-freeze.sh"}]}]} |
/freeze — Restrict Edits to a Directory
Hard-block any Edit, Write, or NotebookEdit to a file outside the chosen directory for the remainder of the session.
Adapted from garrytan/gstack/freeze via TAOM 2026-05-17. Uses the inline-hooks-in-skill-frontmatter pattern: the PreToolUse hooks above only fire while this skill is active — no global settings.json change.
When to use
- Fixing one feature and want zero risk of touching unrelated code
- Running
/deep-review and want scope-locked
- Debugging — pair with
/investigate, which auto-engages this hook
- Long sessions where context drift could cause edit creep
Setup
-
Use AskUserQuestion to ask the user which directory to lock to:
- Question: "Which directory should I restrict edits to? Files outside this path will be blocked."
- Free-text input — the user types a path. Common choices for LOTRAOM:
Main/Features/<FeatureName>/ — single feature scope
Main/Adapters/ — adapter layer only
Main/_Module/ModuleData/ — XML data only
LOTRAOM.Tests/ — tests only
-
Resolve to absolute path and persist to the state file:
FREEZE_INPUT="<user-provided-path>"
if [[ "$FREEZE_INPUT" != /* && "$FREEZE_INPUT" != [A-Za-z]:* ]]; then
FREEZE_DIR="$(cd "$FREEZE_INPUT" 2>/dev/null && pwd)"
else
FREEZE_DIR="$(cd "$FREEZE_INPUT" 2>/dev/null && pwd)"
fi
if [[ -z "$FREEZE_DIR" || ! -d "$FREEZE_DIR" ]]; then
echo "Could not resolve '$FREEZE_INPUT' to a directory."
exit 1
fi
STATE_DIR="${CLAUDE_PROJECT_DIR}/.claude/tmp/freeze"
mkdir -p "$STATE_DIR"
echo "$FREEZE_DIR" > "$STATE_DIR/freeze-dir.txt"
echo "Freeze boundary set: $FREEZE_DIR"
- Confirm to the user:
Edits are now locked to <resolved-path>/. Any Edit, Write, or NotebookEdit outside this directory will be hard-blocked. Run /unfreeze to release.
How it works
The PreToolUse hooks declared in this skill's frontmatter activate the moment the skill is invoked. On every Edit/Write/NotebookEdit tool call, check-freeze.sh runs:
- Reads the freeze-dir state file (
.claude/tmp/freeze/freeze-dir.txt)
- Extracts
file_path from the tool call's JSON input
- Resolves both paths to absolute, normalizes slashes (Windows + Git Bash compatible)
- If the file is outside the freeze boundary → returns
{"permissionDecision":"deny",...} to block
- Otherwise → returns
{} to allow
The hook is silent on success and verbose only when blocking, so freeze adds zero noise to normal work.
What's blocked vs. allowed
| Tool | Behavior |
|---|
| Edit | Blocked outside boundary |
| Write | Blocked outside boundary |
| NotebookEdit | Blocked outside boundary |
| Read, Glob, Grep | Always allowed (read-only) |
| Bash | Always allowed — sed, tee, > etc. can still bypass freeze. This is not a security boundary. |
MCP server tools (Serena's replace_content, etc.) | Not blocked — these are separate tools. Use Edit/Write for changes you want freeze-protected. |
Notes
- Trailing-slash normalization prevents
/Main from matching /Main_old
- Symlinks resolved before comparison (POSIX-portable, works in Git Bash)
- The state file is in
.claude/tmp/ (should be gitignored — verify in .gitignore)
- This is a productivity guard, not a security boundary. A determined Bash command can still touch anything the user has write access to.