Skip to content

Sonny: /goal WHAT asks the agent to set its own goal; /goal shows, /goal clear clears - #397

Merged
lydakis merged 41 commits into
mainfrom
claude/project-thread-kxnbh9
Oct 30, 2026
Merged

lydakis merged 41 commits into
mainfrom
claude/project-thread-kxnbh9

Conversation

@lydakis

@lydakis lydakis commented Oct 30, 2026 •

Copy link
Copy Markdown
Owner

What

A window's /goal, in the shape Codex's /goal has:

  • /goal WHAT goes to the agent as the person typed it, a message like any other. The goal tool's description now ends with "A person's message that starts with /goal asks you to set one on yourself for what it says." So the agent sets the goal and picks its check with the tool, and the lookout follows it as it does any goal. sonny acp already passes such words through as they are.
  • /goal shows the goals of the agent and its tasks: goals: lead: done when the tests pass; /goal clear clears this agent's, or no goal; /goal WHAT asks the agent to work until WHAT is done.
  • /goal clear clears the agent's own goal, through the tool's own clear call.

The goal tool's set still goes through the approval gate like the agent's other calls; the person's /goal message is what the judge sees as their ask.

An earlier version of this PR had the person set the check themselves and run it at once. That version is gone, so this PR no longer touches the lookout.

Tests

  • goal_words_go_to_the_agent_as_typed_and_goal_alone_shows_or_clears (sonny unit test): /goal WHAT is submitted verbatim; /goal and /goal clear submit nothing; they show the goals and clear them.
  • cargo test -p sonny passes (470), and clippy is clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY

claude added 30 commits October 29, 2026 03:41
The goal tool sets an agent, or a task it made, a goal: what done looks
like and a shell command that exits 0 once it is. The lookout runs the
check each time the agent's turn completes; while it fails, the agent
gets a turn with its exit code and the end of its output, and its lead
hears nothing. The goal ends once the check passes, the budget is spent,
two turns it started call no tool, or the agent gives up with blocked,
and the lead hears that last turn with how it ended. No judge, nothing in
the daemon.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY
- A check's output is read as it prints, keeping only its end.
- A turn's goal is read fresh as the turn ends, so one a lead set or
  cleared meanwhile counts.
- One check at a time per agent; a turn that ends while one runs is
  plain news.
- A task is the caller's by its creator's id, not its name.
- A turn waiting for its check keeps the replay cursor before it, so a
  restarted lookout runs the check again.
- The check runs without the provider keys in ~/.agent/env.
- The macOS skip is back on the trigger test, not on note_for.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY
Main does not build since #344 renamed Places::plist to Places::job
while #318's restamp still called the old name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY
- A goal left by an agent deleted while the lookout was away is dropped
  when another agent with that name ends a turn.
- A goal's next turn is not news while it runs, as its end is.
- A goal cleared or set again while its check ran is plain news, even
  when that check passed.
- Listing goals shows a lead its tasks' goals, whoever set them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY
# Conflicts:
#	sonny/src/lookout/mod.rs
…e its check ran ends so

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY
…lay runs again

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY
…turn is not counted twice

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY
The reason an agent gives up for, and a check it set itself, are its own
text; the lead reads them in the turn or with the goal tool.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY
… turn waits on one

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY
…ves a later turn's news

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY
…d a lookout that gives way mid-check

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY
…-kxnbh9

# Conflicts:
#	sonny/src/lookout/mod.rs
#	sonny/src/lookout/updates.rs
…ched or not

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY
… to tell

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY
…t runs

`agent companion add/rm/ls` keeps a command in the store that every daemon
on it starts once it listens, restarts with backoff and stops at shutdown.
Sonny's lookout and approver now run as companions, so they share the
daemon's life cycle whether or not a window is open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY
…, a removed one waited for, and Sonny's take store and socket from the daemon

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY
…nion's whole group is no client, and a log that is no file fails at once

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY
…s idle

`/goal CHECK` keeps the agent the window shows working until CHECK exits 0
in its folder; `/goal` shows its goal and `/goal clear` clears it. With no
turn running, the goal file carries the agent's last turn as `check_after`
and the lookout runs the check on its next tick, as if that turn had just
completed, so a failing check starts the agent's goal turn at once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY
@lydakis lydakis self-assigned this Oct 30, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-30T01:27:58.029629Z 39459b5 New commits
🔒 Security Review ✅ Completed 2026-10-30T01:28:43.340609Z 39459b5 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2704b1cdd7

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread sonny/src/main.rs Outdated
Comment on lines +8243 to +8245
.ok()
.and_then(|turns| turns["turns"][0]["turn"].as_i64()),
false => None,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Start idle goals even when the agent has no previous turn

On a newly created agent, /goal CHECK cannot start any work: the turns response is empty, so last becomes None, which is also the value used for an agent whose turn is running. The goal is consequently written without check_after, and Goals::check_now skips it indefinitely until someone submits a separate message. Sonny's create path creates bots without submitting a turn, so this affects setting a goal as the first action in a new window. Represent an idle agent with no history separately from a busy agent and arrange for its initial check to run.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 30a928f. An idle agent with no turns now gets check_after: 0, so None only ever means a turn is running. A new runtime test sets a goal on a fresh agent and checks that it's met at turn 0.


Generated by Claude Code

Comment thread sonny/src/lookout/goals.rs Outdated
let Some(turn) = goal.check_after else {
continue;
};
checked_now(&self.store, &goal);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve pending idle checks until their outcome is durable

If the lookout restarts or reconnects while an immediate check is running, this clears the only durable indication that the check is pending before it finishes. Goals::reconnected aborts outstanding pursuits, and the immediate pursuit has no event cursor (self.pursue(..., None, ...)) to force replay of its historical turn. After reconnection, check_now therefore skips the goal, leaving the idle agent stuck without retrying the check or starting work. Retain a recoverable pending marker until the check completes or its continuation is durably submitted.

AGENTS.md reference: AGENTS.md:L32-L32

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 30a928f. check_now no longer clears check_after when the check starts. Goals::settled clears it once that turn's check has settled, so a lookout that reconnects or restarts mid-check runs the check again. A continuation submitted twice that way carries the same goal-BOT-TURN request id, and the daemon de-duplicates it.


Generated by Claude Code

…rk stays until its check says

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread sonny/src/lookout/goals.rs Outdated
Comment on lines +453 to +454
if let Some(goal) = read(&self.store, bot).filter(|goal| goal.check_after == Some(turn)) {
checked_now(&self.store, &goal);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Match settlement to the goal generation before clearing its marker

If /goal replaces an idle agent's goal while its check is running, check_now queues a Settled message for the aborted check and starts the replacement check against the same last turn. When that old message is consumed, settled matches only the bot and turn: it removes the replacement's tracking entry and clears the replacement's check_after, even though its check has not finished. A lookout restart during that replacement check then leaves the goal with neither a pending marker nor an event cursor to replay, so the idle agent never starts working. Carry the goal's set_ms through settlement and require it to match before modifying the active check or durable marker.

AGENTS.md reference: AGENTS.md:L32-L32

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 9e61b79. Settled now carries the checked goal's set_ms. Goals::settled removes a tracked check only when both turn and set_ms match, and clears check_after only on the goal with that set_ms. So the aborted check's settlement no longer touches the replacement's check or its marker.


Generated by Claude Code

George picked the Codex shape: the person's words reach the agent as their
message, and the agent sets the goal and its check with its goal tool,
whose description now says so. /goal shows the goals of the agent and its
tasks, and /goal clear clears its own, through the tool's own call. The
person-set check and check-at-once machinery is gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY
@lydakis lydakis changed the title Sonny: /goal sets the agent a goal by hand, checked at once when it is idle Sonny: /goal WHAT asks the agent to set its own goal; /goal shows, /goal clear clears Oct 30, 2026
@lydakis
lydakis merged commit 06aa631 into main Oct 30, 2026
4 checks passed
lydakis pushed a commit that referenced this pull request Oct 30, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGETkBwAL5VmcD7kf5q
lydakis added a commit that referenced this pull request Oct 30, 2026
* Sonny: a register of every feature it has had, and why (sonny/FEATURES.md)

Each Sonny feature added, changed or removed, with its pull requests,
status (experimental, shipped, removed), the reason, and a Used? column
for the person to fill in. AGENTS.md asks every pull request that
touches a Sonny feature to update its row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGETkBwAL5VmcD7kf5q

* FEATURES.md: the commons (#392)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGETkBwAL5VmcD7kf5q

* FEATURES.md: /goal (#397)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGETkBwAL5VmcD7kf5q

* FEATURES.md: #398 and #399

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jkdGETkBwAL5VmcD7kf5q

---------

Co-authored-by: Claude <noreply@anthropic.com>
@lydakis lydakis mentioned this pull request Oct 30, 2026
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.

2 participants