Repository navigation
feat: notify participants when their agent run finishes or fails - #255
Merged
Merged
Conversation
Channels publish each run a person invoked as it ends (done, failed, or stopped, with the author of the newest human input it answered). Hosts project the latest end into the catalog and listings as `ran`, carried over the workspace socket for hosted channels. The app marks the row of an unseen end the current user started (dot for done, attention mark for failed), pulses the window glow when another channel is open, and sends a native desktop notification when the window is unfocused. Part of #12. Waiting-for-answer attention depends on #21. Why: packages/channel/src/channel.ts#fn #ended | pi settles a run's inputs in the same commit that removes LiveDoc.run; read the outcome from that commit's submission changes, not from the transcript Why: packages/channel/src/room.ts#fn isAgent | subagent and cross-channel inputs are authored agent@...; runs they start must not notify a person Why: apps/app/src/attention.ts | `told` persists per host and user so reloads and reconnects never re-notify the same run end; `since` keeps history from lighting up on a first visit
This was referenced Oct 14, 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.
Part of #12. Covers finished and failed runs. Waiting-for-answer attention is left out because it depends on #21, and Ace has no question tool yet.
Channel.
#runsnow keeps each live run's inputs from pi'sLiveDoc. WhenLiveDoc.rungoes away, the same commit carries pi's settlement of those inputs:donemaps todoneunanswered/abortedmaps tostoppedmodel_error,no_model,faulted, …) maps tofailedThe author is the newest input entry the run answered that has a human author, found with one
tx.entryread per input. Transcripts are not scanned. Runs whose inputs all haveagent@…authors publish nothing; these are subagent chats and cross-channel messages. The new optiononRun(run: RunEnd)publishes{ chat, at, outcome, author }.RunEndlives in@ace/channel/protocol.Host. The worker writes the latest end into the catalog record as
ran. Hosted channels send{ ran }overWorkspaceMessage. Listings exposeran?: RunEnd. Likeactive, it is a hint that persists across worker restarts. pi still owns the runs, and losingranloses only pending attention.App (
apps/app/src/attention.ts):{ since, seen, told }in browser storage, keyed by host URL and user.sinceis the first visit, so history never lights up.tolddedupes signals across reloads and reconnects.donegivesunreadCount: 1(a dot, "1 new message").failedgivesneedsAttention(the wave, "Agent needs your attention").stoppedis ignored.notifyDesktopRPC request callsUtils.showNotificationwith the channel name as title and "Agent finished" or "Agent run failed" as body.Docs.
docs/architecture.mdcovers the projection and explains that this is per-user client attention, not lobbies.Verification
All of this ran against a real source host with an isolated
ACE_HOME,ACE_CONFIG_HOME,ACE_PORT=4791, a non-existentACE_KEYCHAIN_SERVICE(so there were no keychain prompts) andACE_USER. The only model key available without prompting wasOPENAI_API_KEY, and OpenAI rejects it with 401.ranuntil its next run.failed: a run in that channel producedran: { outcome: "failed", author: "tester" }in the catalog and in gateway listings.stopped: an ask followed by a stop 0, 50 and 150 ms later producedoutcome: "stopped"each time.ran. A run interrupted by SIGTERM resumed when the channel reopened, then published its end.run.publishlogged no warnings.data-loadingappeared within 100 ms and cleared after the pulse).seen.bun typesandbun run cipass (265 files).Not verified:
done: no working model key was available without the keychain, so this outcome is untested and so is the dot it produces. It uses the same path, with pi'sdonesettlement.{ ran }path is only type-checked. No hosting service was deployed.Limitations
showNotificationhas no click callback, so the native notification can't link to the chat.donerow's expanded text reads "1 new message".Built in Ace
No. Made by a Claude Code subagent in a terminal at the maintainer's choice for this session; not an Ace capability gap. Dogfooding: #5.