Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
027cc35
invoker: wf-1789406883560-32/implement-hook-build-the-lever — Put the…
Sep 16, 2026
bbebd6e
invoker: wf-1789406883560-32/verify-hook-build-the-lever — Run the de…
Sep 16, 2026
5c0096b
invoker: wf-1789406883560-32/scrub-handoff-artifacts — Terminal read-…
Sep 16, 2026
eccbe83
Merge experiment/wf-1789406883560-32/scrub-handoff-artifacts/g1.t5.a-…
EdbertChan Sep 16, 2026
7757396
invoker: wf-1789406886887-33/implement-hook-cat-mode-default — Put th…
Sep 16, 2026
13ec88c
invoker: wf-1789406886887-33/verify-hook-cat-mode-default — Run the d…
Sep 16, 2026
163d9e8
invoker: wf-1789406886887-33/scrub-handoff-artifacts — Terminal read-…
Sep 16, 2026
87798db
Merge experiment/wf-1789406886887-33/scrub-handoff-artifacts/g1.t5.a-…
EdbertChan Sep 16, 2026
530b0eb
Merge remote-tracking branch 'origin/main' into plan/hook-architectur…
EdbertChan Sep 17, 2026
83cce91
invoker: wf-1789406886887-33/implement-hook-cat-mode-default — Put th…
Sep 17, 2026
d70c1f2
invoker: wf-1789406886887-33/implement-hook-cat-mode-default — Put th…
Sep 17, 2026
1dd88c4
invoker: wf-1789406886887-33/verify-hook-cat-mode-default — Run the d…
Sep 17, 2026
2d6cb51
invoker: wf-1789406886887-33/scrub-handoff-artifacts — Terminal read-…
Sep 17, 2026
49ef143
Merge experiment/wf-1789406886887-33/scrub-handoff-artifacts/g1.t7.a-…
EdbertChan Sep 17, 2026
6f10aaf
Merge plan/hook-architecture-14-put-the-cat-mode-default-hook-onto-th…
EdbertChan Sep 17, 2026
2309f44
Merge of #766
mergify[bot] Sep 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions engine/hooks/cat-mode-default/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,22 @@ It stays silent when the flag is off or when the prompt already mentions
cat-mode anywhere (a parent that told the subagent to read it gets no
second copy). Same flag resolution as the prompt hook.

The shared registry keeps this hook in `warn` mode. Set
`CATSTACK_HOOK_MODE_CAT_MODE_DEFAULT=off|warn|stop` for a machine-local
override; `stop` turns the `PreToolUse` (Agent) companion into a real block
(exit 2) instead of rewriting the subagent's prompt. Detection or metrics
failures allow the harness action.

## Files

- `detect.py`: flag resolution, typed `/cat-mode` detection, context text.
- `claude_prompt_submit.py`: the Claude entrypoint; fail-open, never denies.
- `claude.prompt.hook.json`: settings fragment `install_claude_hook.py` merges.
- `claude_pretooluse_agent.py` + `claude.agent.hook.json`: the `PreToolUse`
(`Agent`) companion that carries the default into subagent prompts.
- `detect.py`: flag resolution, typed `/cat-mode` detection, context text,
and `detect(event)`, the SDK entrypoint returning `Finding` objects.
- `claude_prompt_submit.py` / `claude_pretooluse_agent.py`: thin calls into
`engine/hooks/_sdk/runtime.py`. The agent finding carries
`output={"updatedInput": ...}`, which the shared renderer emits as
`updatedInput` rather than its generic `additionalContext`.
- `claude.prompt.hook.json` / `claude.agent.hook.json`: settings fragments
`install_claude_hook.py` merges.
- `tests/fixtures/*.json`: one scenario each (fires / silent) with the
environment, optional `.env` content, and payload.
- `tests/fixtures/agent_*.json`: the same for the Agent-tool companion.
Expand Down
14 changes: 14 additions & 0 deletions engine/hooks/cat-mode-default/tests/test_agent_hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import json
import os
import sys
import tempfile
import unittest
from contextlib import redirect_stderr, redirect_stdout
from unittest.mock import patch
Expand Down Expand Up @@ -150,6 +151,19 @@ def test_unrelated_prompt_does_not_count(self) -> None:


class FailOpenCase(unittest.TestCase):
def setUp(self) -> None:
self.tmp = tempfile.TemporaryDirectory()
self.metrics_env = patch.dict(
os.environ,
{"CATSTACK_HOOK_METRICS_DIR": self.tmp.name},
clear=False,
)
self.metrics_env.start()

def tearDown(self) -> None:
self.metrics_env.stop()
self.tmp.cleanup()

def test_malformed_stdin_prints_nothing(self) -> None:
out = io.StringIO()
with patch.object(sys, "stdin", io.StringIO("not json")):
Expand Down
13 changes: 13 additions & 0 deletions engine/hooks/cat-mode-default/tests/test_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,19 @@ def test_flags_missing_install_instead_of_dead_path(self) -> None:


class FailOpenCase(unittest.TestCase):
def setUp(self) -> None:
self.tmp = tempfile.TemporaryDirectory()
self.metrics_env = patch.dict(
os.environ,
{"CATSTACK_HOOK_METRICS_DIR": self.tmp.name},
clear=False,
)
self.metrics_env.start()

def tearDown(self) -> None:
self.metrics_env.stop()
self.tmp.cleanup()

def test_malformed_stdin_prints_nothing(self) -> None:
out = io.StringIO()
with patch.object(sys, "stdin", io.StringIO("not json")):
Expand Down
Loading