Desktop app renders Task* tool calls as an empty, non-expandable "Updated tasks" row (schema mismatch with the TodoWrite renderer)

Status Fixed / completed
Reported on v2.1.227
Maintainer reply None cached
Activity 0 comments · opened Aug 13, 2026 · closed Aug 18, 2026

Summary

In the Claude desktop app, when the model calls TaskCreate / TaskUpdate, the transcript shows a bare grey row reading "Updated tasks" with no task name, no detail body, and no way to expand it — clicking does nothing.

The cause is a schema mismatch: the inline tool-row renderer routes the Task* tool family to the display kind built for the older TodoWrite tool, but the extraction function reads input.todos[] with a content field, while the Task* tools send {subject, description, activeForm, status}. The extractor returns an empty array, so the body renders null and the row's expand affordance is switched off.

Net effect: on the desktop app, everything the model puts into a task — subject and description — is written to disk but never displayed anywhere in the UI, at any point, live or after the fact.

Steps to reproduce

  1. Open a session in the Claude desktop app (not the CLI).
  2. Give it a multi-part request so it creates a task list, e.g. "here are four things I need done today: …".
  3. Observe the tool rows in the transcript.

Actual: one or more rows labelled "Updated tasks". No subject, no description, no status. The rows are inert — clicking does not expand them.

Expected: either the task list rendered inline (as TodoWrite items are), or at minimum the task subject on the collapsed row and an expandable body with the description.

The data is present and correct the whole time — it is written to ~/.claude/tasks/<session-id>/<n>.json, one file per task, rewritten on every TaskUpdate:

{
  "id": "1",
  "subject": "Surgical resume fix — close-date the desk role",
  "description": "Change 'Mar 2026 – Present' to 'Mar 2026 – Jul 2026' across three files. Rebuild PDFs via build.sh. Verify with a pdftotext reading-order check. No redesign.",
  "activeForm": "Fixing resume dates and rebuilding PDFs",
  "status": "completed",
  "blocks": [],
  "blockedBy": []
}

Only the UI drops it.

Root cause

From the renderer bundle (Claude.app/Contents/Resources/ion-dist/assets/v1/*.js — minified; the hashed filename and identifiers will differ per build).

1. The Task* family is mapped to the todos display kind:

case"TodoWrite":case"TaskCreate":case"TaskUpdate":case"TaskGet":
case"TaskList":case"TaskStop":return"todos";

2. The todos renderer extracts its list via a TodoWrite-shaped reader:

if("todos"===t.kind){
  const t=r6(e.input);
  return t.length>0?(...jsx(i6,{todos:t})):null
}
function r6(e){
  const t=Array.isArray(e.todos)?e.todos:[],n=[];
  for(const s of t){
    if("string"!=typeof s.id||"string"!=typeof s.content)continue;
    ...
  }
  return n
}

r6 requires input.todos[] with .id and .content on each item. TaskCreate sends no todos array at all, and its text lives in subject / description, not content. So r6 returns [] and the body renders null.

3. The empty extraction also disables the expand affordance, which is why the row can't be clicked:

F=!("todos"===i.kind&&0===r6(e.input).length||"agent_status"===...||"peerMessage"===...)
D=()=>{ ...; if(d||!F)return; const t=!(u??c); Fv({kind:i.kind,expanded:t}); f(t) }

With F === false, the click handler early-returns. The row is not collapsed-but-openable; it is inert.

4. Secondary — the collapsed label can't show the task name either. TaskCreate, TaskUpdate and TaskStop share one verb entry with no meta field:

case"TaskCreate":case"TaskUpdate":case"TaskStop":
  return{verb:"Updated tasks",runningVerb:"Updating tasks",failedVerb:"Failed to update tasks",kind:o};

Compare create_session in the same switch, which passes meta:r("title") and does surface its title inline. Adding meta from subject would make the row useful even without a body.

Suggested fix

Either:

  • (a) Teach the extractor the Task* shape — map subjectcontent (and fall back to description), keyed on the tool name; or
  • (b) Give the Task* family its own display kind with a renderer that shows subject, status, and description.

Adding meta from subject to the TaskCreate/TaskUpdate verb entry is a worthwhile independent improvement — it fixes the anonymous-row problem even before the body renders.

Note that fixing the extractor also restores click-to-expand for free, since F is derived from the same call.

Impact

Desktop-app users get no visibility into the task list at all — not live, not on scrollback. Since the model is prompted to use these tools proactively for multi-step work, this is the primary progress-tracking surface, and on the desktop app it renders as a row of anonymous grey placeholders.

Current workarounds, neither good:

  1. Ask mid-session "show me the task list" — this works only because the model relays the result as ordinary assistant text; the TaskList tool row itself renders blank for the same reason.
  2. Read ~/.claude/tasks/<session-id>/*.json directly.

Related

  • #57019 — feature request to surface TodoWrite items in the desktop Tasks panel. Related but distinct: that asks for a new surface; this is a bug in the existing inline transcript renderer, where the row already exists and silently drops its content.

Environment

  • Claude desktop app 1.28929.0 (macOS, arm64)
  • Bundled claude-code 2.1.227
  • macOS 26.5 (25F71), Apple silicon

View original on GitHub ↗