Completed tasks are silently deleted from persistent CLAUDE_CODE_TASK_LIST_ID task lists

Status Open
Reported on v2.1.211
Maintainer reply None cached
Activity 0 comments · opened Jul 16, 2026

Summary

Claude Code intentionally garbage-collects completed tasks ("Completed background agents now stay listed in /tasks until cleanup" — v2.1.208 changelog), but this cleanup also deletes completed tasks from persistent, named CLAUDE_CODE_TASK_LIST_ID lists, silently and with an undocumented trigger. For cross-session workflows the completed records are the deliverable (validation/review steps read them), so this is silent data loss: every TaskCreate/TaskUpdate returns success, TaskList shows the board, then the files are deleted with no error surfaced to the model or user.

Environment

  • Claude Code 2.1.211, macOS (Darwin 25.5.0), APFS, local ~/.claude/tasks
  • Persistent list bound via CLAUDE_CODE_TASK_LIST_ID in .claude/settings.local.json

Observed behavior (from a real incident, decoded from the session transcript)

An interactive session created 10 tasks over ~2h in ~/.claude/tasks/<list-id>/. Timeline (UTC):

  • 01:52–01:54 — tasks 1–4 created (with blockedBy edges)
  • 02:05–02:51 — tasks executed and marked completed one by one; a completed task survived 46+ minutes at this stage (TaskList at 02:51:10 shows all 4 completed tasks present)
  • 02:52–03:07 — tasks 1–4's N.json files deleted from disk
  • 03:07:14 — task 5 marked completed; TaskList at 03:07:16 shows only task 5; TaskList at 03:07:48 shows "No tasks found" (deleted within 34s of completing; no subagent, no user turn, no compaction between the two TaskLists)
  • 03:08–03:09 — model re-creates all 5 tasks (ids 6–10), marking each completed; all deleted again within seconds; .highwatermark stamped "10" at deletion time

Deletion fingerprint: every N.json for a completed task is removed; pending/in_progress tasks survive; .lock survives; .highwatermark survives and its mtime matches the deletion (it is written by the cleanup path).

A second flavor: after ~13 sessions started simultaneously (terminal-multiplexer workspace reopen), four different persistent lists — each containing only completed tasks (3, 26, 3, 24 tasks) — went to 0 files within a 2-second window, ~60–70s after session start.

Controlled experiments

  • Writes are debounced/async: TaskCreate returned success up to 51s before the file appeared on disk — so failures/cleanups can never surface to the tool call.
  • Headless -p sessions never trigger the cleanup (5 attempts: idle sessions, all-completed boards, owner-tagged tasks, subagent-adjacent completion). The cleanup only occurred in long interactive sessions and shortly after session start/resume on all-completed boards.
  • Two live sessions sharing one list id write cleanly (correct id allocation, no cross-deletion) — plain concurrency is not the cause.

Expected behavior

One or more of:

  1. Named (non-session-scoped) task lists opt out of completed-task cleanup — persistence is their purpose.
  2. The cleanup trigger and retention policy are documented and configurable.
  3. Cleanup is surfaced to the model (e.g., TaskList indicating "N completed tasks archived") instead of silently deleting files that TaskCreate/TaskUpdate just confirmed.

Related (not duplicates)

  • v2.1.208 changelog ("stay listed in /tasks until cleanup") — confirms intentional cleanup, trigger undocumented
  • #51779 (cleanupPeriodDays covers ~/.claude/tasks — 30-day age-based; too slow to explain this)
  • #25298 (tasks not surfacing after compaction — different direction)
  • #59962 (task lifecycle state sync)

A second, separable issue found in the same investigation: an ancestor project's .claude/settings.local.json env overrides both a nested worktree's own settings.local.json and the explicit process environment for CLAUDE_CODE_TASK_LIST_ID, silently rebinding worktree sessions to the parent's shared list. Happy to file separately if useful.

View original on GitHub ↗