Skip to content

Commit e723c64

Browse files
v1.35.0.1 fix: /freeze and /careful enforcement chain (#1459)
Three independent bugs all required for hooks to fire and enforce: Bug 1 — bin/ not symlinked (hook script unreachable) Bug 2 — hooks not registered in settings.json (never fires) Bug 3 — wrong hookSpecificOutput format (fires, deny ignored) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent fcc8c95 commit e723c64

2 files changed

Lines changed: 34 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,38 @@
11
# Changelog
22

3+
## [1.35.0.1] - 2026-05-15
4+
5+
**`/freeze` and `/careful` now actually block. Three independent bugs — no bin/ symlink, no hook registration, wrong response format — were all required for the hooks to fire and enforce.**
6+
7+
The `/freeze` skill blocks Edit and Write outside a declared directory. `/careful` warns before destructive Bash commands. Both worked during skill invocation (state file written, UI feedback shown) but provided zero actual enforcement. An Edit on a blocked file would succeed silently. Telemetry logged a `boundary_deny` event, which made it look like the hook fired — it did fire, the deny was just ignored.
8+
9+
### The three numbers that matter
10+
11+
Root cause: `check-freeze.sh` and `check-careful.sh` ran fine when called directly. The problem was in how they were wired, not in the pattern-matching logic.
12+
13+
| Bug | Symptom | Root cause |
14+
|-----|---------|-----------|
15+
| Bug 1 | Hook script not found | `link_claude_skill_dirs` symlinked `SKILL.md` but not `bin/` — `${CLAUDE_SKILL_DIR}/bin/check-freeze.sh` resolved to a non-existent path |
16+
| Bug 2 | Hook never fired | SKILL.md frontmatter `hooks:` is documentation — Claude Code only fires hooks registered in `~/.claude/settings.json`. Setup never wrote there |
17+
| Bug 3 | Hook fired, deny ignored | Scripts returned `{"permissionDecision":"deny","message":"..."}` — a flat object Claude Code doesn't recognise. Correct format is `{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"..."}}` |
18+
19+
With all three fixed, `/freeze` enforces the boundary on Edit, Write, and MultiEdit. `/careful` warns on destructive Bash commands when active. Both work in every new session after re-running `./setup`.
20+
21+
### What this means for users who ran `/freeze` or `/careful` before
22+
23+
Re-run `./setup` once. Setup now symlinks each skill's `bin/` directory and writes the PreToolUse hook entries to `~/.claude/settings.json`. After that, `/freeze` actually blocks edits outside the declared directory. `/careful` is a no-op unless you invoke it (gated by `~/.gstack/careful-active.txt`), so it won't interfere with sessions where you didn't ask for safety mode.
24+
25+
### Itemized changes
26+
27+
#### Fixed
28+
- **Bug 1** — `setup` and `gstack-relink` now symlink each skill's `bin/` directory alongside `SKILL.md` so hook scripts in the frontmatter are reachable at `${CLAUDE_SKILL_DIR}/bin/`
29+
- **Bug 2** — `setup` registers PreToolUse entries for freeze (Edit|Write|MultiEdit) and careful (Bash) in `~/.claude/settings.json` at install time via the extended `gstack-settings-hook`; `gstack-settings-hook` gains `add-pretooluse` and `remove-pretooluse` actions
30+
- **Bug 3** — `check-freeze.sh` now outputs `{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"..."}}` as required; `check-careful.sh` does the same for `permissionDecision:"ask"`
31+
- **Bonus** — `check-freeze.sh` resolves its state root via `gstack-paths` to honour `GSTACK_HOME` in addition to `CLAUDE_PLUGIN_DATA`; `check-careful.sh` is a no-op unless `~/.gstack/careful-active.txt` exists (created when `/careful` is invoked)
32+
33+
#### For contributors
34+
- `test/hook-scripts.test.ts`: all careful tests use `withCarefulActive()` and pass `CLAUDE_PLUGIN_DATA` pointing to a temp dir; freeze tests assert `hookSpecificOutput` shape; two new tests verify the envelope structure and confirm allow responses remain `{}`
35+
336
## [1.35.0.0] - 2026-05-13
437

538
## **Docs become a tracked surface, not an afterthought. `/document-generate` writes them from scratch, `/document-release` audits coverage in four Diataxis quadrants.**

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.35.0.0
1+
1.35.0.1

0 commit comments

Comments
 (0)