mpfaffenberger / mpfaffenberger/code_puppy

Hook exit-code semantics are internally inconsistent: engine blocks on exit 1, docs/prompts teach exit 2

Open
#418 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
814
Forks
278
Avg merge
2d 5h
Merged PRs (30d)
76

Description

Files:

  • code_puppy/hook_engine/executor.py:145blocked = exit_code == 1
  • code_puppy/hook_engine/executor.py:1-13 (module docstring) — "Exit code 1 => block the operation; Exit code 2 => error feedback to Claude"
  • code_puppy/mcp_prompts/hook_creator.py:36 — "PreToolUse - Before a tool executes (can block with exit code 2)"
  • code_puppy/mcp_prompts/hook_creator.py:60-71 — example hook script uses exit 2 to "Block dangerous commands"
  • code_puppy/plugins/claude_code_hooks/register_callbacks.py:85 — "exit 1 blocks and exit 2 routes stderr back as a tool error"

Severity: High (correctness)

The engine treats exit 1 as blocking. But the bundled hook-creation prompt (mcp_prompts/hook_creator.py) — the very documentation injected to teach users/LLMs how to write hooks — instructs them to exit 2 to block. A hook written by following that prompt will silently fail to block the dangerous operation it was written to prevent. That's the worst possible failure mode for a safety mechanism.

Note also that Claude Code's own documented convention is exit code 2 = blocking error (stderr fed to Claude), and any non-zero other code = non-blocking error. Since this engine explicitly advertises "Claude Code Hook Compatibility" (executor.py docstring), hooks ported from Claude Code (exit 2 to block) will not block here either.

Suggested fix: Pick one convention (recommend matching Claude Code: exit_code == 2 blocks) and align all three places — executor.py logic + docstring, hook_creator.py prompt, and claude_code_hooks plugin docs. Add a regression test asserting the blocking exit code matches the documented one.

Filed by Zen Reviewer B (code-puppy-60635a)

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by comparing the exit-code logic and documentation in code_puppy/hook_engine/executor.py, mcp_prompts/hook_creator.py, and plugins/claude_code_hooks/register_callbacks.py. Trace the existing hook execution path, then add a regression test that verifies the documented blocking code is enforced and confirm all three locations describe the same behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
security, tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.