Conversation
Introduces a `Planning` capability (AbstractCapability subclass) that provides agents with `create_plan`, `update_task`, and `get_plan` tools for structured task management. Plan state is per-run isolated via `for_run()` and dynamically injected into the system prompt via `get_instructions()`. Closes #39, relates to #65. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… Planning Address audit findings from PR review: - Add `parent_index` field to Task and `add_subtask` tool for hierarchical plans - Add `insert_task` and `remove_task` tools for mid-plan adjustment - Add `TaskStatus.blocked` for dependency tracking - Subtasks display indented in format_plan; removing a parent cascades to subtasks - All parent_index references adjusted on insert/remove to stay consistent Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
| for removed_idx in sorted(indices_to_remove): | ||
| for task in tasks: | ||
| if task.parent_index is not None and task.parent_index > removed_idx: | ||
| task.parent_index -= 1 |
There was a problem hiding this comment.
🔴 remove_task_impl corrupts parent_index when cascading removal of multiple indices
When remove_task_impl removes a parent task along with its subtasks (multiple indices removed at once), the parent_index adjustment loop on lines 206-209 produces incorrect results. The loop iterates through removed indices in ascending order, decrementing parent_index values above each removed_idx. However, after decrementing for the first removed_idx, the parent_index values are partially shifted, while subsequent removed_idx values remain in the original coordinate system. This causes comparisons like task.parent_index > removed_idx to fail prematurely.
Reproducer showing corrupted parent reference
tasks = [
Task(description='A'), # 0
Task(description='A-child', parent_index=0), # 1
Task(description='B'), # 2
Task(description='B-child', parent_index=2), # 3
]
remove_task_impl(tasks, 0)
# Expected: [B(parent=None), B-child(parent_index=0)]
# Actual: [B(parent=None), B-child(parent_index=1)] ← WRONGB-child ends up pointing to index 1 (out of bounds), but B is at index 0. For a parent_index that was originally N, the code should subtract the count of removed indices below N, but the incremental approach only subtracts count - 1 because the last comparison fails.
| for removed_idx in sorted(indices_to_remove): | |
| for task in tasks: | |
| if task.parent_index is not None and task.parent_index > removed_idx: | |
| task.parent_index -= 1 | |
| for task in tasks: | |
| if task.parent_index is not None: | |
| shift = sum(1 for ri in indices_to_remove if ri < task.parent_index) | |
| task.parent_index -= shift |
Was this helpful? React with 👍 or 👎 to provide feedback.
Audit vs prior art: PlanningWorth adding now:
Follow-up opportunities:
|
Summary
Planningcapability (AbstractCapabilitysubclass) providingcreate_plan,update_task, andget_plantools for structured task planning and trackingfor_run()and dynamically injected into the system prompt viaget_instructions()pending,in_progress,completed,skippedCloses #39, relates to #65.
Test plan
🤖 Generated with Claude Code