Background-task chips outlive the id needed to dismiss them
Background-task chips outlive the id needed to dismiss them
Summary
spawn_task returns a task_id that is the only handle for withdrawing the
chip it creates. That id lives in memory and is dropped on app restart, but the
chip itself persists in the UI. After a restart the chip is therefore
permanently un-withdrawable by the agent: the id it was given no longer
resolves, and there is no way to discover the new one.
The chip is left claiming work that may since have been completed, and only the
user can clear it.
Steps to reproduce
- In a session, call
mcp__ccd_session__spawn_task. Note the returned
task_id (e.g. task_932e1ded). A chip appears.
- Leave the chip unactioned — neither started nor dismissed.
- Restart the app. Resume/continue the same session.
- Do the work the chip describes, so the suggestion is now stale.
- Call
mcp__ccd_session__dismiss_taskwith the originaltask_id.
Expected
The chip is withdrawn — the documented purpose of dismiss_task, whose
description says to call it "if this suggestion later becomes stale."
Actual
No pending task with id task_932e1ded. Task ids are not persisted across app
restarts, so a chip from before a restart can no longer be withdrawn.
Nothing was changed.
The chip stays on screen. Clicking start on it would spin up a fresh session
to do work that is already merged.
Why there is no workaround
Every route to the live id is closed:
- No enumeration. The
ccd_sessionserver exposesspawn_task,
dismiss_task, mark_chapter and read_widget_context — nothing that lists
pending tasks or maps a chip to its current id.
- No widget context.
read_widget_context({tool_name: "spawn_task"})
returns No widget context available for tool 'spawn_task'.
- No stable key. Dismissal accepts only
task_id; there is no way to
address a chip by title, by the prompt it carries, or by session.
So the failure is terminal rather than inconvenient: an agent that correctly
follows the tool's own guidance to retire a stale suggestion cannot do so.
Impact
Low severity, but it degrades exactly the workflow the feature is for. The
intended loop is *flag an out-of-scope issue → later do it → withdraw the
chip.* Any restart between the first and last step breaks the loop and leaves
misleading state, and long-running sessions are precisely where a flagged issue
is most likely to be picked up later.
The mismatch is that chip lifetime and id lifetime differ. Anything that made
them agree would fix it:
- persist task ids alongside the chips they address; or
- reconcile on restart — drop chips whose ids did not survive; or
- accept a stable secondary key (session id + title) in
dismiss_task; or - expose a
list_tasksso an agent can re-discover the live id.
Observed in
Claude Code (desktop), ccd_session MCP server. Reproduced 2026-08-07 in a
session where a chip filed early in the work became stale once the fix shipped;
the chip could not be withdrawn and had to be cleared by hand.