feat: add /goal command for agent self-evaluation before finishing - #9069
Conversation
Add a /goal slash command that lets users set a goal the agent must verify before exiting its reply loop. When the agent would normally finish (text response, no tool calls), it instead injects a nudge message asking itself to verify the goal is met. If not met, it continues working. Capped at 3 goal-check nudges to prevent loops. Usage: /goal ensure all tests pass and code compiles /goal (show current goal) /goal off (clear the goal) Changes: - Agent struct: new goal field (Mutex<Option<String>>) - execute_commands.rs: /goal command handler (set/query/clear) - agent.rs reply_internal: goal-check match arm before normal exit - Tests: 3 new tests covering goal nudging, no-goal baseline, and the /goal command lifecycle Signed-off-by: Michael Neale <michael.neale@gmail.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8654af0850
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Like /goal but re-nudges the agent on every tool-free response with no pending-flag guard, so it keeps working until max_turns or /grind off. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Michael Neale <michael.neale@gmail.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 80ee41522e
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| let message = Message::user().with_text(&nudge) | ||
| .with_visibility(false, true); | ||
| messages_to_add.push(message); |
There was a problem hiding this comment.
Stop persisting goal nudges as future context
When a goal is checked, this hidden user message is added to messages_to_add, and the loop later persists every entry with session_manager.add_message; because the nudge is agent_visible, every later provider call in this session (including after set_goal(None), /goal off, or session reload) will still receive the old “Before finishing...” instruction. Users who completed or cleared a one-shot goal can have subsequent unrelated turns continue to be influenced by the stale goal; keep the nudge only in the in-memory context needed for the immediate follow-up, or mark/remove it before persisting once the check is over.
Useful? React with 👍 / 👎.
jamadeo
left a comment
There was a problem hiding this comment.
I like the simplicity of this. I agree with @DOsinga 's ideas mentioned in discord but also it's hard to imagine keeping it this simple while fitting it in with the other bits.
One other thought here is that this has a lot in common with the "final output" tool, and maybe we could do something to tidy that up.
|
@jamadeo yeah interesting. FWIW been using it for a few days and the simplicity does seem a good balance of just working. |
|
Hey @michaelneale — this PR has merge conflicts with main. Could you rebase/merge to resolve them? Happy to help get this landed once it's clean. |
* origin/main: (160 commits) Add Linux musl CLI builds (#9240) feat(acp): paginate session list (#9199) docs: reorganize (#9310) Structured per-provider config block, non-destructive provider switching (#8977) feat(cli): add `goose review` local code review command (#9114) feat(tui): diff viewer (#9260) fix(otel): emit trace_output as span attribute instead of event (#9255) docs: add guide for connecting goose Desktop to a remote goosed server (#9275) fix(config): check file fallback when keyring has no entry (#9279) fix(desktop): ScheduleModal error message styling (#9278) fix(ui): align sidebar hamburger in macOS fullscreen (#9257) Add documentation for new provider SaladCloud AI Gateway (#9253) fix: use current_exe() instead of PATH lookup when spawning goose (#9236) fix(extension_manager): set TCP_USER_TIMEOUT on streamable HTTP clients (#9207) fix: activate custom provider after adding via configure (#9213) Flush OTLP traces reliably on exit with configurable timeout (#9228) fix: reduce excessive MISSING_TRANSLATION warnings for fallback locales (#9294) feat(acp): pass session cwd param to acp providers (#9229) fix(desktop): eliminate cross-window deep link contamination (#9273) fix: improve Telegram gateway error reporting and connection reliability (#9223) ... Signed-off-by: Michael Neale <michael.neale@gmail.com> # Conflicts: # crates/goose/src/agents/agent.rs # crates/goose/tests/agent.rs
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a35469b261
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| None if did_recovery_compact_this_iteration => { | ||
| // continue from last user message after recovery compact | ||
| } | ||
| None if self.goal.lock().await.is_some() && !goal_check_pending => { |
There was a problem hiding this comment.
Check goals before accepting final output
When a response-schema recipe has installed the final-output tool, the agent exits as soon as final_output is present, so this new goal branch is only reachable when final_output is None. In the /goal + response-schema recipe scenario, the recipe can call recipe__final_output and the final answer is emitted without the promised goal verification. Route the final-output exit path through the same goal/grind check before breaking.
Useful? React with 👍 / 👎.
* main: feat: add /goal command for agent self-evaluation before finishing (#9069)
* main: (38 commits) [Prompt injection mitigation] Update pattern-based detection to reduce FPs (#9350) feat: add Harbor eval runner (#9138) chore(release): bump version to 1.35.0 (minor) (#9150) Include request URL in provider error messages (#9232) fix(databricks): ensure parallel tool image responses don't interleave tool results (#9241) Surface resolved Databricks model metadata (#9206) Add unified thinking effort control across all providers (#9242) Add Linux desktop Vulkan packages (#9323) chore: update canonical model registry (#9331) feat: slash commands (built-in, skill, recipe) in acp server (#9238) feat: add /goal command for agent self-evaluation before finishing (#9069) Feat/summon subagent instructions (#9325) feat: open-plugins generalization + skills (#9112) feat(hooks): PreToolUse denial (#9304) Add support for optional api_key configuration for declarative openai-engine providers (#9202) fix(cli): use plain '> ' prompt instead of goose emoji (#9305) flag for login shell PATH (#9313) Remove popular chat topics from new chat screen (#9307) fix: stop killing goosed when a window closes (#9302) Remove vendored Windows binaries (#9318) ...
…aif-goose#9069) Signed-off-by: Michael Neale <michael.neale@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
I found using goose just ... bare, I wanted to have it loop a little more when not around - giving it a goal to check on, a target.
Add a /goal command that lets users set a goal the agent must verify before exiting its reply loop. When the agent would normally finish (text response, no tool calls), it instead injects a nudge message asking itself to verify the goal is met. If not met, it continues working. Capped at 3 goal-check nudges to prevent loops.
Usage:
/goal ensure all tests pass and code compiles
/goal (show current goal)
/goal off (clear the goal)