Skip to content

Commit 9ca3637

Browse files
committed
fix: use empty JSON instead of invalid \"allow\" decision value
Claude Code only recognizes \"block\" as a top-level decision value. \"allow\" is a permissionDecision value for PreToolUse hooks, not a valid top-level decision. The correct way to not block is to return empty JSON. Caught by #872.
1 parent 355a8a1 commit 9ca3637

2 files changed

Lines changed: 7 additions & 16 deletions

File tree

mempalace/hooks_cli.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,6 @@
3636
"Save everything to MemPalace, then allow compaction to proceed."
3737
)
3838

39-
PRECOMPACT_ALLOW_REASON = (
40-
"MemPalace pre-compaction save. Your conversation has been saved "
41-
"in the background. Compaction can proceed safely."
42-
)
43-
4439

4540
def _sanitize_session_id(session_id: str) -> str:
4641
"""Only allow alnum, dash, underscore to prevent path traversal."""
@@ -239,7 +234,7 @@ def hook_precompact(data: dict, harness: str):
239234
# Mine synchronously so data lands before compaction proceeds
240235
_mine_sync(transcript_path)
241236

242-
_output({"decision": "allow", "reason": PRECOMPACT_ALLOW_REASON})
237+
_output({})
243238

244239

245240
def run_hook(hook_name: str, harness: str):

tests/test_hooks_cli.py

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
from mempalace.hooks_cli import (
1111
SAVE_INTERVAL,
1212
STOP_BLOCK_REASON,
13-
PRECOMPACT_ALLOW_REASON,
1413
_count_human_messages,
1514
_get_mine_dir,
1615
_log,
@@ -212,8 +211,7 @@ def test_precompact_allows(tmp_path):
212211
{"session_id": "test"},
213212
state_dir=tmp_path,
214213
)
215-
assert result["decision"] == "allow"
216-
assert result["reason"] == PRECOMPACT_ALLOW_REASON
214+
assert result == {}
217215

218216

219217
# --- _log ---
@@ -382,7 +380,7 @@ def test_precompact_with_mempal_dir(tmp_path):
382380
{"session_id": "test"},
383381
state_dir=tmp_path,
384382
)
385-
assert result["decision"] == "allow"
383+
assert result == {}
386384
mock_run.assert_called_once()
387385

388386

@@ -397,7 +395,7 @@ def test_precompact_with_mempal_dir_oserror(tmp_path):
397395
{"session_id": "test"},
398396
state_dir=tmp_path,
399397
)
400-
assert result["decision"] == "allow"
398+
assert result == {}
401399

402400

403401
def test_precompact_with_timeout(tmp_path):
@@ -412,7 +410,7 @@ def test_precompact_with_timeout(tmp_path):
412410
result = _capture_hook_output(
413411
hook_precompact, {"session_id": "test"}, state_dir=tmp_path
414412
)
415-
assert result["decision"] == "allow"
413+
assert result == {}
416414

417415

418416
def test_precompact_mines_transcript_dir(tmp_path, monkeypatch):
@@ -426,7 +424,7 @@ def test_precompact_mines_transcript_dir(tmp_path, monkeypatch):
426424
{"session_id": "test", "transcript_path": str(transcript)},
427425
state_dir=tmp_path,
428426
)
429-
assert result["decision"] == "allow"
427+
assert result == {}
430428
mock_run.assert_called_once()
431429
# Verify mine dir is the transcript's parent
432430
call_args = mock_run.call_args[0][0]
@@ -471,9 +469,7 @@ def test_run_hook_dispatches_precompact(tmp_path):
471469
with patch("mempalace.hooks_cli.STATE_DIR", tmp_path):
472470
with patch("mempalace.hooks_cli._output") as mock_output:
473471
run_hook("precompact", "claude-code")
474-
mock_output.assert_called_once()
475-
call_args = mock_output.call_args[0][0]
476-
assert call_args["decision"] == "allow"
472+
mock_output.assert_called_once_with({})
477473

478474

479475
def test_run_hook_unknown_hook():

0 commit comments

Comments
 (0)