Add subtask generation decision

Change-Id: If43efa882de08bc262fe6117af7307e97c4dfeda
diff --git a/server/agent/manager.go b/server/agent/manager.go
index 3d8277f..ab625bf 100644
--- a/server/agent/manager.go
+++ b/server/agent/manager.go
@@ -261,16 +261,16 @@
 		return fmt.Errorf("failed to update task status: %w", err)
 	}
 
-	// Check if this task should generate subtasks
+	// Check if this task should generate subtasks (with LLM decision)
 	if m.shouldGenerateSubtasks(task) {
-		log.Printf("Analyzing task %s for subtask generation", task.ID)
+		log.Printf("LLM determined task %s should generate subtasks", task.ID)
 		if err := m.generateSubtasksForTask(ctx, task); err != nil {
 			log.Printf("Warning: Failed to generate subtasks for task %s: %v", task.ID, err)
 			// Continue with normal processing if subtask generation fails
 		} else {
 			// Task has been converted to subtask management, mark as completed
 			task.Status = tm.StatusCompleted
-			task.Solution = "Task broken down into subtasks. See subtasks PR for details."
+			task.Solution = "Task analyzed by LLM and broken down into subtasks with potential new agent creation. See subtasks PR for details."
 			completedAt := time.Now()
 			task.CompletedAt = &completedAt
 			agent.CurrentTask = nil
@@ -279,7 +279,7 @@
 				return fmt.Errorf("failed to update task with subtasks: %w", err)
 			}
 
-			log.Printf("Task %s converted to subtasks by agent %s", task.ID, agent.Name)
+			log.Printf("Task %s converted to subtasks by agent %s using LLM analysis", task.ID, agent.Name)
 			return nil
 		}
 	}
@@ -611,24 +611,37 @@
 	return status
 }
 
-// shouldGenerateSubtasks determines if a task should be broken down into subtasks
+// shouldGenerateSubtasks determines if a task should be broken down into subtasks using LLM
 func (m *Manager) shouldGenerateSubtasks(task *tm.Task) bool {
 	// Don't generate subtasks for subtasks
 	if task.ParentTaskID != "" {
 		return false
 	}
 
-	// Don't generate if already generated
-	if task.SubtasksGenerated {
+	// Don't generate if already evaluated
+	if task.SubtasksEvaluated {
 		return false
 	}
 
-	// Only generate for high priority tasks or complex descriptions
-	if task.Priority == tm.PriorityHigh || len(task.Description) > 200 {
-		return true
+	// Ask LLM to decide
+	ctx := context.Background()
+	decision, err := m.subtaskService.ShouldGenerateSubtasks(ctx, task)
+	if err != nil {
+		log.Printf("Warning: Failed to get LLM subtask decision for task %s: %v", task.ID, err)
+		// Fallback to simple heuristics
+		return task.Priority == tm.PriorityHigh || len(task.Description) > 200
 	}
 
-	return false
+	// Update task to mark as evaluated
+	task.SubtasksEvaluated = true
+	if err := m.taskManager.UpdateTask(task); err != nil {
+		log.Printf("Warning: Failed to update task evaluation status: %v", err)
+	}
+
+	log.Printf("LLM subtask decision for task %s: needs_subtasks=%v, complexity=%d, reasoning=%s", 
+		task.ID, decision.NeedsSubtasks, decision.ComplexityScore, decision.Reasoning)
+
+	return decision.NeedsSubtasks
 }
 
 // generateSubtasksForTask analyzes a task and creates a PR with proposed subtasks
@@ -654,7 +667,14 @@
 	task.SubtasksGenerated = true
 
 	log.Printf("Generated subtask PR for task %s: %s", task.ID, prURL)
-	log.Printf("Proposed %d subtasks for task %s", len(analysis.Subtasks), task.ID)
+	log.Printf("Proposed %d subtasks and %d new agents for task %s", len(analysis.Subtasks), len(analysis.AgentCreations), task.ID)
+	
+	// Log proposed new agents if any
+	if len(analysis.AgentCreations) > 0 {
+		for _, agent := range analysis.AgentCreations {
+			log.Printf("Proposed new agent: %s with skills: %v", agent.Role, agent.Skills)
+		}
+	}
 
 	return nil
 }
diff --git a/server/llm/fake/fake.go b/server/llm/fake/fake.go
index 3735821..58185b3 100644
--- a/server/llm/fake/fake.go
+++ b/server/llm/fake/fake.go
@@ -186,6 +186,20 @@
   "estimated_total_hours": 102,
   "risk_assessment": "Main risks include scope creep, API integration complexity, and potential database performance issues. Mitigation strategies include regular stakeholder reviews, comprehensive API documentation, and early performance testing."
 }`,
+
+		`{
+  "needs_subtasks": true,
+  "reasoning": "This task appears to be complex and multi-faceted, requiring different specialized skills including backend development, frontend work, database management, and testing. Breaking it down into subtasks would allow for better parallel execution and specialized agent assignment.",
+  "complexity_score": 8,
+  "required_skills": ["backend_development", "frontend_development", "database_design", "api_development", "testing", "deployment"]
+}`,
+
+		`{
+  "needs_subtasks": false,
+  "reasoning": "This task is straightforward and can be completed by a single agent with existing capabilities. The scope is well-defined and doesn't require multiple specialized skills or extensive coordination.",
+  "complexity_score": 3,
+  "required_skills": ["basic_development"]
+}`,
 	}
 
 	return &FakeProvider{
@@ -199,22 +213,34 @@
 	// Simulate API delay
 	time.Sleep(500 * time.Millisecond)
 
-	// Check if this is a subtask analysis request
-	isSubtaskRequest := false
+	// Check the type of request to provide appropriate response
+	isSubtaskAnalysisRequest := false
+	isSubtaskDecisionRequest := false
 	for _, msg := range req.Messages {
-		if strings.Contains(msg.Content, "subtasks") || strings.Contains(msg.Content, "JSON") {
-			isSubtaskRequest = true
+		if strings.Contains(msg.Content, "break it down into subtasks") || strings.Contains(msg.Content, "subtask analysis") {
+			isSubtaskAnalysisRequest = true
+			break
+		} else if strings.Contains(msg.Content, "needs to be broken down") || strings.Contains(msg.Content, "evaluate whether") {
+			isSubtaskDecisionRequest = true
 			break
 		}
 	}
 
 	var response string
-	if isSubtaskRequest && len(f.responses) > 3 {
-		// Always use the JSON subtask response for subtask requests
-		response = f.responses[3] // The JSON response is at index 3
+	if isSubtaskAnalysisRequest && len(f.responses) > 3 {
+		// Use the detailed subtask analysis JSON response
+		response = f.responses[3] // The detailed JSON response is at index 3
+	} else if isSubtaskDecisionRequest && len(f.responses) > 4 {
+		// Use alternating decision responses
+		if f.index%2 == 0 {
+			response = f.responses[4] // "needs_subtasks": true
+		} else {
+			response = f.responses[5] // "needs_subtasks": false
+		}
+		f.index++
 	} else {
-		// Get the next response (cycle through responses)
-		response = f.responses[f.index%len(f.responses)]
+		// Get the next regular response (cycle through first 3)
+		response = f.responses[f.index%3] // Only cycle through first 3 responses
 		f.index++
 	}
 
diff --git a/server/subtasks/service.go b/server/subtasks/service.go
index ad397ff..710dfaf 100644
--- a/server/subtasks/service.go
+++ b/server/subtasks/service.go
@@ -27,6 +27,44 @@
 	}
 }
 
+// ShouldGenerateSubtasks asks LLM whether a task needs subtasks based on existing agents
+func (s *SubtaskService) ShouldGenerateSubtasks(ctx context.Context, task *tm.Task) (*tm.SubtaskDecision, error) {
+	prompt := s.buildSubtaskDecisionPrompt(task)
+	
+	req := llm.ChatCompletionRequest{
+		Model: "gpt-4",
+		Messages: []llm.Message{
+			{
+				Role:    llm.RoleSystem,
+				Content: s.getSubtaskDecisionSystemPrompt(),
+			},
+			{
+				Role:    llm.RoleUser,
+				Content: prompt,
+			},
+		},
+		MaxTokens:   &[]int{1000}[0],
+		Temperature: &[]float64{0.3}[0],
+	}
+
+	resp, err := s.llmProvider.ChatCompletion(ctx, req)
+	if err != nil {
+		return nil, fmt.Errorf("LLM decision failed: %w", err)
+	}
+
+	if len(resp.Choices) == 0 {
+		return nil, fmt.Errorf("no response from LLM")
+	}
+
+	// Parse the LLM response
+	decision, err := s.parseSubtaskDecision(resp.Choices[0].Message.Content)
+	if err != nil {
+		return nil, fmt.Errorf("failed to parse LLM decision: %w", err)
+	}
+
+	return decision, nil
+}
+
 // AnalyzeTaskForSubtasks uses LLM to analyze a task and propose subtasks
 func (s *SubtaskService) AnalyzeTaskForSubtasks(ctx context.Context, task *tm.Task) (*tm.SubtaskAnalysis, error) {
 	prompt := s.buildSubtaskAnalysisPrompt(task)
@@ -65,21 +103,53 @@
 	return analysis, nil
 }
 
+// getSubtaskDecisionSystemPrompt returns the system prompt for subtask decision
+func (s *SubtaskService) getSubtaskDecisionSystemPrompt() string {
+	availableRoles := strings.Join(s.agentRoles, ", ")
+	
+	return fmt.Sprintf(`You are an expert project manager and task analyst. Your job is to determine whether a task needs to be broken down into subtasks.
+
+Currently available team roles and their capabilities: %s
+
+When evaluating a task, consider:
+1. Task complexity and scope
+2. Whether multiple specialized skills are needed
+3. If the task can be completed by a single agent with current capabilities
+4. Whether new agent roles might be needed for specialized skills
+
+Respond with a JSON object in this exact format:
+{
+  "needs_subtasks": true/false,
+  "reasoning": "Clear explanation of why subtasks are or aren't needed",
+  "complexity_score": 5,
+  "required_skills": ["skill1", "skill2", "skill3"]
+}
+
+Complexity score should be 1-10 where:
+- 1-3: Simple tasks that can be handled by one agent
+- 4-6: Moderate complexity, might benefit from subtasks
+- 7-10: Complex tasks that definitely need breaking down
+
+Required skills should list all technical/domain skills needed to complete the task.`, availableRoles)
+}
+
 // getSubtaskAnalysisSystemPrompt returns the system prompt for subtask analysis
 func (s *SubtaskService) getSubtaskAnalysisSystemPrompt() string {
 	availableRoles := strings.Join(s.agentRoles, ", ")
 	
 	return fmt.Sprintf(`You are an expert project manager and technical architect. Your job is to analyze complex tasks and break them down into well-defined subtasks that can be assigned to specialized team members.
 
-Available team roles: %s
+Currently available team roles: %s
 
 When analyzing a task, you should:
 1. Understand the task requirements and scope
 2. Break it down into logical, manageable subtasks
-3. Assign each subtask to the most appropriate team role
+3. Assign each subtask to the most appropriate team role OR propose creating new agents
 4. Estimate effort and identify dependencies
 5. Provide a clear execution strategy
 
+If you need specialized skills not covered by existing roles, propose new agent creation.
+
 Respond with a JSON object in this exact format:
 {
   "analysis_summary": "Brief analysis of the task and approach",
@@ -90,7 +160,16 @@
       "priority": "high|medium|low",
       "assigned_to": "role_name",
       "estimated_hours": 8,
-      "dependencies": ["subtask_index_1", "subtask_index_2"]
+      "dependencies": ["subtask_index_1", "subtask_index_2"],
+      "required_skills": ["skill1", "skill2"]
+    }
+  ],
+  "agent_creations": [
+    {
+      "role": "new_role_name",
+      "skills": ["specialized_skill1", "specialized_skill2"],
+      "description": "Description of what this agent does",
+      "justification": "Why this new agent is needed"
     }
   ],
   "recommended_approach": "High-level strategy for executing these subtasks",
@@ -98,7 +177,34 @@
   "risk_assessment": "Potential risks and mitigation strategies"
 }
 
-Only use the available team roles for assignment. Dependencies should reference subtask indices (e.g., ["0", "1"] means depends on first and second subtasks).`, availableRoles)
+For existing roles, use: %s
+For new agents, propose appropriate role names and skill sets.
+Dependencies should reference subtask indices (e.g., ["0", "1"] means depends on first and second subtasks).`, availableRoles, availableRoles)
+}
+
+// buildSubtaskDecisionPrompt creates the user prompt for subtask decision
+func (s *SubtaskService) buildSubtaskDecisionPrompt(task *tm.Task) string {
+	return fmt.Sprintf(`Please evaluate whether the following task needs to be broken down into subtasks:
+
+**Task Title:** %s
+
+**Description:** %s
+
+**Priority:** %s
+
+**Current Status:** %s
+
+Consider:
+- Can this be completed by a single agent with existing capabilities?
+- Does it require multiple specialized skills?
+- Is the scope too large for one person?
+- Are there logical components that could be parallelized?
+
+Provide your decision in the JSON format specified in the system prompt.`, 
+		task.Title, 
+		task.Description, 
+		task.Priority, 
+		task.Status)
 }
 
 // buildSubtaskAnalysisPrompt creates the user prompt for LLM analysis
@@ -127,6 +233,26 @@
 		task.Status)
 }
 
+// parseSubtaskDecision parses the LLM response into a SubtaskDecision struct
+func (s *SubtaskService) parseSubtaskDecision(response string) (*tm.SubtaskDecision, error) {
+	// Try to extract JSON from the response
+	jsonStart := strings.Index(response, "{")
+	jsonEnd := strings.LastIndex(response, "}")
+	
+	if jsonStart == -1 || jsonEnd == -1 {
+		return nil, fmt.Errorf("no JSON found in LLM response")
+	}
+	
+	jsonStr := response[jsonStart : jsonEnd+1]
+	
+	var decision tm.SubtaskDecision
+	if err := json.Unmarshal([]byte(jsonStr), &decision); err != nil {
+		return nil, fmt.Errorf("failed to unmarshal JSON: %w", err)
+	}
+	
+	return &decision, nil
+}
+
 // parseSubtaskAnalysis parses the LLM response into a SubtaskAnalysis struct
 func (s *SubtaskService) parseSubtaskAnalysis(response string, parentTaskID string) (*tm.SubtaskAnalysis, error) {
 	// Try to extract JSON from the response (LLM might wrap it in markdown)
@@ -148,7 +274,9 @@
 			AssignedTo     string   `json:"assigned_to"`
 			EstimatedHours int      `json:"estimated_hours"`
 			Dependencies   []string `json:"dependencies"`
+			RequiredSkills []string `json:"required_skills"`
 		} `json:"subtasks"`
+		AgentCreations      []tm.AgentCreationProposal `json:"agent_creations"`
 		RecommendedApproach   string `json:"recommended_approach"`
 		EstimatedTotalHours   int    `json:"estimated_total_hours"`
 		RiskAssessment        string `json:"risk_assessment"`
@@ -162,6 +290,7 @@
 	analysis := &tm.SubtaskAnalysis{
 		ParentTaskID:        parentTaskID,
 		AnalysisSummary:     rawAnalysis.AnalysisSummary,
+		AgentCreations:      rawAnalysis.AgentCreations,
 		RecommendedApproach: rawAnalysis.RecommendedApproach,
 		EstimatedTotalHours: rawAnalysis.EstimatedTotalHours,
 		RiskAssessment:      rawAnalysis.RiskAssessment,
@@ -184,43 +313,81 @@
 			AssignedTo:     st.AssignedTo,
 			EstimatedHours: st.EstimatedHours,
 			Dependencies:   st.Dependencies,
+			RequiredSkills: st.RequiredSkills,
 		}
 		
 		analysis.Subtasks = append(analysis.Subtasks, subtask)
 	}
 	
-	// Validate agent assignments
-	if err := s.validateAgentAssignments(analysis); err != nil {
-		log.Printf("Warning: Invalid agent assignments: %v", err)
-		// Fix assignments by using first available role
-		s.fixAgentAssignments(analysis)
+	// Validate agent assignments and handle new agent creation
+	if err := s.validateAndHandleAgentAssignments(analysis); err != nil {
+		log.Printf("Warning during agent assignment handling: %v", err)
 	}
 	
 	return analysis, nil
 }
 
-// validateAgentAssignments checks if all assigned roles are valid
-func (s *SubtaskService) validateAgentAssignments(analysis *tm.SubtaskAnalysis) error {
-	for i, subtask := range analysis.Subtasks {
-		if !s.isValidAgentRole(subtask.AssignedTo) {
-			return fmt.Errorf("subtask %d has invalid agent role: %s", i, subtask.AssignedTo)
+// validateAndHandleAgentAssignments validates assignments and creates agent creation subtasks if needed
+func (s *SubtaskService) validateAndHandleAgentAssignments(analysis *tm.SubtaskAnalysis) error {
+	// Collect all agent roles that will be available (existing + proposed new ones)
+	availableRoles := make(map[string]bool)
+	for _, role := range s.agentRoles {
+		availableRoles[role] = true
+	}
+	
+	// Add proposed new agent roles
+	for _, agentCreation := range analysis.AgentCreations {
+		availableRoles[agentCreation.Role] = true
+		
+		// Create a subtask for agent creation
+		agentCreationSubtask := tm.SubtaskProposal{
+			Title:          fmt.Sprintf("Create %s Agent", strings.Title(agentCreation.Role)),
+			Description:    fmt.Sprintf("Create and configure a new %s agent with skills: %s. %s", agentCreation.Role, strings.Join(agentCreation.Skills, ", "), agentCreation.Justification),
+			Priority:       tm.PriorityHigh, // Agent creation is high priority
+			AssignedTo:     "ceo", // CEO creates new agents
+			EstimatedHours: 4,     // Estimated time to set up new agent
+			Dependencies:   []string{}, // No dependencies for agent creation
+			RequiredSkills: []string{"agent_configuration", "system_design"},
+		}
+		
+		// Insert at the beginning so agent creation happens first
+		analysis.Subtasks = append([]tm.SubtaskProposal{agentCreationSubtask}, analysis.Subtasks...)
+		
+		// Update dependencies to account for the new subtask at index 0
+		for i := 1; i < len(analysis.Subtasks); i++ {
+			for j, dep := range analysis.Subtasks[i].Dependencies {
+				// Convert dependency index and increment by 1
+				if depIndex := s.parseDependencyIndex(dep); depIndex >= 0 {
+					analysis.Subtasks[i].Dependencies[j] = fmt.Sprintf("%d", depIndex+1)
+				}
+			}
 		}
 	}
-	return nil
-}
-
-// fixAgentAssignments fixes invalid agent assignments
-func (s *SubtaskService) fixAgentAssignments(analysis *tm.SubtaskAnalysis) {
+	
+	// Now validate all assignments against available roles
 	defaultRole := "ceo" // fallback role
 	if len(s.agentRoles) > 0 {
 		defaultRole = s.agentRoles[0]
 	}
 	
 	for i := range analysis.Subtasks {
-		if !s.isValidAgentRole(analysis.Subtasks[i].AssignedTo) {
+		if !availableRoles[analysis.Subtasks[i].AssignedTo] {
+			log.Printf("Warning: Unknown agent role '%s' for subtask '%s', assigning to %s", 
+				analysis.Subtasks[i].AssignedTo, analysis.Subtasks[i].Title, defaultRole)
 			analysis.Subtasks[i].AssignedTo = defaultRole
 		}
 	}
+	
+	return nil
+}
+
+// parseDependencyIndex parses a dependency string to an integer index
+func (s *SubtaskService) parseDependencyIndex(dep string) int {
+	var idx int
+	if _, err := fmt.Sscanf(dep, "%d", &idx); err == nil {
+		return idx
+	}
+	return -1 // Invalid dependency format
 }
 
 // isValidAgentRole checks if a role is in the available agent roles
diff --git a/server/subtasks/service_test.go b/server/subtasks/service_test.go
index 1d94211..ade62fc 100644
--- a/server/subtasks/service_test.go
+++ b/server/subtasks/service_test.go
@@ -95,6 +95,38 @@
 	}
 }
 
+func TestShouldGenerateSubtasks(t *testing.T) {
+	// Test decision to generate subtasks
+	decisionResponse := `{
+  "needs_subtasks": true,
+  "reasoning": "Complex task requiring multiple skills",
+  "complexity_score": 8,
+  "required_skills": ["backend", "frontend", "database"]
+}`
+
+	mockProvider := NewMockLLMProvider([]string{decisionResponse})
+	agentRoles := []string{"backend", "frontend", "qa"}
+	service := NewSubtaskService(mockProvider, nil, agentRoles)
+	
+	// Test the parseSubtaskDecision method directly since ShouldGenerateSubtasks is used by manager
+	decision, err := service.parseSubtaskDecision(decisionResponse)
+	if err != nil {
+		t.Fatalf("parseSubtaskDecision failed: %v", err)
+	}
+	
+	if !decision.NeedsSubtasks {
+		t.Error("Expected decision to need subtasks")
+	}
+	
+	if decision.ComplexityScore != 8 {
+		t.Errorf("Expected complexity score 8, got %d", decision.ComplexityScore)
+	}
+	
+	if len(decision.RequiredSkills) != 3 {
+		t.Errorf("Expected 3 required skills, got %d", len(decision.RequiredSkills))
+	}
+}
+
 func TestAnalyzeTaskForSubtasks(t *testing.T) {
 	jsonResponse := `{
   "analysis_summary": "This task requires breaking down into multiple components",
@@ -105,7 +137,8 @@
       "priority": "high",
       "assigned_to": "backend",
       "estimated_hours": 16,
-      "dependencies": []
+      "dependencies": [],
+      "required_skills": ["go", "api_development"]
     },
     {
       "title": "Frontend Development", 
@@ -113,7 +146,16 @@
       "priority": "medium",
       "assigned_to": "frontend",
       "estimated_hours": 12,
-      "dependencies": ["0"]
+      "dependencies": ["0"],
+      "required_skills": ["react", "typescript"]
+    }
+  ],
+  "agent_creations": [
+    {
+      "role": "security_specialist",
+      "skills": ["security_audit", "penetration_testing"],
+      "description": "Specialized agent for security tasks",
+      "justification": "Authentication requires security expertise"
     }
   ],
   "recommended_approach": "Start with backend then frontend",
@@ -122,7 +164,7 @@
 }`
 
 	mockProvider := NewMockLLMProvider([]string{jsonResponse})
-	agentRoles := []string{"backend", "frontend", "qa"}
+	agentRoles := []string{"backend", "frontend", "qa", "ceo"} // Include CEO for agent creation
 	service := NewSubtaskService(mockProvider, nil, agentRoles)
 	
 	task := &tm.Task{
@@ -148,12 +190,39 @@
 		t.Error("Analysis summary should not be empty")
 	}
 	
-	if len(analysis.Subtasks) != 2 {
-		t.Errorf("Expected 2 subtasks, got %d", len(analysis.Subtasks))
+	// Should have 3 subtasks (1 for agent creation + 2 original)
+	if len(analysis.Subtasks) != 3 {
+		t.Errorf("Expected 3 subtasks (including agent creation), got %d", len(analysis.Subtasks))
+		t.Logf("Subtasks: %+v", analysis.Subtasks)
+		return // Exit early if count is wrong to avoid index errors
 	}
 	
-	// Test first subtask
-	subtask1 := analysis.Subtasks[0]
+	// Test agent creation was processed
+	if len(analysis.AgentCreations) != 1 {
+		t.Errorf("Expected 1 agent creation, got %d", len(analysis.AgentCreations))
+	} else {
+		agentCreation := analysis.AgentCreations[0]
+		if agentCreation.Role != "security_specialist" {
+			t.Errorf("Expected role 'security_specialist', got %s", agentCreation.Role)
+		}
+		if len(agentCreation.Skills) != 2 {
+			t.Errorf("Expected 2 skills, got %d", len(agentCreation.Skills))
+		}
+	}
+
+	// We already checked the count above
+
+	// Test first subtask (agent creation)
+	subtask0 := analysis.Subtasks[0]
+	if !strings.Contains(subtask0.Title, "Security_specialist") {
+		t.Errorf("Expected agent creation subtask for security_specialist, got %s", subtask0.Title)
+	}
+	if subtask0.AssignedTo != "ceo" {
+		t.Errorf("Expected agent creation assigned to 'ceo', got %s", subtask0.AssignedTo)
+	}
+
+	// Test second subtask (original backend task, now at index 1)
+	subtask1 := analysis.Subtasks[1]
 	if subtask1.Title != "Backend Development" {
 		t.Errorf("Expected title 'Backend Development', got %s", subtask1.Title)
 	}
@@ -166,19 +235,27 @@
 	if subtask1.EstimatedHours != 16 {
 		t.Errorf("Expected 16 hours, got %d", subtask1.EstimatedHours)
 	}
+	if len(subtask1.RequiredSkills) != 2 {
+		t.Errorf("Expected 2 required skills, got %d", len(subtask1.RequiredSkills))
+	}
 	
-	// Test second subtask
-	subtask2 := analysis.Subtasks[1]
+	// Test third subtask (original frontend task, now at index 2 with updated dependencies)
+	subtask2 := analysis.Subtasks[2]
 	if subtask2.Title != "Frontend Development" {
 		t.Errorf("Expected title 'Frontend Development', got %s", subtask2.Title)
 	}
 	if subtask2.Priority != tm.PriorityMedium {
 		t.Errorf("Expected medium priority, got %s", subtask2.Priority)
 	}
-	if len(subtask2.Dependencies) != 1 || subtask2.Dependencies[0] != "0" {
-		t.Errorf("Expected dependencies [0], got %v", subtask2.Dependencies)
+	// Dependencies should be updated to account for the new agent creation subtask
+	if len(subtask2.Dependencies) != 1 || subtask2.Dependencies[0] != "1" {
+		t.Errorf("Expected dependencies [1] (updated for agent creation), got %v", subtask2.Dependencies)
+	}
+	if len(subtask2.RequiredSkills) != 2 {
+		t.Errorf("Expected 2 required skills, got %d", len(subtask2.RequiredSkills))
 	}
 	
+	// Total hours should include agent creation time (4 hours)
 	if analysis.EstimatedTotalHours != 28 {
 		t.Errorf("Expected 28 total hours, got %d", analysis.EstimatedTotalHours)
 	}
diff --git a/server/tm/types.go b/server/tm/types.go
index ef6508c..980be44 100644
--- a/server/tm/types.go
+++ b/server/tm/types.go
@@ -47,6 +47,7 @@
 	ParentTaskID      string    `json:"parent_task_id,omitempty"`      // ID of parent task if this is a subtask
 	SubtasksPRURL     string    `json:"subtasks_pr_url,omitempty"`     // PR URL for proposed subtasks
 	SubtasksGenerated bool      `json:"subtasks_generated"`            // Whether subtasks have been generated
+	SubtasksEvaluated bool      `json:"subtasks_evaluated"`            // Whether task has been evaluated for subtasks
 	
 	CreatedAt      time.Time    `json:"created_at"`
 	UpdatedAt      time.Time    `json:"updated_at"`
@@ -102,6 +103,23 @@
 	AssignedTo  string       `json:"assigned_to"`  // Suggested agent role
 	EstimatedHours int       `json:"estimated_hours,omitempty"`
 	Dependencies []string    `json:"dependencies,omitempty"` // IDs of other subtasks this depends on
+	RequiredSkills []string  `json:"required_skills,omitempty"` // Skills needed for this subtask
+}
+
+// SubtaskDecision represents LLM's decision about whether a task needs subtasks
+type SubtaskDecision struct {
+	NeedsSubtasks   bool     `json:"needs_subtasks"`
+	Reasoning       string   `json:"reasoning"`
+	ComplexityScore int      `json:"complexity_score"` // 1-10 scale
+	RequiredSkills  []string `json:"required_skills"`  // Skills needed for the task
+}
+
+// AgentCreationProposal represents a proposal to create a new agent
+type AgentCreationProposal struct {
+	Role         string   `json:"role"`
+	Skills       []string `json:"skills"`
+	Description  string   `json:"description"`
+	Justification string  `json:"justification"`
 }
 
 // SubtaskAnalysis represents the LLM's analysis and proposed subtasks
@@ -109,6 +127,7 @@
 	ParentTaskID    string             `json:"parent_task_id"`
 	AnalysisSummary string             `json:"analysis_summary"`
 	Subtasks        []SubtaskProposal  `json:"subtasks"`
+	AgentCreations  []AgentCreationProposal `json:"agent_creations,omitempty"` // New agents needed
 	RecommendedApproach string         `json:"recommended_approach"`
 	EstimatedTotalHours int            `json:"estimated_total_hours"`
 	RiskAssessment  string             `json:"risk_assessment,omitempty"`