feat: lifecycle hooks system - #8842
Closed
michaelneale wants to merge 1 commit into
Closed
Conversation
Adds a hooks module that lets users extend goose at key lifecycle points
via shell commands or HTTP endpoints, configured in config.yaml.
Hook events:
- before_tool_call: fires before tool execution, can block (exit 2)
- after_tool_call: fires after tool dispatch
- before_reply: fires when user message arrives
- after_reply: available via emit_hook() for callers
- on_session_start / on_session_end: available via emit_hook()
Configuration (in ~/.config/goose/config.yaml):
hooks:
before_tool_call:
- matcher: "bash|write_file"
hooks:
- command: "~/.config/goose/hooks/safety-check.sh"
timeout: 5
after_tool_call:
- hooks:
- url: "http://localhost:9000/hook"
Wire protocol:
- Shell: JSON on stdin, optional JSON on stdout
- HTTP: JSON POST body, optional JSON response
- Exit code 2 = block (Claude Code convention)
- Supports Claude Code (decision/reason), Hermes (action/message),
and direct (block/reason) response formats
Design principles:
- Fail-open: broken hooks log warnings, never crash the agent
- Matcher filtering: regex against tool name for tool events
- Short-circuit: first block wins for before_tool_call
- Zero overhead: has_hooks() fast-path skips when no hooks configured
Signed-off-by: Michael Neale <michael.neale@gmail.com>
Bojun-Vvibe
added a commit
to Bojun-Vvibe/oss-contributions
that referenced
this pull request
Apr 26, 2026
…merge-after-nits
Bojun-Vvibe
added a commit
to Bojun-Vvibe/oss-contributions
that referenced
this pull request
Apr 26, 2026
- aaif-goose/goose#8842: lifecycle hooks system (needs-discussion: trust model + timeout + error taxonomy) - cline/cline#10384: cap retry-after delay to prevent silent multi-hour hangs - INDEX.md: drip-72 entry, count bumped to drip-72
|
@michaelneale this is very important feat, waiting |
Collaborator
|
Closing this (per @michaelneale's OK in slack) because we have these going now |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a hooks module that lets users extend goose at key lifecycle points via shell commands or HTTP endpoints, configured in config.yaml.
Hook Events
before_tool_call— fires before tool execution, can block (exit code 2)after_tool_call— fires after tool dispatchbefore_reply— fires when user message arrivesafter_reply/on_session_start/on_session_end— available viaemit_hook()for CLI/server callersHandler Types
Configuration
In
~/.config/goose/config.yaml:Wire Protocol
Scripts receive JSON on stdin:
{ "event": "before_tool_call", "session_id": "abc123", "tool_name": "bash", "tool_input": {"command": "rm -rf /"}, "working_dir": "/home/user/project" }Decisions via stdout JSON — supports three formats:
{"decision": "block", "reason": "..."}{"action": "deny", "message": "..."}{"block": true, "reason": "..."}Or simply exit code 2 to block (no JSON needed).
Design
Based on research of hooks in Pi, Hermes, and Claude Code:
before_tool_callhas_hooks()fast-path skips when no hooks configuredcc @DOsinga for interest