Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 168 additions & 0 deletions docs/TASK_MANAGEMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# Task Management in multiclaude

## Overview

multiclaude agents can leverage Claude Code's built-in task management tools to track complex, multi-step work. This document explains how these tools work and when to use them.

## Claude Code's Task Management Tools

Claude Code provides four task management tools available to all agents:

### TaskCreate
Creates a new task in the task list.

**When to use:**
- Complex multi-step tasks requiring 3+ distinct steps
- Non-trivial operations that benefit from progress tracking
- User provides multiple tasks in a list
- You want to demonstrate thoroughness and organization

**When NOT to use:**
- Single, straightforward tasks
- Trivial operations (1-2 steps)
- Tasks completable in <3 steps
- Purely conversational or informational work

**Example:**
```
TaskCreate({
subject: "Fix authentication bug in login flow",
description: "Investigate and fix the issue where users can't log in with OAuth. Need to check middleware, token validation, and error handling.",
activeForm: "Fixing authentication bug"
})
```

### TaskUpdate
Updates an existing task's status, owner, or details.

**Status workflow:** `pending` → `in_progress` → `completed`

**When to use:**
- Mark task as `in_progress` when starting work
- Mark task as `completed` when finished
- Update task details as requirements clarify
- Establish dependencies between tasks

**IMPORTANT:** Only mark tasks as `completed` when FULLY done. If you encounter errors, blockers, or partial completion, keep status as `in_progress`.

### TaskList
Lists all tasks with their current status, owner, and blockedBy dependencies.

**When to use:**
- Check what tasks are available to work on
- See overall progress on a project
- Find tasks that are blocked
- After completing a task, to find next work

### TaskGet
Retrieves full details of a specific task by ID.

**When to use:**
- Before starting work on an assigned task
- To understand task dependencies
- To get complete requirements and context

## Task Management vs Task Tool

**Task Management (TaskCreate/Update/List/Get):**
- Tracks progress on multi-step work within a single agent session
- Creates todo-style checklists visible to users
- Helps organize complex workflows
- Persists within the conversation context

**Task Tool (spawning sub-agents):**
- Delegates work to parallel sub-agents
- Enables concurrent execution of independent operations
- multiclaude already does this at the orchestration level with workers!

## Best Practices for multiclaude Agents

### For Worker Agents

**Use task management when:**
- Your assigned task has multiple logical steps (e.g., "Implement authentication: add middleware, update routes, write tests")
- You want to show progress on a complex feature
- The user asks you to track progress explicitly

**Don't overuse:**
- For simple bug fixes or single-file changes
- When you're just doing research/exploration
- For trivial operations

**Example workflow:**
```bash
# Starting a complex task
TaskCreate({
subject: "Add user authentication endpoint",
description: "Create /api/auth endpoint with JWT validation, rate limiting, and tests",
activeForm: "Adding authentication endpoint"
})

# Start work
TaskUpdate({ taskId: "1", status: "in_progress" })

# ... do the work ...

# Complete when done
TaskUpdate({ taskId: "1", status: "completed" })
```

### For Supervisor Agent

**Use task management for:**
- Tracking multiple workers' overall progress
- Coordinating complex multi-worker efforts
- Breaking down large features into assignable chunks

**Pattern for supervision:**
1. Create high-level tasks for major work items
2. Assign tasks to workers (use task metadata to track which worker owns what)
3. Update task status as workers report completion
4. Use TaskList to monitor overall progress

### For Merge Queue Agent

**Use task management for:**
- Tracking PRs through the merge process
- Managing multiple PR reviews/merges concurrently
- Organizing complex merge conflict resolutions

## Task Management and PR Creation

**IMPORTANT:** Task management is for tracking work, NOT for delaying PRs.

- Create tasks to organize your work into logical blocks
- When a block (task) is complete and tests pass, create a PR immediately
- Don't wait for all tasks to be complete before creating PRs
- Each completed task should generally result in a focused PR

**Good pattern:**
```
Task 1: "Add validation function" → Complete → Create PR #1
Task 2: "Wire validation into API" → Complete → Create PR #2
Task 3: "Add error handling" → Complete → Create PR #3
```

**Bad pattern:**
```
Task 1: "Complete validation system"
- Subtask: Add function
- Subtask: Wire into API
- Subtask: Add error handling
→ Wait for ALL to complete → Create massive PR
```

## Checking if Task Management is Available

multiclaude automatically detects task management capabilities during daemon startup. Agents can assume these tools are available if running Claude Code v2.0+.

To check manually:
```bash
multiclaude diagnostics --json | jq '.capabilities.task_management'
```

## Related Documentation

- [Claude Agent SDK - Todo Tracking](https://platform.claude.com/docs/en/agent-sdk/todo-tracking) - Official documentation
- [AGENTS.md](AGENTS.md) - multiclaude agent architecture
- [CLAUDE.md](CLAUDE.md) - Development guide for multiclaude itself
41 changes: 41 additions & 0 deletions internal/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/dlorenc/multiclaude/internal/agents"
"github.com/dlorenc/multiclaude/internal/bugreport"
"github.com/dlorenc/multiclaude/internal/daemon"
"github.com/dlorenc/multiclaude/internal/diagnostics"
"github.com/dlorenc/multiclaude/internal/errors"
"github.com/dlorenc/multiclaude/internal/fork"
"github.com/dlorenc/multiclaude/internal/format"
Expand Down Expand Up @@ -720,6 +721,14 @@ func (c *CLI) registerCommands() {
Run: c.bugReport,
}

// Diagnostics command
c.rootCmd.Subcommands["diagnostics"] = &Command{
Name: "diagnostics",
Description: "Show system diagnostics in machine-readable format",
Usage: "multiclaude diagnostics [--json] [--output <file>]",
Run: c.diagnostics,
}

// Version command
c.rootCmd.Subcommands["version"] = &Command{
Name: "version",
Expand Down Expand Up @@ -5939,6 +5948,38 @@ func (c *CLI) bugReport(args []string) error {
return nil
}

// diagnostics generates system diagnostics in machine-readable format
func (c *CLI) diagnostics(args []string) error {
flags, _ := ParseFlags(args)

// Create collector and generate report
collector := diagnostics.NewCollector(c.paths, Version)
report, err := collector.Collect()
if err != nil {
return fmt.Errorf("failed to collect diagnostics: %w", err)
}

// Always output as pretty JSON by default (unless --json=false for compact)
prettyJSON := flags["json"] != "false"
jsonOutput, err := report.ToJSON(prettyJSON)
if err != nil {
return fmt.Errorf("failed to format diagnostics as JSON: %w", err)
}

// Check if output file specified
if outputFile, ok := flags["output"]; ok {
if err := os.WriteFile(outputFile, []byte(jsonOutput), 0644); err != nil {
return fmt.Errorf("failed to write diagnostics to %s: %w", outputFile, err)
}
fmt.Printf("Diagnostics written to: %s\n", outputFile)
return nil
}

// Print to stdout
fmt.Println(jsonOutput)
return nil
}

// listBranchesWithPrefix returns all local branches with the given prefix
func (c *CLI) listBranchesWithPrefix(repoPath, prefix string) ([]string, error) {
cmd := exec.Command("git", "branch", "--list", prefix+"*")
Expand Down
25 changes: 25 additions & 0 deletions internal/daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"time"

"github.com/dlorenc/multiclaude/internal/agents"
"github.com/dlorenc/multiclaude/internal/diagnostics"
"github.com/dlorenc/multiclaude/internal/hooks"
"github.com/dlorenc/multiclaude/internal/logging"
"github.com/dlorenc/multiclaude/internal/messages"
Expand Down Expand Up @@ -97,6 +98,9 @@ func (d *Daemon) Start() error {

d.logger.Info("Daemon started successfully")

// Log system diagnostics for monitoring and debugging
d.logDiagnostics()

// Restore agents for tracked repos BEFORE starting health checks
// This prevents race conditions where health check cleans up agents being restored
d.restoreTrackedRepos()
Expand Down Expand Up @@ -142,6 +146,27 @@ func (d *Daemon) TriggerWake() {
d.wakeAgents()
}

// logDiagnostics logs system diagnostics in machine-readable JSON format
func (d *Daemon) logDiagnostics() {
// Get version from CLI package (same as used by CLI)
version := "dev"

collector := diagnostics.NewCollector(d.paths, version)
report, err := collector.Collect()
if err != nil {
d.logger.Error("Failed to collect diagnostics: %v", err)
return
}

jsonOutput, err := report.ToJSON(false) // Compact JSON for logs
if err != nil {
d.logger.Error("Failed to format diagnostics: %v", err)
return
}

d.logger.Info("System diagnostics: %s", jsonOutput)
}

// Stop stops the daemon
func (d *Daemon) Stop() error {
d.logger.Info("Stopping daemon")
Expand Down
Loading