Skip to content

Conversation

@silvin-lubecki
Copy link
Contributor

@silvin-lubecki silvin-lubecki commented Jan 24, 2026

Summary

Add a tasks tool with dependency management and automatic persistence, inspired by Claude Code's task system. The existing todo tool remains unchanged for simple cases.

Features

Task Management with Dependencies

  • Struct Task: ID, Description, Status, BlockedBy, Blocks, Owner
  • Tools: create_task, create_tasks, update_tasks, list_tasks, add_task_dependency, remove_task_dependency, get_blocked_tasks
  • Enforcement: Cannot start a blocked task (status in-progress)
  • Cycle Detection: Prevents circular dependencies (direct and transitive)
  • Notifications: Informs when tasks become unblocked
  • Display: ✓ done, ■ in-progress, □ pending, ⚠ blocked + stats header

Always Shared, Always Persisted

  • All agents automatically share the same task list (singleton)
  • Tasks automatically persist to ~/.cagent/tasks/<id>.json
  • Git-aware: Task list ID auto-detected from git repo (shared across worktrees!)
  • Multiple worktrees of the same repo share the same task list for coordination
  • --task-list <id> flag or CAGENT_TASK_LIST_ID env var to override

TUI Support

  • Tasks panel in sidebar
  • Component: pkg/tui/components/tool/taskstool/
  • Shows blocker descriptions (not just IDs)

Tests

  • 35+ unit tests (pkg/tools/builtin/tasks_test.go)
  • 15+ persistence tests (pkg/tools/builtin/tasks_store_test.go)
    • Worktree sharing tests
    • Cross-repo isolation tests
    • Load error handling tests
  • Flag tests (cmd/root/flags_test.go)
  • Concurrency tests with -race flag
  • E2E configs: e2e/testdata/tasks_dependencies.yaml, e2e/testdata/shared_tasks.yaml

Usage

# Tasks auto-persist based on git repo (default)
cagent run agent.yaml

# Override with custom task list ID
cagent run agent.yaml --task-list my-project

# Or via env var
export CAGENT_TASK_LIST_ID="my-project"
cagent run agent.yaml

Example Config

# Single agent with tasks
version: "2"
agents:
  root:
    model: openai/gpt-4o
    toolsets:
      - type: tasks

# Multi-agent - tasks automatically shared
version: "2"
agents:
  coordinator:
    toolsets:
      - type: tasks
      - type: transfer_task
    sub_agents: [backend, frontend]
  backend:
    toolsets:
      - type: tasks
  frontend:
    toolsets:
      - type: tasks

Storage Format

~/.cagent/tasks/
├── cagent-a1b2c3d4.json      # Auto-detected from git repo
├── my-project.json           # Custom --task-list ID
└── other-repo-e5f6g7h8.json  # Another repo
{
  "version": 1,
  "tasks": [
    {
      "id": "task_1",
      "description": "Setup database",
      "status": "completed",
      "blocked_by": [],
      "blocks": ["task_2"],
      "owner": "backend-dev"
    }
  ]
}

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
@silvin-lubecki silvin-lubecki requested a review from a team as a code owner January 24, 2026 16:46
@silvin-lubecki silvin-lubecki changed the title Feature/tasks dependencies Tasks dependencies Jan 24, 2026
- 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
@silvin-lubecki silvin-lubecki marked this pull request as draft January 24, 2026 16:51
@silvin-lubecki silvin-lubecki changed the title Tasks dependencies feat: add tasks tool with dependencies and cross-session persistence Jan 25, 2026
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
@silvin-lubecki silvin-lubecki force-pushed the feature/tasks-dependencies branch from 861b914 to 7633b5d Compare January 25, 2026 18:08
- 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
@silvin-lubecki
Copy link
Contributor Author

/review

Copy link
Contributor

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

Review Summary

Found 4 high-severity concurrency bugs in shared tasks mode that could lead to data corruption:

  1. Race in ensureLoaded() - Multiple agents can load duplicate tasks from disk
  2. Race in task ID generation - Concurrent creates can generate duplicate task IDs
  3. 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.

@silvin-lubecki silvin-lubecki force-pushed the feature/tasks-dependencies branch from b043a2c to 69f5728 Compare January 26, 2026 09:59
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
@silvin-lubecki silvin-lubecki force-pushed the feature/tasks-dependencies branch from 69f5728 to 0be7092 Compare January 26, 2026 09:59
@silvin-lubecki
Copy link
Contributor Author

/review

Copy link
Contributor

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

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:

  1. Missing circular dependency validation in batch task creation
  2. Shared store singleton pattern that could cause confusion
  3. Silent persistence failures
  4. 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
@silvin-lubecki
Copy link
Contributor Author

/review

Copy link
Contributor

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

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
@silvin-lubecki
Copy link
Contributor Author

/review

Encourage the agent to use the tasks tool for complex multi-step work.

Assisted-By: cagent
Copy link
Contributor

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

Code Review Summary

Found 3 issues in the new tasks tool implementation that should be addressed:

Issues Found

  1. MEDIUM: Race condition in file writes due to non-unique temp filename
  2. MEDIUM: Empty/dot listID causes unintended file sharing
  3. 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
@silvin-lubecki silvin-lubecki force-pushed the feature/tasks-dependencies branch from 2bf00bf to e66f981 Compare January 26, 2026 14:33
@silvin-lubecki silvin-lubecki marked this pull request as ready for review January 26, 2026 14:42
@silvin-lubecki silvin-lubecki marked this pull request as draft January 26, 2026 14:47
@krissetto
Copy link
Contributor

btw i love seeing you try out the review bot <3

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.

3 participants