Skip to content

Add Planning capability#180

Draft
DouweM wants to merge 2 commits intomainfrom
capability/planning
Draft

Add Planning capability#180
DouweM wants to merge 2 commits intomainfrom
capability/planning

Conversation

@DouweM
Copy link
Copy Markdown
Contributor

@DouweM DouweM commented Apr 10, 2026

Summary

  • Adds a Planning capability (AbstractCapability subclass) providing create_plan, update_task, and get_plan tools for structured task planning and tracking
  • Plan state is per-run isolated via for_run() and dynamically injected into the system prompt via get_instructions()
  • Task statuses: pending, in_progress, completed, skipped

Closes #39, relates to #65.

Test plan

  • 32 tests covering all public API, tool logic, per-run isolation, dynamic instructions, edge cases (empty plan, invalid index, negative index)
  • 100% branch coverage
  • ruff lint and format clean
  • pyright strict mode clean

🤖 Generated with Claude Code

DouweM and others added 2 commits April 2, 2026 05:28
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>
Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 3 additional findings in Devin Review.

Open in Devin Review

Comment on lines +206 to +209
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
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 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)]  ← WRONG

B-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.

Suggested change
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
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@DouweM
Copy link
Copy Markdown
Contributor Author

DouweM commented Apr 10, 2026

Originally posted by @DouweM in #136 comment (PR was recreated)

Audit vs prior art: Planning

Worth adding now:

  • Hierarchical subtasks: parent_index on Task + add_subtask tool (VStorm pydantic-ai-todo)
  • insert_task and remove_task tools for mid-plan adjustment
  • blocked status for dependency tracking

Follow-up opportunities:

  • Persistent plans (file/DB), dependency graph, time estimates

@DouweM DouweM marked this pull request as draft April 10, 2026 15:12
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.

Planning capability (periodic reasoning/reflection steps)

1 participant