From f7b2becb7820726fc70235805d867aff799504ed Mon Sep 17 00:00:00 2001 From: lunchboxfortwo Date: Mon, 6 Jul 2026 21:27:31 -0400 Subject: [PATCH 1/2] feat(hooks): pass working_dir to the Stop hook context The Stop hook already emits last_assistant_message (#9968) but not the session working directory, so a Stop hook that shells out to a verifier must guess the repo from the process cwd. Thread session.working_dir through emit_stop_hook / emit_stop_hook_blocking into stop_hook_context and set it via the existing .with_working_dir builder, matching the other lifecycle events. Additive; no behavior change for hooks that ignore working_dir. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01CxaoNZnqVZjmEELjLbV4BX --- crates/goose/src/agents/agent.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/crates/goose/src/agents/agent.rs b/crates/goose/src/agents/agent.rs index 95220cf74e04..7d828963b006 100644 --- a/crates/goose/src/agents/agent.rs +++ b/crates/goose/src/agents/agent.rs @@ -447,19 +447,21 @@ impl Agent { fn stop_hook_context( session_id: &str, last_assistant_message: &str, + working_dir: &str, ) -> crate::hooks::HookContext { crate::hooks::HookContext::new(crate::hooks::HookEvent::Stop, session_id) .with_last_assistant_message(last_assistant_message.to_string()) + .with_working_dir(working_dir.to_string()) } - async fn emit_stop_hook(&self, session_id: &str, last_assistant_message: &str) { + async fn emit_stop_hook(&self, session_id: &str, last_assistant_message: &str, working_dir: &str) { if !self.hook_manager.has_hooks(crate::hooks::HookEvent::Stop) { return; } self.hook_manager .emit( crate::hooks::HookEvent::Stop, - Self::stop_hook_context(session_id, last_assistant_message), + Self::stop_hook_context(session_id, last_assistant_message, working_dir), ) .await; } @@ -468,11 +470,12 @@ impl Agent { &self, session_id: &str, last_assistant_message: &str, + working_dir: &str, ) -> crate::hooks::HookDecision { self.hook_manager .emit_blocking( crate::hooks::HookEvent::Stop, - Self::stop_hook_context(session_id, last_assistant_message), + Self::stop_hook_context(session_id, last_assistant_message, working_dir), ) .await } @@ -1956,7 +1959,7 @@ impl Agent { conversation.push(message); match self - .emit_stop_hook_blocking(&session_config.id, &last_assistant_text) + .emit_stop_hook_blocking(&session_config.id, &last_assistant_text, &session.working_dir.to_string_lossy()) .await { crate::hooks::HookDecision::Allow => { @@ -2705,7 +2708,7 @@ impl Agent { if exit_chat { match self - .emit_stop_hook_blocking(&session_config.id, &last_assistant_text) + .emit_stop_hook_blocking(&session_config.id, &last_assistant_text, &session.working_dir.to_string_lossy()) .await { crate::hooks::HookDecision::Allow => { @@ -2738,7 +2741,7 @@ impl Agent { } if !stop_hook_handled_for_exit { - self.emit_stop_hook(&session_config.id, &last_assistant_text).await; + self.emit_stop_hook(&session_config.id, &last_assistant_text, &session.working_dir.to_string_lossy()).await; } }.instrument(reply_stream_span)); Ok(inner) From 02b89d879437c3384930e119b1d8f1db0a4225d0 Mon Sep 17 00:00:00 2001 From: lunchboxfortwo Date: Wed, 15 Jul 2026 14:26:55 -0400 Subject: [PATCH 2/2] style: cargo fmt emit_stop_hook signature Wrap the emit_stop_hook signature to satisfy cargo fmt (the line exceeded rustfmt's 100-char max_width). Unblocks the Check Rust Code Format CI job; matches the already-wrapped emit_stop_hook_blocking sibling. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01H1BcytE8qDDc511EHjQU92 --- crates/goose/src/agents/agent.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/crates/goose/src/agents/agent.rs b/crates/goose/src/agents/agent.rs index 7d828963b006..ab2ec613ee49 100644 --- a/crates/goose/src/agents/agent.rs +++ b/crates/goose/src/agents/agent.rs @@ -454,7 +454,12 @@ impl Agent { .with_working_dir(working_dir.to_string()) } - async fn emit_stop_hook(&self, session_id: &str, last_assistant_message: &str, working_dir: &str) { + async fn emit_stop_hook( + &self, + session_id: &str, + last_assistant_message: &str, + working_dir: &str, + ) { if !self.hook_manager.has_hooks(crate::hooks::HookEvent::Stop) { return; }