-
Notifications
You must be signed in to change notification settings - Fork 227
feat: add tasks tool with dependencies and cross-session persistence #1492
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
feat: add tasks tool with dependencies and cross-session persistence #1492
Conversation
Add a new 'tasks' toolset separate from 'todo' that provides
dependency-aware task management inspired by Claude Code's task system:
Features:
- BlockedBy/Blocks relationships between tasks
- Automatic enforcement: cannot start blocked tasks
- Visual indicators: ✓=done, ■=in-progress, □=pending, ⚠=blocked
- Owner assignment for tasks
- Circular dependency detection
- Unblock notifications when dependencies complete
New tools:
- create_task: Create task with optional blocked_by and owner
- create_tasks: Batch create tasks with dependencies
- update_tasks: Update status with dependency enforcement
- list_tasks: List with stats and blocked indicators
- add_task_dependency: Add blockers to existing task
- remove_task_dependency: Remove blockers
- get_blocked_tasks: Query blocked tasks
Usage in config:
toolsets:
- type: tasks
shared: true # Optional: share across agents
The original 'todo' tool remains unchanged for simple use cases.
Assisted-By: cagent
Unit tests (tasks_test.go): - Test task creation with/without dependencies - Test canStart logic for blocked tasks - Test update enforcement (cannot start blocked) - Test completion unblocking dependents - Test list_tasks output with visual indicators - Test add/remove dependencies - Test circular dependency detection - Test shared instance behavior - Test cross-agent sharing simulation TUI components: - Add taskstool package with sidebar component - Display tasks with dependency indicators in sidebar - Show stats: X done · Y active · Z pending · W blocked - Visual icons: ✓ □ ■ ⚠ - Owner display and blocked-by indicators - Update sidebar to render both todos and tasks E2E test configs: - tasks_dependencies.yaml: single agent with tasks - shared_tasks.yaml: multi-agent with shared tasks Assisted-By: cagent
Replace todo with tasks to leverage dependency management for more structured development workflows. Assisted-By: cagent
- Fix gci import formatting in tasks.go - Combine append calls in taskstool/sidebar.go (gocritic) - Use integer range syntax for loop (intrange) Assisted-By: cagent
Assisted-By: cagent
Add file-based persistence for tasks with --task-list flag or CAGENT_TASK_LIST_ID env var. Tasks are stored in ~/.cagent/tasks/<id>.json. - Add TaskStore interface with FileTaskStore and MemoryTaskStore - Add GetTasksDir() to paths package - Add TaskListID to RuntimeConfig - Add --task-list flag and CAGENT_TASK_LIST_ID env var support - Lazy loading: tasks loaded on first access - Atomic writes with temp file + rename Without --task-list flag, tasks remain in-memory only (no persistence). Assisted-By: cagent
861b914 to
7633b5d
Compare
- Remove MemoryTaskStore usage, always use FileTaskStore - Auto-detect task list ID from git common dir (shared across worktrees) - Format: <dirname>-<short-hash> (e.g., 'cagent-a1b2c3d4') - Enables coordination across worktrees of the same repo - --task-list flag still overrides auto-detection if needed - shared: true now also persists (uses same store) Assisted-By: cagent
- TestDefaultTaskListID_Worktrees: verify same ID across main repo and worktree - TestDefaultTaskListID_DifferentRepos: verify different IDs for different repos - TestDefaultTaskListID_NotGitRepo: verify fallback to directory name - Fix symlink resolution for macOS (/tmp -> /private/tmp) Assisted-By: cagent
- Add tasks tool section to USAGE.md with features, tools, and examples - Update tool Instructions() to mention persistence and git-aware sharing - Add tasks to the toolsets configuration example Assisted-By: cagent
|
/review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review Summary
Found 4 high-severity concurrency bugs in shared tasks mode that could lead to data corruption:
- Race in ensureLoaded() - Multiple agents can load duplicate tasks from disk
- Race in task ID generation - Concurrent creates can generate duplicate task IDs
- Race in Clear operation - Newly created tasks can be incorrectly deleted
Also found several medium/low severity issues with TOCTOU patterns and eventual consistency concerns.
Root cause: The tasksHandler struct lacks synchronization at the handler level. While concurrent.Slice provides thread-safe operations, compound operations (check-then-act, read-compute-write) are not atomic.
Recommendation: Add a handler-level mutex (sync.RWMutex) to protect compound operations in shared mode, or document that shared mode is not thread-safe.
b043a2c to
69f5728
Compare
Add sync.RWMutex to tasksHandler to protect compound operations in shared mode. This fixes several concurrency bugs: 1. Race in ensureLoaded() - multiple agents loading duplicate tasks 2. Race in task ID generation - concurrent creates generating duplicates 3. Race in Clear operation - newly created tasks incorrectly deleted Use sync.Once for ensureLoaded() to allow read operations (listTasks, getBlockedTasks) to use RLock() for better concurrency, while write operations use Lock(). Added concurrent tests with -race flag to verify the fix. Assisted-By: cagent
69f5728 to
0be7092
Compare
|
/review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review Summary
Found 4 confirmed issues in the changed code:
- 2 HIGH severity bugs requiring fixes
- 1 MEDIUM severity issue worth addressing
- 1 LOW severity issue to consider
The major concerns are:
- Missing circular dependency validation in batch task creation
- Shared store singleton pattern that could cause confusion
- Silent persistence failures
- Task ID reuse after clearing completed tasks
Please review the inline comments for details.
…warnings - Add validation for self-dependency and ordering in createTasks batch - Tasks can only depend on earlier tasks in the same batch - save() now returns warning message appended to output on failure - Document NewSharedTasksToolWithStore singleton behavior - Add tests for circular/self/mutual dependencies in batch Assisted-By: cagent
|
/review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review Summary
Found 1 high-severity bug in the task persistence layer that could lead to data loss.
Critical Issue
- Data Loss Risk: Silent load failures can permanently overwrite existing task data
Analysis Details
Reviewed the new tasks tool implementation focusing on:
- ✅ Concurrent access patterns (mutexes correctly used)
- ✅ Circular dependency detection (comprehensive)
- ✅ File I/O atomicity (temp file + rename pattern)
- ❌ Error handling in lazy loading (found critical bug)
- ✅ Shared instance management (working as designed)
- ✅ Batch task validation (ordering constraints prevent cycles)
The identified bug occurs when task loading fails but operations continue with empty state, potentially overwriting existing data.
ensureLoaded() now captures and returns the load error. All handlers check this error and refuse to operate on empty state, preventing accidental overwrite of corrupted files. Added test: TestTasksToolWithStore_LoadError Assisted-By: cagent
|
/review |
Encourage the agent to use the tasks tool for complex multi-step work. Assisted-By: cagent
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review Summary
Found 3 issues in the new tasks tool implementation that should be addressed:
Issues Found
- MEDIUM: Race condition in file writes due to non-unique temp filename
- MEDIUM: Empty/dot listID causes unintended file sharing
- LOW: Git symlink resolution order may break worktree ID consistency
The core functionality looks solid with good test coverage. The issues are edge cases that could cause data corruption in multi-process scenarios or with unusual configurations.
…tence Breaking changes: - Remove MemoryTaskStore (no longer needed) - Remove shared option from tasks toolset (always shared now) - Remove NewSharedTasksTool, NewSharedTasksToolWithStore, NewTasksToolWithStore (use NewTasksTool) Improvements: - NewTasksTool() returns singleton instance - SetTaskListID() allows CLI override before first use - NewFileTaskStore uses option pattern (WithBaseDir) instead of separate constructor - Factored addBlockerLink/removeBlockerLink helpers - Consistent use of findTask() method - noopTaskStore for unit tests avoids singleton interference Tasks are now: - Always persisted to ~/.cagent/tasks/<repo-id>.json - Always shared across all agents in the same process - Auto-detected from git repo (shared across worktrees) Assisted-By: cagent
- Update Instructions() to mention all agents share the same task list - Update USAGE.md to remove shared option examples - Add 'Always shared' to features list - Update PR description Assisted-By: cagent
…stry - Remove global singleton pattern from tasks.go - NewTasksTool(store) now takes store as parameter (pure function) - ToolsetRegistry holds shared instance via GetOrCreateTasksTool() - Sharing happens at registry level, not via global state - Better testability: each test can create isolated instances Assisted-By: cagent
1. Race condition in atomic write: use unique temp filename with PID and nanosecond timestamp to prevent corruption when multiple processes write simultaneously 2. Empty/dot listID validation: filePath() now handles empty, '.', and '..' values by falling back to 'default' 3. Git symlink resolution: check for .git basename BEFORE resolving symlinks to handle cases where .git is symlinked to a different path Added TestFileTaskStore_EmptyListID test. Assisted-By: cagent
- Add recover() in goroutine to handle panics when ResponseWriter becomes invalid after client disconnect - Check context before starting new goroutines - Add type assertion with fallback for writers without ReaderFrom Assisted-By: cagent
2bf00bf to
e66f981
Compare
|
btw i love seeing you try out the review bot <3 |
Summary
Add a tasks tool with dependency management and automatic persistence, inspired by Claude Code's task system. The existing
todotool remains unchanged for simple cases.Features
Task Management with Dependencies
create_task,create_tasks,update_tasks,list_tasks,add_task_dependency,remove_task_dependency,get_blocked_tasksin-progress)Always Shared, Always Persisted
~/.cagent/tasks/<id>.json--task-list <id>flag orCAGENT_TASK_LIST_IDenv var to overrideTUI Support
pkg/tui/components/tool/taskstool/Tests
pkg/tools/builtin/tasks_test.go)pkg/tools/builtin/tasks_store_test.go)cmd/root/flags_test.go)-raceflage2e/testdata/tasks_dependencies.yaml,e2e/testdata/shared_tasks.yamlUsage
Example Config
Storage Format
{ "version": 1, "tasks": [ { "id": "task_1", "description": "Setup database", "status": "completed", "blocked_by": [], "blocks": ["task_2"], "owner": "backend-dev" } ] }