Skip to content

Commit 00e50fa

Browse files
committed
Add GOOSE_STATUS_HOOK for terminal status updates
Adds a hook that runs when goose's status changes between 'waiting' (ready for input) and 'thinking' (processing). This is useful for users running multiple goose sessions who want visual indicators of which sessions are ready for input. Example usage for tmux title: export GOOSE_STATUS_HOOK='printf "\033]2;goose: $1\033\\"' Features: - Cross-platform support (sh -c on Unix, cmd /C on Windows) - Runs asynchronously to not block the main thread - Errors are silently ignored Signed-off-by: Trae Robrock <trobrock@gmail.com>
1 parent 5971e2f commit 00e50fa

2 files changed

Lines changed: 64 additions & 0 deletions

File tree

crates/goose-cli/src/session/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,7 @@ impl CliSession {
444444
loop {
445445
self.display_context_usage().await?;
446446

447+
output::run_status_hook("waiting");
447448
let input = input::get_input(&mut editor)?;
448449
if matches!(input, InputResult::Exit) {
449450
break;
@@ -578,6 +579,7 @@ impl CliSession {
578579

579580
let _provider = self.agent.provider().await?;
580581

582+
output::run_status_hook("thinking");
581583
output::show_thinking();
582584
let start_time = Instant::now();
583585
self.process_agent_response(true, CancellationToken::default())

crates/goose-cli/src/session/output.rs

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,48 @@ pub fn hide_thinking() {
160160
}
161161
}
162162

163+
/// Run the status hook command if GOOSE_STATUS_HOOK is set.
164+
///
165+
/// The hook command receives the status as its first argument.
166+
/// Valid statuses: "waiting", "thinking"
167+
///
168+
/// Example usage for tmux title:
169+
/// export GOOSE_STATUS_HOOK='printf "\033]2;goose: $1\033\\"'
170+
///
171+
/// The hook runs asynchronously and errors are silently ignored.
172+
///
173+
/// Note: We use `std::thread::spawn` rather than `tokio::spawn` here because:
174+
/// 1. Status changes are infrequent (only twice per user interaction cycle)
175+
/// 2. The spawned process is short-lived (typically a simple shell command)
176+
/// 3. Using std::thread keeps this function synchronous, simplifying call sites
177+
/// 4. This is a standard "fire and forget" pattern for shell command execution
178+
pub fn run_status_hook(status: &str) {
179+
if let Ok(hook) = Config::global().get_param::<String>("GOOSE_STATUS_HOOK") {
180+
let status = status.to_string();
181+
std::thread::spawn(move || {
182+
#[cfg(target_os = "windows")]
183+
let result = std::process::Command::new("cmd")
184+
.arg("/C")
185+
.arg(format!("{} {}", hook, status))
186+
.stdin(std::process::Stdio::null())
187+
.stdout(std::process::Stdio::null())
188+
.stderr(std::process::Stdio::null())
189+
.status();
190+
191+
#[cfg(not(target_os = "windows"))]
192+
let result = std::process::Command::new("sh")
193+
.arg("-c")
194+
.arg(format!("{} {}", hook, status))
195+
.stdin(std::process::Stdio::null())
196+
.stdout(std::process::Stdio::null())
197+
.stderr(std::process::Stdio::null())
198+
.status();
199+
200+
let _ = result;
201+
});
202+
}
203+
}
204+
163205
pub fn is_showing_thinking() -> bool {
164206
THINKING.with(|t| t.borrow().is_shown())
165207
}
@@ -1027,4 +1069,24 @@ mod tests {
10271069
"/v/l/p/w/m/components/file.txt"
10281070
);
10291071
}
1072+
1073+
#[test]
1074+
fn test_run_status_hook_no_env_var() {
1075+
// Ensure GOOSE_STATUS_HOOK is not set
1076+
env::remove_var("GOOSE_STATUS_HOOK");
1077+
// Should not panic when env var is not set
1078+
run_status_hook("waiting");
1079+
run_status_hook("thinking");
1080+
}
1081+
1082+
#[test]
1083+
fn test_run_status_hook_with_env_var() {
1084+
// Set a simple hook that just exits successfully
1085+
env::set_var("GOOSE_STATUS_HOOK", "true");
1086+
// Should not panic when env var is set
1087+
run_status_hook("waiting");
1088+
run_status_hook("thinking");
1089+
// Clean up
1090+
env::remove_var("GOOSE_STATUS_HOOK");
1091+
}
10301092
}

0 commit comments

Comments
 (0)