🤖 feat: notify on terminal background work#3632
Conversation
…; thread workflow run policy
…le-drain notifier
…fier (busy/queued deferral, restart-safe)
…ynthetic-message stories for notify-on-terminal
…ccept; persist notify on foreground-wait timeout detach
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 83b1c999cb
ℹ️ 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".
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
|
@codex review Re-requesting on the latest head after resolving the previous threads and retriggering checks. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 55d64c4ca2
ℹ️ 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".
|
Addressed the latest Codex P2 findings in 8dbd050:
Validation on the pushed head:
|
|
@codex review Please review the latest pushed fixes for the two P2 findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8dbd0506f2
ℹ️ 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".
|
Addressed the second Codex P2 findings in c9b877b:
Validation on the pushed head:
|
|
@codex review Please review the latest pushed fixes for the second P2 round. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c9b877b8fa
ℹ️ 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".
|
Addressed the latest Codex findings in 0a62cb0:
Validation on the pushed head:
|
|
@codex review Please review the latest pushed fixes for the P1/P2 drain and completion-recovery findings. |
|
Addressed the auto-retry-start waiter gap in bdc522f:
Validation on the pushed head:
|
|
@codex review Please review the latest pushed fix for waking terminal-attention drain waiters when auto-retry starts. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bdc522fc7c
ℹ️ 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".
|
@codex review Pushed one more retry-state hardening fix: |
|
@codex review The retry-startup thread is now resolved after the pushed fix. Please review the latest head. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7b2cb3d899
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 30c6685b0c
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 54ee67e98b
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8363d18f03
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7ac8f15a8c
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3621cb51a4
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 34be8c8b07
ℹ️ 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".
|
Codex Review: Didn't find any major issues. Keep them coming! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
Summary
Refactors background work orchestration so intentionally backgrounded tasks, workspace turns, and workflow runs no longer force broad active
task_awaitprompts at parent turn-end. Background launches now persist an internal notify-on-terminal attention policy, keep the parent free to finish its turn, and wake the owner only when terminal output is ready to integrate.Background
Previously
run_in_background: truework could still be re-forced through broad parent stream-end await prompts, which made background execution behave like foreground execution and caused agents to spend extra turns polling. The accepted implementation plan called for separating true blocking dependencies from background work that should notify only on terminal completion.Implementation
BackgroundWorkAttentionPolicywith legacy-safe blocking defaults.task_awaitprompts.task_await(..., timeout_secs: 0)wake-up.Validation
MUX_ESLINT_CONCURRENCY=1 make static-checkbun test src/node/services/taskService.test.ts -t "background"bun test src/node/services/taskService.test.ts -t "workspace-turn"bun test src/node/services/taskService.test.ts -t "workflow"bun test src/node/services/tools/task_await.test.ts src/node/services/tools/workflow_run.test.ts src/node/services/tools/workflow_resume.test.tsagent-browseragainst Storybook synthetic auto-resume messages and a dev-server sandbox. Evidence included screenshots/videos/report in/tmp/mux-notify-dogfoodand was attached in the workspace chat.Risks
This touches task lifecycle orchestration, workspace-turn settlement, workflow run records, and model-facing tool guidance. Regression risk is mainly around incorrectly classifying active work as non-blocking or duplicating terminal wake-ups; mitigations include persisted legacy-default blocking behavior, explicit terminal notification idempotency, queued/streaming owner deferral, restart-safe tests, and targeted task/workflow integration coverage.
Pains
The refactor crossed several durable-state seams (workspace config, handle store, workflow store, generated skill bundles, tool docs). Electron desktop GUI dogfooding was unavailable in this headless workspace, so browser evidence was captured through Storybook and dev-server sandbox instead.
📋 Implementation Plan
Implementation Plan: Replace Broad Background-Task Force-Awaits with Terminal Wake-Ups
Objective
Refactor Mux's background-work orchestration so agents are not broadly forced to await every active background task at turn end. Instead:
task_awaitbefore the agent can conclude.This preserves correctness for dependency-driven parallel work while making
run_in_backgroundbehave like real background execution.Evidence gathered
Verified through repo inspection and Explore sub-agent reports:
src/node/services/taskService.tsbuildBackgroundAwaitPrompt()currently emits theMUST NOT end your turnprompt and instructs the agent to calltask_awaituntil all listed work is terminal.handleStreamEnd()currently auto-resumes parent workspaces whenever active descendant tasks, active workflow runs, or active workspace-turn handles exist.userBackgroundedTaskIds, but a later stream-end can force the await again.<mux_subagent_report>and usesCOMPLETED_BACKGROUND_SUBAGENT_HANDOFF_PROMPT, which tells the parent to integrate injected reports withouttask_await.<mux_subagent_failure>and usesFAILED_BACKGROUND_SUBAGENT_HANDOFF_PROMPT.wst_...) persist terminal output inTaskHandleStore; they do not inject output into parent history, so completed output must still be retrieved withtask_await.src/node/services/taskHandleStore.tsWorkspaceTurnTaskHandleRecordis persisted per owner workspace and is the right persisted seam for workspace-turn attention policy and terminal wake-up state.src/common/schemas/project.tsWorkspaceConfigSchemapersists child task metadata (parentWorkspaceId,taskStatus,workflowTask,bestOf, model/thinking settings) and is the right seam for sub-agent attention policy.src/common/orpc/schemas/workflow.tsandsrc/common/types/workflow.tsWorkflowRunRecordSchemapersists workflow run state and is the right seam for workflow attention policy.src/node/services/aiService.tsonBackgroundRunTerminalalready feeds terminal workflow results back as a synthetic continuation usingrequireIdle: trueandstartStreamInBackground: true.task_awaitwhile it is still running; terminal wake-up already exists for top-level background workflow runs.src/node/services/taskService.test.tssrc/node/services/tools/task_await.test.tssrc/node/services/tools/workflow_run.test.ts/workflow_resume.test.tsif schema/result notes change.src/browser/features/Messages/MessageRenderer.stories.tsxand currently still contains older force-await /task_awaitwording.Recommended approach
Approach A — Recommended: internal attention policy derived from launch intent
Net product LoC estimate: +850 to +1,150 product LoC.
Introduce a persisted internal attention policy for background work, but do not expose a new model-visible tool parameter in the first implementation. Derive policy from existing intent:
run_in_background: false/ foreground waits →blocking_until_terminal.run_in_background: true→notify_on_terminal.notify_on_terminalinstead of relying on a one-shot in-memory exemption.This keeps the public tool interface small while aligning behavior with the existing meaning of
run_in_background.Explicit v1 semantic tradeoff: in this plan,
run_in_background: trueis intentionally redefined as “non-blocking with terminal wake-up.” Agents that need a result before answering should either use the foreground/default mode or explicitly calltask_awaitbefore finalizing. This is a behavioral change from today's effective force-await safety net, so the tool descriptions and tests must make the new contract unambiguous.Alternatives considered
Approach B — Expose
attention_policyon task/workflow toolsNet product LoC estimate: +1,050 to +1,450 product LoC.
Add a public
attention_policyfield totask,workflow_run, and possiblyworkflow_resumetool schemas. This is more flexible (blocking_until_terminal,notify_on_terminal,silent_background) but increases model-facing interface complexity and creates new misuse modes. Defer until users need explicit silent/background semantics beyondrun_in_background.If implemented later, optional tool schema fields must use
.nullish()per repo convention, not.optional()alone.Approach C — Remove the force-await guard globally
Net product LoC estimate: +80 to +160 product LoC.
Simply stop auto-resuming on active descendants/workflows. This is too risky: agents could finalize answers before dependency results arrive, breaking best-of-N, foreground task calls, workflow-owned work, and task-local background workflows.
Reject this approach.
Target design
Attention policy domain model
Add a shared internal type/schema, e.g.
src/common/types/backgroundWorkAttention.ts:Phase 1 intentionally omits
silent_backgroundfrom persisted/public state unless implementation shows it is nearly free. The product need isnotify_on_terminal, and avoiding unused policy variants keeps behavior auditable.Policy semantics:
blocking_until_terminalbuildBackgroundAwaitPrompt()behavior remains appropriate.notify_on_terminaltask_await.Output-delivery rules
task_await.wst_...)TaskHandleStore, not injected into parent history.task_await({ task_ids: [...], timeout_secs: 0 })to retrieve terminal output. Do not instruct repeated waiting.wfr_...)AIService.onBackgroundRunTerminalinjects workflow result context and starts a continuation when current and idle.task_awaitwhile running. Preserve existing terminal continuation.Terminal notification delivery seam
Add a small delivery seam (helper/module) so terminal wake-ups are not ad-hoc
sendMessage()calls from settlement paths. Suggested name:TerminalAttentionNotifierplus a tinyTerminalAttentionNotificationStore.Responsibilities:
Persist pending terminal notifications in the owner workspace session directory, keyed by source kind + source ID, e.g.:
Top-level workflow terminal continuation already has a specialized path in
AIService.onBackgroundRunTerminal; do not route workflows through this notifier in the first PR unless doing so avoids duplication and preservesisWorkflowInvocationCurrent().Coalesce by owner workspace before sending:
task_awaitwith these terminal IDs andtimeout_secs: 0” wake-up.Drain only when the owner is idle:
pending.Never send while holding settlement locks:
workspaceService.sendMessage()calls or retry loops while holdingworkspaceTurnSettlementLocks,workspaceEventLocks, the broadTaskServicemutex, or task-finalization locks.Preserve existing parent resume/send behavior:
agentId, thinking level, and relevant resume metadata/options through the same path as existing TaskService parent auto-resumes (e.g.resolveParentAutoResumeOptions()or a small injected equivalent).{ synthetic: true, agentInitiated: true, skipAutoResumeReset: true, requireIdle: true }.Mark delivered only after accepted send:
deliveredAt/terminalAttentionNotifiedAtaftersendMessage()succeeds.sendMessage()returns busy, leave pending and retry on the next drain trigger.supersededwith a logged reason and leave the underlying report/handle retrievable.This notifier is the deep module for terminal attention delivery: settlement code should not need to know retry/coalescing/currentness details beyond enqueueing the right notification.
Explicit out of scope: background bash handles
The current active turn-end guard under discussion covers sub-agent tasks, workspace-turn handles, and workflow runs. Background
bash(run_in_background=true)processes are surfaced by the bash/task await tooling but are not part of theTaskService.handleStreamEnd()descendant/workflow force-await inventory. This plan does not add attention policy for background bash handles. If implementation discovers a separate bash force-await path, treat that as a follow-up design rather than silently folding it into this refactor.Implementation phases
Phase 0 — Baseline and invariants
bun test src/node/services/taskService.test.ts -t "auto-resumes a parent workspace until background workflow runs finish"bun test src/node/services/taskService.test.ts -t "does not auto-resume for queue-backgrounded descendants"bun test src/node/services/taskService.test.ts -t "tasks-completed auto-resume preserves parent agentId"bun test src/node/services/tools/task_await.test.ts -t "backgrounded"src/browser/features/Messages/MessageRenderer.stories.tsxQuality gate: baseline targeted tests either pass or failures are recorded as unrelated pre-existing failures before implementation proceeds.
Phase 1 — Persist attention policy on each work-handle kind
1. Add shared policy schema/type
Create a small shared type module for
BackgroundWorkAttentionPolicyor colocate the schema in an existing common task/workflow type module if a better existing home is obvious.Defensive checks:
Record<BackgroundWorkAttentionPolicy, ...>anywhere prompts/labels are mapped.blocking_until_terminalfor backward compatibility.2. Sub-agent task workspaces
Update
WorkspaceConfigSchemainsrc/common/schemas/project.tswith optional persisted metadata such as:Implementation notes:
taskAttentionPolicyrather than genericattentionPolicyto avoid confusion with unrelated workspace metadata.TaskService.create()based on the call's launch mode.blocking_until_terminal.3. Workspace-turn handles
Update
WorkspaceTurnTaskHandleRecordandWorkspaceTurnTaskHandleRecordSchemainsrc/node/services/taskHandleStore.tswith:attentionPolicy?: BackgroundWorkAttentionPolicyterminalAttentionNotifiedAt?: string(mandatory for restart-safe one-shot terminal wake-up dedupe).Populate
attentionPolicyinTaskService.createWorkspaceTurn().4. Workflow runs
Update
WorkflowRunRecordSchemainsrc/common/orpc/schemas/workflow.tswith optionalattentionPolicy.Thread policy through:
src/node/services/tools/workflow_run.tssrc/node/services/tools/workflow_resume.tswheneverworkflow_resume({ run_in_background: true })resumes or continues a run in the background; resumed background runs must persist/retainnotify_on_terminalso they do not re-enter active force-await behavior.src/node/services/workflows/WorkflowService.tscreate/start input and run creation.Default existing runs to
blocking_until_terminalunless the runtime can infer they were started via a background tool invocation. For first implementation, explicit new runs are enough; legacy runs can remain conservative.Quality gate: schema/type tests parse old records without policy and new records with policy;
make typecheckshould catch every place that needs threading.Phase 2 — Derive policy from launch/wait intent
1.
tasktool launch intentIn
src/node/services/tools/task.tsandTaskService.create()/TaskService.createWorkspaceTurn():run_in_background: true→notify_on_terminal.run_in_background: false→blocking_until_terminal.Keep the model-facing
tasktool schema unchanged in Phase 1/2. Update only descriptions/notes to say Mux will wake the workspace when intentionally backgrounded work completes.2. Detached foreground waiters
Replace the one-shot
userBackgroundedTaskIdsmental model with durable policy escalation for every foreground-wait detachment path:waitForAgentReport()orwaitForWorkspaceTurn()is backgrounded because a queued message arrives (ForegroundWaitBackgroundedErrorpath), persist that task/handle asnotify_on_terminal.notify_on_terminalfor that handle/run as well.markBackgroundWorkNotifyOnTerminal(...), rather than adding another in-memory exemption.Keep durable attention policy separate from
markTaskForegroundRelevant():markTaskForegroundRelevant()may still manage transient waiter bookkeeping, but it must not clear durablenotify_on_terminalpolicy.task_awaiton a notify handle is allowed and should resolve/reject normally, but it must not automatically re-promote the persisted policy toblocking_until_terminal.3. Workflow launches
For
workflow_run({ run_in_background: true })andworkflow_resume({ run_in_background: true }):attentionPolicy: "notify_on_terminal"on the workflow run.AIService.onBackgroundRunTerminalcontinuation for top-level background runs.task_awaitonly when the current request depends on immediate output.Quality gate: targeted unit tests prove policy is stored for new sub-agent tasks, workspace-turn handles, and background workflow runs.
Phase 3 — Filter active work at parent stream-end
Refactor the parent branch of
TaskService.handleStreamEnd()so it builds an inventory of active work:Implementation details:
TaskService:resolveAgentTaskAttentionPolicy(taskId, cfg)resolveWorkspaceTurnAttentionPolicy(ownerWorkspaceId, handleId)resolveWorkflowRunAttentionPolicy(workspaceId, runId)listBlockingActiveDescendantTaskIds(ownerWorkspaceId, cfg)listBlockingActiveWorkflowRunIds(ownerWorkspaceId, runIds)kind="workspace"task workspaces, do not finalize thewst_...handle while that workspace still has active descendants, workspace-turn handles, or task-local workflow dependencies that would make its final output incomplete.blockingTaskIds = getBlockingTaskIds(activeTaskIds)logic with policy-aware filtering.buildBackgroundAwaitPrompt()forblocking_until_terminalwork.notify_on_terminalwork remains active:Important behavior changes:
task_awaitprompt.Quality gate:
taskService.test.tsproves default blocking behavior remains,notify_on_terminalactive work does not force await, and mixed blocking/notify prompts include only blocking IDs.Phase 4 — Terminal wake-ups for notify-on-terminal work
1. Reuse existing sub-agent terminal handoffs
For successful sub-agent tasks:
deliverReportToParent()and the existing injected<mux_subagent_report>artifact.COMPLETED_BACKGROUND_SUBAGENT_HANDOFF_PROMPTfrom finalization, enqueue aTerminalAttentionNotificationwithoutputDelivery: "already_injected"and letTerminalAttentionNotifierdrain it when the owner is idle.For terminal sub-agent failures:
<mux_subagent_failure>injection.TerminalAttentionNotificationwithoutputDelivery: "already_injected"and let the notifier compose the failure handoff prompt when it drains.Foreground waiter consumption rule:
hadForegroundWaitersskip semantics. If an active foregroundtask_await/waitForAgentReport()consumed the sub-agent report or failure, do not enqueue a terminal notification for that source.waitForWorkspaceTurn()has an active foreground waiter that receives the terminal result, do not enqueue a duplicate terminal wake-up.notify_on_terminalwork can still be explicitly awaited, but a successful explicit await suppresses the later synthetic wake-up for that terminal result.Coalescing recommendation:
2. Add workspace-turn terminal wake-up
Workspace-turn output is not injected, so add a new prompt constant near existing background handoff prompts:
Implementation details:
settleWorkspaceTurn()on first active → terminal transition whenattentionPolicy === "notify_on_terminal".workspaceTurnSettlementLocks, persist the terminal record and enqueue a pendingTerminalAttentionNotification; do not callsendMessage()from inside the lock.TerminalAttentionNotifiersend torecord.ownerWorkspaceIdafter the lock is released with:synthetic: trueagentInitiated: trueskipAutoResumeReset: truerequireIdle: truewst_...IDs. Usetimeout_secs: 0in prompt because the handle is terminal and this should be retrieval, not waiting.Workspace-turn settlement may need a small interface adjustment so waiter consumption is observable:
settleWorkspaceTurnWaiters()(or its caller) to return whether any foreground waiter consumed the terminal result.workspace_turn_terminalnotifications when no foreground waiter consumed the result.Workspace-turn wake-up idempotency is mandatory:
terminalAttentionNotifiedAt(or an equivalent notification token) on theWorkspaceTurnTaskHandleRecordonly after the synthetic wake-up is accepted/sent.3. Preserve workflow terminal continuation
For top-level background workflows:
AIService.onBackgroundRunTerminalalready handles it.attentionPolicy === "notify_on_terminal"as non-blocking.isWorkflowInvocationCurrent()andrequireIdle: truesemantics unchanged.4. Busy/queued-turn gating, currentness, and supersession
Terminal wake-ups must have an explicit owner-workspace gating policy:
aiService.isStreaming(ownerWorkspaceId)is true, do not interrupt the active stream.workspaceService.hasPendingQueuedOrPreparingTurn(ownerWorkspaceId)is true, do not inject ahead of the user's queued/preparing turn.task_list/task_await.Work-kind-specific currentness:
isWorkflowInvocationCurrent()before terminal continuation; preserve that behavior.requireIdle: truethrough the notifier drain. IfrequireIdlefails because the workspace is busy, leave the notification pending without markingterminalAttentionNotifiedAt; a later idle/stream-end drain trigger should retry it.If implementation needs stronger stale-result handling, add helper(s) modeled on workflow currentness:
Do not silently broaden wake-ups beyond existing currentness semantics; add tests for whichever skip/defer policy is implemented.
Quality gate: terminal wake-up tests prove sub-agent reports/failures still wake once, workspace-turn terminal handles wake with
task_await timeout_secs: 0, and workflow terminal continuation is not duplicated.Phase 5 — Update tool descriptions, built-in skills, and synthetic story copy
Update wording so model instructions match behavior:
src/common/utils/tools/toolDefinitions.tstasktool:run_in_background: truereturns immediately; Mux may wake the workspace when the task completes.task_awaitis for when the current request depends on the output or the agent chooses to inspect progress.task_awaittool: remove or soften the line that says synthetic follow-ups with active background work are always blocking, or narrow it to “blocking dependency follow-ups”.workflow_run/workflow_resume: background runs may wake on terminal result;task_awaitremains available for explicit progress checks.$workflow-authoring: explain the internal persisted attention policy for workflow runs and workflow-owned steps.$loop: explain how loop/orchestration authors should choose foreground/default execution vsrun_in_background: truebased on whether the next decision depends on the result.attentionPolicyis internal in v1 and is not a field authors/agents pass directly.src/browser/features/Messages/MessageRenderer.stories.tsxMUST NOT endexamples with updated blocking-only wording and terminal wake-up examples.task_awaitfor already-injected reports.Built-in skill policy guidance to add
Add equivalent guidance to
$workflow-authoringand$loopso agents understand the inferred policy without needing a new tool argument:task,workflow_run,workflow_resumerun_in_backgroundor set it tofalse.blocking_until_terminaltask,workflow_run,workflow_resumerun_in_background: trueonly when unrelated work can proceed.notify_on_terminalnotify_on_terminalnotify_on_terminaltask_awaiton notify worknotify_on_terminal; if the waiter consumes the terminal result, no duplicate wake-up is sent.agent(),parallel(),pipeline(), nestedworkflow()Suggested
$workflow-authoringwording:Suggested
$loopwording:Avoid tautological tests that assert exact prompt prose unless the behavior depends on a specific machine-readable ID list.
Quality gate: tool descriptions, built-in skill docs, and Storybook stories all describe the same inferred-policy behavior without advertising an unsupported public
attentionPolicy/attention_policytool argument; Storybook renders the new synthetic-message states without layout regressions.Test plan
Unit tests to add/update
src/node/services/taskService.test.tsblocking_until_terminalpolicy still triggers parent auto-resume withbuildBackgroundAwaitPrompt().taskAttentionPolicy: "notify_on_terminal"does not trigger parent auto-resume at stream-end.task_awaiton notify work does not re-promote to blocking or duplicate wakenotify_on_terminal.agentId, model, and thinking-level behavior from stream-end metadata/history/defaults.synthetic,agentInitiated,skipAutoResumeReset, andrequireIdle.wst_...with notify policy does not trigger parent active-await prompt.settleWorkspaceTurn()terminal transition enqueues a pending notification, then the notifier sends a synthetic prompt to the owner workspace after locks are released and the owner is idle.timeout_secs: 0guidance.terminalAttentionNotifiedAtis already present.kind="workspace"task workspace with active descendants/workflows does not settle itswst_...handle before those dependencies are terminal or explicitly non-blocking under the target workspace's own policy.buildBackgroundAwaitPrompt()at parent stream-end.onBackgroundRunTerminalcontinuation remains responsible for terminal wake-up.norvariantsdo not cause repeated wake-up spam; the idle parent wakes once with all injected terminal reports available.promptTaskForBackgroundAwait()before final report unless explicitly handled by workflow ownership.src/node/services/tools/task_await.test.tstimeout_secs: 0returns terminal report/error without blocking.Workflow tests
workflow_run({ run_in_background: true })persistsattentionPolicy: "notify_on_terminal".workflow_resume({ run_in_background: true })persists or retainsattentionPolicy: "notify_on_terminal".Schema tests
WorkspaceConfigSchemaparses old child workspaces withouttaskAttentionPolicy.WorkspaceTurnTaskHandleRecordSchemaparses old handles withoutattentionPolicy.WorkflowRunRecordSchemaparses old runs withoutattentionPolicy.Built-in skill documentation checks
$workflow-authoringdescribes internal inferredattentionPolicybehavior for foreground/default workflow runs, background workflow runs, and workflow-owned conductor steps.$loopdescribes how to choose foreground/default execution vsrun_in_background: truebased on whether the next loop decision depends on the result.attentionPolicyorattention_policyfield in v1.silent_backgroundbehavior as available.Terminal notification store tests
promptKind/terminalOutcomerather than guessing from history.workspaceService.sendMessage()when the owner is streaming, queued, or preparing.Validation commands
Run after implementation:
Before declaring done, run the broader static gate if local resources allow:
If
make static-checkis too heavy or fails for known environmental reasons, record the exact blocker and the targeted passing checks.Dogfooding plan
Dogfooding must happen between implementation phases and before PR-ready claims. Collect screenshots and a short video so reviewers can verify behavior.
Setup
Use an isolated desktop sandbox so the test does not affect the developer's real Mux state:
If provider/project state should be clean:
MUX_E2E=1 make dev-desktop-sandbox DEV_DESKTOP_SANDBOX_ARGS="--clean-projects"Use
agent-browserfor interaction and evidence capture. At dogfood time, load current CLI instructions:Scenario 1 — Background sub-agent no longer forces active await
src/node/services/taskService.ts, then continue with a short acknowledgement.”MUST NOT end your turn/ activetask_awaitprompt.Evidence:
task_awaitturn appears.Scenario 2 — Terminal sub-agent wake-up integrates injected report
<mux_subagent_report>.task_awaitjust to retrieve an already-injected sub-agent report.Evidence:
chat.jsonlexcerpt showing a synthetic<mux_subagent_report>in parent history.Scenario 3 — Workspace-turn terminal wake-up retrieves output with
task_awaittask(kind="workspace", run_in_background=true)) that will produce a short final answer.wst_...handle runs.wst_...ID and instructstask_awaitwithtimeout_secs: 0.task_await, receives terminal output, and integrates it.Evidence:
wst_...andtimeout_secs: 0.Scenario 4 — Background workflow continues via existing workflow result path
task_awaitwhile the workflow is still running.Evidence:
Mobile/narrow-width visual check
If synthetic message copy or tool-card layout changes are visible in the renderer:
task_...,wst_...,wfr_...) wrap/truncate without right-edge overflow.Acceptance criteria
run_in_background: truesub-agent tasks do not trigger active force-await prompts at parent stream-end.run_in_background: trueworkspace-turn handles do not trigger active force-await prompts while running.run_in_background: truetop-level workflow runs do not trigger active force-await prompts while running.notify_on_terminal.task_awaitonnotify_on_terminalwork does not clear durable notify policy or re-promote the work to blocking.task_awaitunnecessarily.task_awaitandtimeout_secs: 0.blocking_until_terminal.agentId, model, thinking level) and synthetic send flags.workflow_resume({ run_in_background: true })retains/persists notify policy.$workflow-authoringand$loopare updated to document inferred internal attention policy cases and explicitly state the field is not directly settable in v1.silent_backgroundor a publicattentionPolicy/attention_policyargument.Risks and mitigations
blocking_until_terminal; only derive notify from explicitrun_in_backgroundor queued-message backgrounding.task_awaitincorrectly.task_awaitwith terminal IDs.attention_policyin first PR; derive from existingrun_in_background.Suggested implementation order
TerminalAttentionNotifier/ notification store and tests before wiring terminal sends to it.handleStreamEnd()active-work filtering to separate blocking and notify work.$workflow-authoring,$loop, and story copy to definerun_in_background: trueas non-blocking with terminal wake-up while keepingattentionPolicyinternal/not directly settable in v1.Advisor review log
run_in_background: truesemantics as non-blocking with terminal wake-up;markTaskForegroundRelevant()bookkeeping;workflow_resume({ run_in_background: true });TerminalAttentionNotifier/ persisted notification store seam;sendMessage()/ retry loops while holding TaskService settlement/event locks;task_awaitwithout duplicate wake-up.$workflow-authoringand$loopguidance. Amendment added:attentionPolicybehavior;attentionPolicy/attention_policyargument;Generated with
mux• Model:openai:gpt-5.5• Thinking:xhigh• Cost:$128.29