Skip to content

fix: make TodoItemSchema tolerant of Claude's TodoWrite payload#502

Open
GeT-LeFt wants to merge 1 commit intotiann:mainfrom
GeT-LeFt:fix/todo-schema-optional-fields
Open

fix: make TodoItemSchema tolerant of Claude's TodoWrite payload#502
GeT-LeFt wants to merge 1 commit intotiann:mainfrom
GeT-LeFt:fix/todo-schema-optional-fields

Conversation

@GeT-LeFt
Copy link
Copy Markdown

Problem

Claude's TodoWrite tool sends todo items as:

{ "content": "Fix the bug", "status": "in_progress", "activeForm": "Fixing the bug" }

But TodoItemSchema requires priority and id as mandatory fields:

export const TodoItemSchema = z.object({
    content: z.string(),
    status: z.enum(['pending', 'in_progress', 'completed']),
    priority: z.enum(['high', 'medium', 'low']),  // ← required
    id: z.string()                                 // ← required
})

This causes TodosSchema.safeParse() to return { success: false } in all three extraction paths (extractTodosFromClaudeOutput, extractTodosFromCodexMessage, extractTodosFromAcpMessage), so session.todos is never populated and the web UI todo panel stays permanently empty.

Solution

Make priority and id optional with sensible defaults, and add activeForm as an optional field:

export const TodoItemSchema = z.object({
    content: z.string(),
    status: z.enum(['pending', 'in_progress', 'completed']),
    priority: z.enum(['high', 'medium', 'low']).optional().default('medium'),
    id: z.string().optional().default(''),
    activeForm: z.string().optional()
})

Backwards-compatible: existing data with all fields present still parses correctly (Zod defaults only apply when the field is missing).

Changes

File Change
shared/src/schemas.ts Make priority and id optional with defaults, add activeForm

Fixes #501

Claude's TodoWrite tool sends {content, status, activeForm} without
priority or id fields. The strict schema causes safeParse() to fail
silently, so session.todos is never populated and the web UI todo
panel stays empty.

- Make priority optional with default 'medium'
- Make id optional with default '' (empty string)
- Add activeForm as optional field (used by Claude for in-progress labels)

Backwards-compatible: existing data with all fields still parses correctly.

Fixes tiann#501
Copy link
Copy Markdown

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Findings

  • No high-confidence issues found in the added/modified lines.

Summary

  • Review mode: initial
  • No issues found in shared/src/schemas.ts:90. Residual risk: this fixes the parsing mismatch, but I did not find automated coverage in repo/docs for TodoWrite payloads that omit priority/id or include activeForm, so a regression here could slip through silently.

Testing

  • Not run (automation)

HAPI Bot

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.

[Bug] TodoWrite todos not displayed: TodoItemSchema requires fields that Claude doesn't send

1 participant