Notify on background-workflow completion (banner + agent summary) - #302
Merged
Merged
Conversation
… run finishes
Background workflows enqueue a <task-notification> envelope on completion, but
nothing in the REPL ever drained that queue — its own docstring admits the
consumer ("WI-3.3") was deferred. So a finished /deep-research run surfaced only
by polling /workflows, with no completion signal and no pointer to the results.
Wire the consumer:
* src/repl/task_notifications.py (new, pure/tested): deterministic completion
banner from the terminal task state (✔/✗/⊘ · name · agents · tokens · duration
· run journal), an envelope fallback, and build_notification_turn() which wraps
drained envelopes in a guiding system-reminder for the agent.
* REPL glue (core.py): _deliver_pending_task_notifications() drains the queue at
the turn boundary, prints each banner, then feeds the envelopes to the agent as
one turn so it reads the result and summarizes conversationally — the Claude
Code "the research is done…" behavior. A daemon watcher wakes the idle ❯ prompt
the moment a run finishes (verified cross-thread against prompt_toolkit 3.0.x
via app.exit), so it surfaces without a keystroke — and never clobbers a
half-typed line or a permission dialog.
Tests (15): pure helpers, the REPL delivery method (banner + single agent turn,
no-op on empty queue), the wake guard (idle+empty exits; half-typed/not-running
don't), the watcher (wakes when idle+pending, silent otherwise), and an
end-to-end run through the production launcher → enqueue → REPL delivery with a
fake runner. Pre-existing test_workspace_search_c5 failures (ripgrep env) are
unrelated.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
singlaamitesh
pushed a commit
to singlaamitesh/clawcodex
that referenced
this pull request
Jul 7, 2026
…low-completion-notifications Notify on background-workflow completion (banner + agent summary)
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.
Problem
You ran
/deep-researchend-to-end — all 15 agents finished, Synthesize completed — but the REPL never told you. The only way to see it was done was to keep polling/workflows, and even then there was no pointer to the results.Root cause: on completion,
complete_workflow_task→enqueue_workflow_notificationdutifully builds a<task-notification>(result + output location + token/agent stats) and pushes it onto themessage_queue_managerqueue… and nothing in the REPL ever drains that queue.drain_pending_notificationshad zero production callers — its own docstring admits the consumer side ("WI-3.3") was deferred. The notification was built and dropped on the floor.Fix
Wire the missing consumer, matching the Claude Code reference you showed (banner, then the agent reads + summarizes):
src/repl/task_notifications.py(new, pure + fully unit-tested): deterministic completion banner from the terminal task state (✔/✗/⊘· name · agents · tokens · duration · run journal), an envelope-only fallback, andbuild_notification_turn()that wraps drained envelopes in a guiding<system-reminder>for the agent.core.py):_deliver_pending_task_notifications()drains the queue at the turn boundary, prints each banner, then hands the envelopes to the agent as one turn so it summarizes and points to where the output lives. A daemon watcher wakes the idle❯prompt the moment a run finishes — so it surfaces without a keystroke — and is careful to never clobber a half-typed line or a permission dialog (only wakes when the prompt is running with an empty buffer).The cross-thread wake (
app.exitvialoop.call_soon_threadsafe) was verified against prompt_toolkit 3.0.52 under a PTY before building on it.Tests — 15, all green
Pure helpers; the REPL delivery method (banner + exactly one agent turn; no-op on empty queue); the wake guard (idle+empty exits; half-typed / not-running don't); the watcher (wakes when idle+pending, silent when not at prompt); and an end-to-end test driving the real production launcher (
run_workflow_task) → enqueue → REPL delivery with a fake runner.Scope note
Banner + agent-summary is the behavior you picked.
ppause /ssave and other surfaces are untouched. This consumer also covers background agent task notifications (same queue), not just workflows.🤖 Generated with Claude Code