Skip to content

fix(hooks): inject stdout into context + register missing events (#298)#299

Open
mpfaffenberger wants to merge 2 commits intomainfrom
fix/issue-298-hook-stdout-injection
Open

fix(hooks): inject stdout into context + register missing events (#298)#299
mpfaffenberger wants to merge 2 commits intomainfrom
fix/issue-298-hook-stdout-injection

Conversation

@mpfaffenberger
Copy link
Copy Markdown
Owner

Closes #298.

Milton's report was spot on. Two fixes wrapped in one PR since they're tightly coupled.

What was broken

  1. Hook stdout was captured but never injected into the agent context. ExecutionResult.stdout was populated, the README promised "Exit code 0 → stdout shown in transcript", but every wired callback in plugins/claude_code_hooks/register_callbacks.py only checked result.blocked. Hooks could veto, but not inform.

  2. UserPromptSubmit, PreCompact, SessionEnd, and Notification were ghosts. Schema-registered, silently no-op'd at runtime.

What's fixed

Stdout → model context

Event Where stdout lands
SessionStart Appended to the system prompt via a new load_prompt callback in the plugin. Cached once per process.
UserPromptSubmit Prepended to the user prompt before it reaches the model (new user_prompt_submit phase fired from _runtime.run_with_mcp).
PreToolUse Prepended to the tool observation. Extended the pre_tool_call return contract with {"inject_context": "..."}; pydantic_patches.py applies it when the tool result is a string.

Newly-wired events

  • Added 4 new PhaseType entries + triggers to callbacks.py: user_prompt_submit, pre_compact, session_end, notification.
  • Plugin wires:
    • session_end (and shutdown for belt-and-braces) → SessionEnd hook.
    • message_history_processor_startPreCompact hook.
    • notificationNotification hook.
    • user_prompt_submitUserPromptSubmit hook with stdout injection + block support.

Tests

  • 19 new tests in tests/plugins/test_claude_code_hooks_issue_298.py cover all three injection paths and all four newly-wired events.
  • Full existing suite: 1896 passed, 6 skipped, 0 failures.

Back-compat notes

  • The pre_tool_call return contract is additive: existing {"blocked": True, ...} behavior untouched. {"inject_context": "..."} is the new optional key.
  • Hooks that print stdout but previously had no destination will now start influencing context. If this is surprising for any existing user, they can delete the stdout or silence their hook (this is the documented behavior).

Docs

  • hook_engine/README.md exit-codes section expanded with a "Where stdout goes" table.

🐶 Signed, Biscuit (code-puppy-de7a94). Milton, thanks for the crisp report.

ma-juang and others added 2 commits April 18, 2026 22:22
- Add VisibilityStore class for reusable visibility persistence
- Add Space key to toggle model visibility (hides selected model)
- Add Tab key to show/hide all (session-level filter)
- Persist hidden models across sessions via JSON config
- Add tests for visibility functionality
- Tests preserve user's visibility config during test runs
Two closely-related fixes for the Claude Code hooks plugin:

1. Hook stdout is now propagated into the model context (exit code 0):
   - SessionStart: stdout cached and appended to the system prompt via a
     new load_prompt callback in the plugin.
   - UserPromptSubmit: stdout prepended to the user prompt before the
     model sees it, via a new 'user_prompt_submit' callback phase fired
     from run_with_mcp.
   - PreToolUse: stdout prepended to the tool observation by extending
     the pre_tool_call return contract with {'inject_context': '...'}
     in pydantic_patches.

2. UserPromptSubmit, PreCompact, SessionEnd, and Notification events
   are now registered and fire:
   - Added four new PhaseType entries + trigger functions in callbacks.py.
   - Plugin now wires session_end/shutdown, pre_compact via
     message_history_processor_start, and a notification phase.

Covered by 19 new tests in test_claude_code_hooks_issue_298.py. Full
existing test suite (1896 passed, 6 skipped) stays green.
@mpfaffenberger mpfaffenberger force-pushed the main branch 2 times, most recently from c1f396b to daa401a Compare April 23, 2026 22:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hook engine: stdout not injected into context + UserPromptSubmit / PreCompact not registered

2 participants