Repository navigation
fix(pi): end left runs before continuing Pi, add session controls, trim the README - #1498
Merged
Merged
Conversation
Ports the Pi plugin from #1103 onto current main as one commit. The plugin files are unchanged apart from following main's renames: - Me chats are Solo chats now: read `soloChat` from the agent's reads, and fake a Solo channel in the runtime test. - New agent's Instructions field is labelled optional. - Keep `buzz.pi` off by default beside `buzz.usage` in the bundled-default checks. Co-authored-by: Opus <f038cc09b32a776e7d95b65c267e9d851777ee2b6cdbd46a48edba01b1d10ebd@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
- Stop on a turn's activity aborts the Pi run it is in; a stopped turn posts no failure. - List each agent's sessions for plugins: its Pi conversations, read from Pi's storage when first asked, with Working or Idle while it runs here. - Hand a Solo chat's Canvas to each turn, and read no earlier messages of a chat its owner is still creating, as Claude and goose do. - Give the Buzz tools the community's relay, audience and workflow authorities, as the other harnesses do. - Tag Pi as a coding agent in the plugin catalog. Co-authored-by: Opus <f038cc09b32a776e7d95b65c267e9d851777ee2b6cdbd46a48edba01b1d10ebd@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
Pins @earendil-works/pi-durable, pi-ai and chord 1.3.0 (from 1.1.0) and follows the changes since: - A tool result's text for the model is `output` now, not `content`; with `content`, Pi showed the model an empty result for every Buzz tool. - Storage that fails now closes its Harness for good, so the host drops it and opens the agent again on the next request. The live host test now checks that the model reads what a Buzz tool answered, and that aborting a conversation leaves its request unanswered as `aborted`, which the runtime's Stop relies on. Co-authored-by: Opus <f038cc09b32a776e7d95b65c267e9d851777ee2b6cdbd46a48edba01b1d10ebd@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
The Buzz tools Claude and Codex load on search, the attention tools and those plugins add, are deferred in Pi too: each agent's registry has Pi durable's `tool_search`, which loads them when the model looks for them, and they stay loaded in that conversation. The Buzz tools section says what the search can find, as Claude's server instructions do. Co-authored-by: Opus <f038cc09b32a776e7d95b65c267e9d851777ee2b6cdbd46a48edba01b1d10ebd@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
…fely From review: - A wait that Pi's failed storage cut off now waits again once the agent is opened again, where the run continues, instead of failing the turn while the run goes on. - A new conversation is listed, and subscribers told, as its first turn is handed over rather than once it ends. - Listing sessions opens only the storage of an agent running here, and an agent's storage closes when it stops running here even if it only listed. - The README opens with the short Getting started guide every bundled plugin's has. Co-authored-by: Opus <f038cc09b32a776e7d95b65c267e9d851777ee2b6cdbd46a48edba01b1d10ebd@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
Signed-off-by: Salman Mohammed <smohammed@squareup.com>
Pi's install logic moves from bash into launch.mjs, plain Node, so it runs the same everywhere. On Mac and Linux pi.sh only finds Node, as before, then starts the launcher; Windows starts `node` itself. The host source and the lock go on stdin, since together they pass Windows' 32 KB command line. File uploads read through `host.files` instead of `base64`, so the Mac and Linux gate goes. npm now runs inside the install folder: npm 11 refuses `ci --prefix` to a folder outside where it runs. Co-authored-by: Opus <f038cc09b32a776e7d95b65c267e9d851777ee2b6cdbd46a48edba01b1d10ebd@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
…ive a host stopping mid-handover A mention queued behind another's handover no longer opens the agent's storage or reaches Pi once the agent is removed, retyped or disconnected; Pi's coding tools have no sandbox. Storage the handover opened again closes. A host that stops before it answers `deliver` may already have the turn. The runtime asks the next host again with the same request, which Pi durable finds by its request ID rather than taking twice. The host records a new conversation for its key before submitting to it, so the next host finds that conversation. Removes docs/view-pi-session.md, which describes the retired buzz-pi-acp integration, not Pi durable's storage. Co-authored-by: Opus <f038cc09b32a776e7d95b65c267e9d851777ee2b6cdbd46a48edba01b1d10ebd@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
Signed-off-by: Salman Mohammed <smohammed@squareup.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
- Finds Node set up in an interactive shell's rc file, such as nvm's or fnm's in .zshrc, taking its path from behind a marker past what the rc prints. - Usage adds what Pi durable recorded beyond the answers, such as compaction requests, as one more request per model; the host reads the totals. - A run resumed after an interruption replaces its partial answer and no longer shows as stopped; an owner's Stop still does. - The model field's button says it is the model and opens a dialog. - A wait after an agent's storage failed is told to open it again, so the runtime's retry finds the accepted turn rather than dropping it. - An agent's storage folder is 0700 and its database 0600, existing ones too; SQLite gives its -wal and -shm files the database's mode. - Runs an earlier app left unfinished are taken on at the first turn after it starts: they show as working, and their answer or failure is posted. Co-authored-by: Opus <f038cc09b32a776e7d95b65c267e9d851777ee2b6cdbd46a48edba01b1d10ebd@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
…n no key commands - A run adopted after a restart, in a conversation several threads share, answers in its mention's thread: the mention is read to find its root. - Setup reads Pi's providers and defaults again each time and when the window gets focus, so a /login or default chosen with the pi command shows. - The host no longer runs `!command` keys from auth.json. One host serves every agent, so a command held them all; such a key's turns now fail with a message to enter the key in Buzz. Co-authored-by: Opus <f038cc09b32a776e7d95b65c267e9d851777ee2b6cdbd46a48edba01b1d10ebd@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
… name Buzz runs as a desktop app without the shell's environment, so a `$NAME` key in Pi's auth.json fails its turn with the same message as a `!command` key. Main's activity layout names the opened conversation's button `View transcript: <channel>`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… waiting - Credential reads take the same lock as writes and `pi`, so a key save or refresh can't hand another agent's request a half-written auth.json. - Adoption resolves every left run's thread and send baseline before any wait, since a wait continues all of Pi's runs and one could send first. - Pi agents get the community repositories folder, as the other types do. - Point the no-model and package-provider errors at the Identity tab. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
A paused host whose stale lock another Buzz build takes over went on running the agent beside it. It now closes that agent's storage, which records no outcome for its runs, so the new owner continues them; opening again here says the agent is open in another Buzz app. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
…ntinue them Any delivery's wait continues every run in an agent's storage, so a watch's or timer's run left when the app quit resumed later with no deadline, lane or Stop. Adoption now ends those before any wait, as quitting ends other harnesses' turns, and leaves this app's own standalone turns alone when it lists left runs again. Recovered mentions still continue; their Stop is a follow-up. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
Keeps both Pi and relay notes in the plugins that start disabled. Signed-off-by: Salman Mohammed <smohammed@squareup.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Aborting a conversation resumes Pi's whole scheduler, so ending a left watch or timer run could let a mention left beside it send before its thread and sends were counted, or a sibling one-off run first. The host's drop now takes every left one-off at once and only withdraws queued requests and marks placed runs aborted, which continues nothing. Adoption asks for it after every mention's sends are counted and before any wait. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
Picks up the Usage plugin name fix for the catalog scroll browser test. Signed-off-by: Salman Mohammed <smohammed@squareup.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
Pi continues every run once asked anything. A failed `unfinished` or `drop` was logged and the turn went on, so a wait that reopened the agent continued the watch or timer run it had failed to end. - A taking-on of left runs that fails now fails the turn that needed it, forgets the mentions it took, and is done again by the next turn. - Opening an agent again, after its host stopped or its storage failed, lists and ends left runs before it waits or hands a turn over again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
Pi reads its stored Buzz prompts with its own small wrapper around the shared promptSections and promptMessage, as goose does, and Claude's prompt helper is private again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
Stop on a mention's activity needs the runner's job, which a run that an earlier app left has none of. Pi now has the session controls Claude, Codex and goose have, which act on a thread's conversation rather than a request, and so reach runs taken on after a restart. - Interrupt aborts the conversation's run, and any compaction in it. - Compact runs Pi durable's compact() and settles once the summary is placed. - New starts a new context with reset(), and the next turn is shown the whole Buzz conversation again. - A mention during an action waits for it, past its handover. Each action takes on left runs first, as Pi continues them once asked anything. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
# Conflicts: # src/bundled/pi/README.md # src/bundled/pi/host.live.test.ts # src/bundled/pi/host.mjs # src/bundled/pi/index.ts # src/bundled/pi/runtime.test.ts # src/bundled/pi/runtime.ts # src/bundled/pi/transcript.ts
The merge of main brought back the export that #1420 added for Pi, which now has its own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
kalvinnchau
reviewed
Oct 21, 2026
Pi durable records compaction's usage only in each conversation's totals, so Usage dates it all at the newest compaction. Manual Compact makes that more frequent, so the limit stays documented. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
Stopped in the tools phase, Pi durable writes an aborted result for each cut-off call (diagnostic code "aborted") and no aborted answer. The host now flags those results, and the transcript marks the turn stopped and the tool terminated rather than failed. An answer after them means only that call was aborted and the run went on, so it clears the stop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
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: 2278038391
ℹ️ 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".
Pi takes on runs left in its storage before any session action, and posting their answers needs the agent's handle. That handle came only from a delivery, so Compact and New were refused until the agent had been mentioned since Buzz started, unlike other harnesses. Session actions now take the handle from Agents.handle when no delivery has given one, so they run, with the shared busy state, at once. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
Compact and New are checked idle before Pi's storage opens and its left runs are taken on. A left run in the same conversation, found then, still got the action, and an Interrupt during that preparation did not stop the Compact or New sent after it. The action now stops when either happened, just before it reaches Pi. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
kalvinnchau
reviewed
Oct 21, 2026
kalvinnchau
reviewed
Oct 21, 2026
When the app quits or the host stops during a Buzz tool call, Pi tells the model the call may have run, so a send it makes again may be posted twice. The trimmed README had dropped this; a Stop or Interrupt does not cause it, as it ends the run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
…handovers on Interrupt A turn that gave up on its run, after the host stopped twice, storage kept failing or the retried hand-over failed, left the cached taking-on in place. The next turn then continued that run with nothing waiting for it. Such a turn now marks the agent's left runs to be listed again, so the next turn takes on or ends them first. Interrupt now also cancels a mention still being handed over, as Claude's does: it is not delivered and says nothing, and later mentions are unaffected. Also covers the retried hand-over listing and ending what the stopped host left before it delivers again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Salman Mohammed <smohammed@squareup.com>
kalvinnchau
approved these changes
Oct 21, 2026
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.
Review fixes on top of #1420.
What changed
f5b817d68). Pi continues every run as soon as it is asked anything. Before, a failedunfinishedordropwas logged and the turn went on, so a wait that reopened the agent continued the watch or timer run it had failed to end.abc3e0ef6). It gives up when the host stops twice while it waits, storage keeps failing, the retried hand-over fails, or a standalone turn fails after it submitted. Before, the cached taking-on was reused, so the next turn continued that run with nothing waiting for it.a53cbd3dd). Stop on a mention's activity needs the runner's job, which a run left by an earlier app doesn't have. Pi now has the composer's three session controls, as Claude, Codex and goose do (feat(agents): add buttons to compact and start new session #1434). They act on the thread's conversation rather than one request, so they reach runs taken on after a restart.compact()and settles once the summary is placed.reset(). The next turn is shown the whole Buzz conversation again, and the old turns stay in the transcript and in Usage.SessionControls. Each action takes on left runs first.c51d93b2c). Taking on left runs needs the agent's handle to post their answers; with no delivery's handle yet, the action takes it fromAgents.handle.11746cda2). A left run taken on in the same conversation refuses them, and an Interrupt during their preparation cancels them.abc3e0ef6). It is not delivered and posts nothing; later mentions are unaffected.16becb485). It has a small wrapper around the sharedpromptSectionsandpromptMessage, as goose does. Claude'spromptis private again, soclaude-code/transcript.tsmatchesmain.227803839). Stopped in the tools phase, Pi durable writes an aborted result for each cut-off call (diagnostic codeaborted) and no aborted answer, so the transcript showed a failed tool instead.21a3d36ff) from 167 to 50 lines: the required Getting started guide, the checks, how to update the packages, and the limits.a6ca0dfc4): Pi durable records compaction's usage only in each conversation's totals, so Usage dates it all at the newest compaction. Manual Compact makes that more frequent.sendlimit, with the mechanism corrected (6d57be244). Pi doesn't rerun a cut-off Buzz tool call; after a quit or host stop it tells the model the call may have run, and asendmade again may post twice. A Stop or Interrupt ends the run instead.Testing
bin/pnpm exec vitest run src/bundled/pi src/bundled/readmes.test.ts src/features/agents/service.test.ts: all pass.tsc --noEmitand biome are clean.7bb187829and passing here:drophands nothing over and waits for nothing, and the next turn ends the run firstdropafter reopening waits for nothingopen)unfinishedbeforedeliver(fails withoutabc3e0ef6)11746cda2)abc3e0ef6)PI_DEPS=… vitest run src/bundled/pi/host.live.test.ts) now also checks:pi.compactionsummarypi.resetand resets what the conversation was shownbashcall leaves a tool result flaggedaborted227803839, both the unit test and the live check.Known gaps
🤖 Generated with Claude Code