Skip to content

fix(claude): map TodoWrite updates to plan events#1387

Open
samjandris wants to merge 4 commits intopingdotgg:mainfrom
samjandris:claude-plan-steps
Open

fix(claude): map TodoWrite updates to plan events#1387
samjandris wants to merge 4 commits intopingdotgg:mainfrom
samjandris:claude-plan-steps

Conversation

@samjandris
Copy link

@samjandris samjandris commented Mar 24, 2026

What Changed

Maps successful Claude TodoWrite results to turn.plan.updated events so Claude todo updates flow through the existing plan event path.

Validated with bun fmt, bun lint, and bun typecheck.

Why

Without this mapping, successful Claude TodoWrite updates do not flow through the existing plan event path, which can leave plan todos missing.

UI Changes

Shows how TodoWrite was previously ignored by the plan sidebar panel vs now.

Before:

Before

After:

After

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Medium Risk
Changes how Claude tool results are classified and which runtime events are emitted, which may affect downstream UI/ingestion that previously relied on item.updated/content.delta for these tool calls.

Overview
TodoWrite tool calls are now treated as plan updates. ClaudeAdapter classifies tools whose name contains todowrite (case-insensitive) as plan items.

On successful todowrite tool_result messages, the adapter emits a turn.plan.updated event built from tool.input.todos (normalizing statuses), and skips the usual item.updated/content.delta emissions for that result while still emitting the final item.completed.

Adds a regression test ensuring turn.plan.updated is emitted for todowrite regardless of tool name casing.

Written by Cursor Bugbot for commit 606fbe6. This will update automatically on new commits. Configure here.

Note

Map TodoWrite tool results to turn.plan.updated events in ClaudeAdapter

  • classifyToolItemType in ClaudeAdapter.ts now returns 'plan' for any tool whose normalized name includes 'todowrite'.
  • When a successful todowrite tool result is received, the adapter emits a turn.plan.updated event built from tool.input.todos, mapping each item to a {step, status} pair with status normalized to completed, inProgress, or pending.
  • The subsequent item.completed emission is preserved; the prior item.updated/content.delta sequence is skipped for todowrite tools.
  • Behavioral Change: todowrite tool results no longer emit item.updated or content.delta events.

Macroscope summarized 606fbe6.

@coderabbitai
Copy link

coderabbitai bot commented Mar 24, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d13020a6-6ccf-4850-9bd5-c63458d07c95

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

- Classify TodoWrite tool calls as plan items
- Emit turn.plan.updated events from successful TodoWrite results
- Emit plan updates for TodoWrite tool results regardless of casing
- Add coverage for lowercase todowrite tool events
- Treat any tool name containing `todowrite` as a completed todo-write action
- Preserve turn state updates for renamed Claude tool variants
- Treat `todowrite` as a normal tool call instead of a plan item
- Update the Claude adapter test expectations accordingly
Copy link
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

method: "claude/user",
payload: message,
},
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TodoWrite tools misclassified as file_change in lifecycle events

Medium Severity

The new code emits turn.plan.updated for todowrite tools, but classifyToolItemType still classifies "todowrite" as "file_change" because the name contains "write" (matching at line 422). This means the item.started and item.completed lifecycle events report itemType: "file_change" and title: "File change" for what is actually a plan/todo tool. A check for "todowrite" returning "plan" needs to be added to classifyToolItemType before the "write" check so the full item lifecycle is consistent with the new plan event.

Additional Locations (1)
Fix in Cursor Fix in Web

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This review is valid. TodoWrite already emits turn.plan.updated, but its lifecycle events are still classified as file_change. So, the work log currently shows both a file_change tool event and a separate Plan updated event for the same action.

I can fix that if desired, though it slightly widens the scope because it affects lifecycle classification and not just event emission. If so, should TodoWrite still appear as its own tool event, or should we only show Plan updated?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant