Repository navigation
Fix six rough edges from a day of running bots - #318
Merged
Merged
Conversation
Sonny gave the 1-hour cache only to bots it made from the terminal. Tasks started with start_task never got it, and leads made before that change stayed on five minutes, so every idle gap over five minutes reread the whole context. Tasks now start with --cache-ttl 1h for anthropic/ and bedrock/ models, and Sonny moves a bot it opens to that lifetime when it has another. The daemon's configure takes cache_ttl for that. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGEx3HPXnzgjwn75aHw
An empty reply to a prompt failed as empty_completion. Sonny's lookout asks a lead to end with an empty reply when a note needs nothing, so a lead that decided that without calling a tool failed and spent a full context. Saying nothing is the bot's choice; the turn completes with empty text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGEx3HPXnzgjwn75aHw
run, wait and the history listing name turns with store-wide handles (turn:BOT/N), while history's turn counts a bot's turns from 1, so a handle's number read another turn or none. history now takes handle in place of bot and turn, and turn_not_in_history says how turns are numbered. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGEx3HPXnzgjwn75aHw
A task called resolve_task and ended its turn with nothing, so its lead's wait read empty text and had to look elsewhere for the result. The tool now says the reply after it is what the lead reads. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGEx3HPXnzgjwn75aHw
A trigger named its store by the daemon's store identity, which hashes the file's inode, so a store put back from a copy failed every fire with store_mismatch, and the triggers dropped out of the lists that filter by the same id. Triggers now name the store's lineage, which a copy keeps; Sonny rewrites triggers made with the old identity once it opens on that store. A fire the daemon took no turn for (skipped while the bot works, or failed) now tells the reply agent, else the agent it messages, by attach, so a missed run is heard of in that agent's next model call. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGEx3HPXnzgjwn75aHw
A write whose content comes before its path, as a model may order it, was cut at its 2 KiB preview before the path. An ungated one has no node to read back, so every later gated call in the turn was escalated as "too long to show". tool_started now names the file of a cut write or edit as it does a patch's, the prompts read keeps those paths ahead of a call it cuts at its byte budget, and a write that still names nothing is said to be that, not the call being judged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGEx3HPXnzgjwn75aHw
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1bb9b60975
ℹ️ 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".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGEx3HPXnzgjwn75aHw
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGEx3HPXnzgjwn75aHw
This was referenced Oct 29, 2026
Merged
lydakis
pushed a commit
that referenced
this pull request
Oct 29, 2026
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
This was referenced Oct 29, 2026
lydakis
pushed a commit
that referenced
this pull request
Oct 29, 2026
#318's restamp still read the definition through Places::plist, which #344 renamed to Places::job, so main did not compile. The store id it rewrites now has a unit form too, and restamp runs at start on Linux. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGF2ShRt6WjfWgiPdZF
lydakis
pushed a commit
that referenced
this pull request
Oct 29, 2026
#344 renamed Places::plist to Places::job while #318 added a call to the old name, so main stopped compiling. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGCoLcHQMmGw188SP8o
lydakis
added a commit
that referenced
this pull request
Oct 29, 2026
#318's restamp still read the definition through Places::plist, which #344 renamed to Places::job, so main did not compile. The store id it rewrites now has a unit form too, and restamp runs at start on Linux. Claude-Session: https://claude.ai/code/session_013jkdGF2ShRt6WjfWgiPdZF Co-authored-by: Claude <noreply@anthropic.com>
This was referenced Oct 29, 2026
Merged
lydakis
added a commit
that referenced
this pull request
Oct 30, 2026
…oal clear clears (#397) * Goals: keep an agent working until a check command passes 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 * Goals: the lead-reaction test's lookout gets its goals * Goals: answer Codex's review - 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 * Triggers: restamp reads the job file by its new name 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 * Goals: answer Codex's second review - 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 * Goals: a turn its check holds is not judged, and a goal given up while its check ran ends so Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY * Goals: a goal set again counts its turns without a tool from 0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY * Goals: a dropped connection stops the checks under way, which the replay runs again Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY * Goals: a stopped check takes what it started with it, and a replayed turn is not counted twice Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY * Goals: the lead hears how a goal ended in the lookout's words only 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 * Goals: a lookout giving way stops its checks, and only a heard task's turn waits on one Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY * Goals: a check runs where its turn worked, and how a goal ended survives a later turn's news Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY * Goals: a check goes without every provider key an agent's shell does Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY * Goals: tests for a goal its lead sets, a turn that ends mid-check, and 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 * Goals: a turn the lead's wait read still says how its goal ended Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY * Goals: the held-turn test asks due() as main's lookout has it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY * Goals: a check under way keeps the replay cursor before its turn, watched or not Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY * Goals: a wait that reads a turn leaves how its goal ended to tell Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY * Goals: a trigger passing a turn's answer on leaves how its goal ended to tell Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY * Goals: deleting an agent stops its check Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY * Goals: a goal set again while its last one is checked is checked afresh Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY * Goals: how a goal ended is news even while the lead waits on its turn Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY * Daemon companions: commands the daemon keeps running for as long as it 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 * Companions: log setup off the runtime thread, the whole group stopped, 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 * Companions: idle-exit counts from the last client's activity, a companion'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 * Companions: a session is a companion's or not once, as it opens Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY * Sonny: /goal sets the agent a goal by hand, checked at once when it is 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 * Goals: /goal starts an agent with no turn yet, and a check-at-once mark stays until its check says Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY * Goals: a check settles only what is its own goal's, by when it was set Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jkdGHCyGRHdT5WYDPKVFY * Goals: /goal WHAT goes to the agent as typed, which sets its own goal 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 --------- Co-authored-by: Claude <noreply@anthropic.com>
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.
Requested by George · project thread
Six fixes from a day of running bots, one commit each.
What changes
start_taskwere created without--cache-ttl, and leads made before the hour-long default were still on 5 minutes. So any gap over 300 s re-read the whole context uncached. Now tasks start with1h, and when Sonny opens an existing Claude bot whose TTL differs from the policy, it moves the bot to1hwith the newconfigurefieldcache_ttl. The protocol version is unchanged.store_mismatch, andtrigger lsand the background view filtered those triggers out. Triggers now pin the store's lineage, which survives a copy. Sonny also restamps any trigger plists still carrying the old identity when it starts. A fire that is skipped or fails attaches one line to its reply-to bot (or else its target), so the agent finds out without starting a turn.empty_completion. Now any empty completion completes with empty text.{"content": …, "path": …}. Past the 2 KiB preview the path was gone, and an ungated write has no planning node to read back, so every later gated call that turn was escalated as "the call is too long to show".tool_startednow names the file of a cutwriteoredit, as it already did forapply_patch. Thepromptsread keeps those paths ahead of a call it cuts at its byte budget. When a write still names nothing, the escalation says that, instead of blaming the call under review.resolve_taskdescription now says the reply after the call is what the lead reads. Before, a task could call it and then end with nothing, so the lead'swaitgot empty text.historyreads a turn by its handle. Every tool hands outturn:BOT/Nwith store-wide numbers, buthistory'sturncounts one bot's turns from 1. The tool now takeshandle, andturn_not_in_historysays how each one is numbered.Checked
cargo fmt --check,cargo clippy --workspace --all-targets -D warningsandcargo test --workspacepass.test_configure_moves_a_bot_to_the_hour_long_cachetest_a_fire_finds_its_store_after_the_file_was_replacedtest_an_empty_reply_ends_a_turn_after_a_tool_call_and_after_a_prompttest_an_ungated_write_cut_before_its_path_still_names_its_filetest_siblingstest_triggertool_startednow parses the arguments of a cut write or edit once. That is oneserde_jsonread of a call that already arrived whole, the same work a cut patch already did. Thepromptsread parses only the one call it cuts at its budget.No screenshots: nothing here changes what Sonny draws.
Generated by Claude Code