Refactor everything

Change-Id: Ic3a37c38cfecba943c91f6ae545ce1c5b551c0d5
diff --git a/server/agent/manager.go b/server/agent/manager.go
index 191d42e..ea7474d 100644
--- a/server/agent/manager.go
+++ b/server/agent/manager.go
@@ -1,17 +1,11 @@
 package agent
 
 import (
-	"context"
 	"fmt"
 	"log/slog"
-	"os"
-	"os/exec"
-	"path/filepath"
-	"strings"
 	"time"
 
 	"github.com/iomodo/staff/config"
-	"github.com/iomodo/staff/git"
 	"github.com/iomodo/staff/llm"
 	_ "github.com/iomodo/staff/llm/providers" // Auto-register all providers
 	"github.com/iomodo/staff/task"
@@ -20,70 +14,31 @@
 
 // Manager manages multiple AI agents with Git operations and task processing
 type Manager struct {
-	config         *config.Config
-	agents         map[string]*Agent
-	taskManager    tm.TaskManager
-	autoAssigner   *task.AutoAssigner
-	prProvider     git.PullRequestProvider
-	cloneManager   *git.CloneManager
-	subtaskService *task.SubtaskService
-	isRunning      map[string]bool
-	stopChannels   map[string]chan struct{}
-	logger         *slog.Logger
+	config       *config.Config
+	agents       map[string]*Agent
+	taskManager  tm.TaskManager
+	autoAssigner *task.AutoAssigner
+	isRunning    map[string]bool
+	roles        []string
+	logger       *slog.Logger
 }
 
 // NewManager creates a new agent manager
 func NewManager(cfg *config.Config, taskManager tm.TaskManager, logger *slog.Logger) (*Manager, error) {
-	if logger == nil {
-		logger = slog.Default()
-	}
-	// Create auto-assigner
 	autoAssigner := task.NewAutoAssigner(cfg.Agents)
 
-	// Create PR provider based on configuration
-	var prProvider git.PullRequestProvider
-	var repoURL string
-
-	switch cfg.GetPrimaryGitProvider() {
-	case "github":
-		githubConfig := git.GitHubConfig{
-			Token:  cfg.GitHub.Token,
-			Logger: logger,
-		}
-		prProvider = git.NewGitHubPullRequestProvider(cfg.GitHub.Owner, cfg.GitHub.Repo, githubConfig)
-		repoURL = fmt.Sprintf("https://github.com/%s/%s.git", cfg.GitHub.Owner, cfg.GitHub.Repo)
-		logger.Info("Using GitHub as pull request provider",
-			slog.String("owner", cfg.GitHub.Owner),
-			slog.String("repo", cfg.GitHub.Repo))
-	case "gerrit":
-		gerritConfig := git.GerritConfig{
-			Username: cfg.Gerrit.Username,
-			Password: cfg.Gerrit.Password,
-			BaseURL:  cfg.Gerrit.BaseURL,
-			Logger:   logger,
-		}
-		prProvider = git.NewGerritPullRequestProvider(cfg.Gerrit.Project, gerritConfig)
-		repoURL = fmt.Sprintf("%s/%s", cfg.Gerrit.BaseURL, cfg.Gerrit.Project)
-		logger.Info("Using Gerrit as pull request provider",
-			slog.String("base_url", cfg.Gerrit.BaseURL),
-			slog.String("project", cfg.Gerrit.Project))
-	default:
-		return nil, fmt.Errorf("no valid Git provider configured")
+	agentRoles := make([]string, 0, len(cfg.Agents))
+	for _, agentConfig := range cfg.Agents {
+		agentRoles = append(agentRoles, agentConfig.Role)
 	}
 
-	// Create clone manager for per-agent Git repositories
-	workspacePath := filepath.Join(".", "workspace")
-	cloneManager := git.NewCloneManager(repoURL, workspacePath)
-
 	manager := &Manager{
 		config:       cfg,
 		agents:       make(map[string]*Agent),
 		taskManager:  taskManager,
 		autoAssigner: autoAssigner,
-		prProvider:   prProvider,
-		cloneManager: cloneManager,
 		isRunning:    make(map[string]bool),
-		stopChannels: make(map[string]chan struct{}),
+		roles:        agentRoles,
 		logger:       logger,
 	}
 
@@ -92,18 +47,19 @@
 		return nil, fmt.Errorf("failed to initialize agents: %w", err)
 	}
 
-	// Initialize subtask service after agents are created
-	if err := manager.initializeSubtaskService(); err != nil {
-		return nil, fmt.Errorf("failed to initialize subtask service: %w", err)
-	}
-
 	return manager, nil
 }
 
 // initializeAgents creates agent instances from configuration
 func (m *Manager) initializeAgents() error {
+	llmConfig := llm.Config{
+		Provider: llm.ProviderFake, // Use fake provider for testing
+		APIKey:   m.config.OpenAI.APIKey,
+		BaseURL:  m.config.OpenAI.BaseURL,
+		Timeout:  m.config.OpenAI.Timeout,
+	}
 	for _, agentConfig := range m.config.Agents {
-		agent, err := m.createAgent(agentConfig)
+		agent, err := NewAgent(agentConfig, llmConfig, m.taskManager, m.roles, m.logger)
 		if err != nil {
 			return fmt.Errorf("failed to create agent %s: %w", agentConfig.Name, err)
 		}
@@ -112,95 +68,25 @@
 	return nil
 }
 
-// initializeSubtaskService creates the subtask service with available agent roles
-func (m *Manager) initializeSubtaskService() error {
-	// Get agent roles from configuration
-	agentRoles := make([]string, 0, len(m.config.Agents))
-	for _, agentConfig := range m.config.Agents {
-		agentRoles = append(agentRoles, agentConfig.Name)
+func (m *Manager) StartAllAgents() {
+	// Start all configured agents with a default loop interval
+	defaultInterval := 1 * time.Second
+
+	for _, a := range m.agents {
+		m.logger.Info("Starting agent",
+			slog.String("name", a.Name),
+			slog.String("role", a.Role),
+			slog.String("model", a.Model))
+		if err := a.Start(defaultInterval); err != nil {
+			m.logger.Error("Failed to start agent",
+				slog.String("agent", a.Name),
+				slog.String("error", err.Error()))
+			continue
+		}
+		m.isRunning[a.Name] = true
 	}
-
-	// Use the first agent's LLM provider for subtask analysis
-	if len(m.agents) == 0 {
-		return fmt.Errorf("no agents available for subtask service")
-	}
-
-	var firstAgent *Agent
-	for _, agent := range m.agents {
-		firstAgent = agent
-		break
-	}
-
-	// Get owner and repo for subtask service based on provider
-	var owner, repo string
-	switch m.config.GetPrimaryGitProvider() {
-	case "github":
-		owner = m.config.GitHub.Owner
-		repo = m.config.GitHub.Repo
-	case "gerrit":
-		owner = m.config.Gerrit.Project
-		repo = m.config.Gerrit.Project
-	}
-
-	m.subtaskService = task.NewSubtaskService(
-		firstAgent.Provider,
-		m.taskManager,
-		agentRoles,
-		m.prProvider,
-		owner,
-		repo,
-		m.cloneManager,
-		m.logger,
-	)
-
-	return nil
 }
 
-// createAgent creates a single agent instance
-func (m *Manager) createAgent(agentConfig config.AgentConfig) (*Agent, error) {
-	// Load system prompt
-	systemPrompt, err := m.loadSystemPrompt(agentConfig.SystemPromptFile)
-	if err != nil {
-		return nil, fmt.Errorf("failed to load system prompt: %w", err)
-	}
-
-	// Create LLM provider
-	llmConfig := llm.Config{
-		Provider: llm.ProviderFake, // Use fake provider for testing
-		APIKey:   m.config.OpenAI.APIKey,
-		BaseURL:  m.config.OpenAI.BaseURL,
-		Timeout:  m.config.OpenAI.Timeout,
-	}
-
-	provider, err := llm.CreateProvider(llmConfig)
-	if err != nil {
-		return nil, fmt.Errorf("failed to create LLM provider: %w", err)
-	}
-
-	agent := &Agent{
-		Name:         agentConfig.Name,
-		Role:         agentConfig.Role,
-		Model:        agentConfig.Model,
-		SystemPrompt: systemPrompt,
-		Provider:     provider,
-		MaxTokens:    agentConfig.MaxTokens,
-		Temperature:  agentConfig.Temperature,
-		Stats:        AgentStats{},
-	}
-
-	return agent, nil
-}
-
-// loadSystemPrompt loads the system prompt from file
-func (m *Manager) loadSystemPrompt(filePath string) (string, error) {
-	content, err := os.ReadFile(filePath)
-	if err != nil {
-		return "", fmt.Errorf("failed to read system prompt file %s: %w", filePath, err)
-	}
-	return string(content), nil
-}
-
-// StartAgent starts an agent to process tasks in a loop
 func (m *Manager) StartAgent(agentName string, loopInterval time.Duration) error {
 	agent, exists := m.agents[agentName]
 	if !exists {
@@ -211,409 +97,28 @@
 		return fmt.Errorf("agent %s is already running", agentName)
 	}
 
-	stopChan := make(chan struct{})
-	m.stopChannels[agentName] = stopChan
+	agent.Start(loopInterval)
 	m.isRunning[agentName] = true
-
-	go m.runAgentLoop(agent, loopInterval, stopChan)
-
-	m.logger.Info("Started agent",
-		slog.String("name", agentName),
-		slog.String("role", agent.Role),
-		slog.String("model", agent.Model))
 	return nil
 }
 
 // StopAgent stops a running agent
 func (m *Manager) StopAgent(agentName string) error {
+	agent, exists := m.agents[agentName]
+	if !exists {
+		return fmt.Errorf("agent %s not found", agentName)
+	}
 	if !m.isRunning[agentName] {
 		return fmt.Errorf("agent %s is not running", agentName)
 	}
 
-	close(m.stopChannels[agentName])
-	delete(m.stopChannels, agentName)
+	agent.Stop()
 	m.isRunning[agentName] = false
 
 	m.logger.Info("Stopped agent", slog.String("name", agentName))
 	return nil
 }
 
-// runAgentLoop runs the main processing loop for an agent
-func (m *Manager) runAgentLoop(agent *Agent, interval time.Duration, stopChan <-chan struct{}) {
-	ticker := time.NewTicker(interval)
-	defer ticker.Stop()
-
-	for {
-		select {
-		case <-stopChan:
-			m.logger.Info("Agent stopping", slog.String("name", agent.Name))
-			return
-		case <-ticker.C:
-			if err := m.processAgentTasks(agent); err != nil {
-				m.logger.Error("Error processing tasks for agent",
-					slog.String("agent", agent.Name),
-					slog.String("error", err.Error()))
-			}
-		}
-	}
-}
-
-// processAgentTasks processes all assigned tasks for an agent
-func (m *Manager) processAgentTasks(agent *Agent) error {
-	if agent.CurrentTask != nil {
-		return nil
-	}
-
-	// Get tasks assigned to this agent
-	tasks, err := m.taskManager.GetTasksByAssignee(agent.Name)
-	if err != nil {
-		return fmt.Errorf("failed to get tasks for agent %s: %w", agent.Name, err)
-	}
-
-	m.logger.Info("Processing tasks for agent",
-		slog.Int("task_count", len(tasks)),
-		slog.String("agent", agent.Name))
-
-	for _, task := range tasks {
-		if task.Status == tm.StatusToDo {
-			if err := m.processTask(agent, task); err != nil {
-				m.logger.Error("Error processing task",
-					slog.String("task_id", task.ID),
-					slog.String("error", err.Error()))
-				// Mark task as failed
-				task.Status = tm.StatusFailed
-				if err := m.taskManager.UpdateTask(task); err != nil {
-					m.logger.Error("Error updating failed task",
-						slog.String("task_id", task.ID),
-						slog.String("error", err.Error()))
-				}
-				agent.Stats.TasksFailed++
-			} else {
-				agent.Stats.TasksCompleted++
-			}
-			// Update success rate
-			total := agent.Stats.TasksCompleted + agent.Stats.TasksFailed
-			if total > 0 {
-				agent.Stats.SuccessRate = float64(agent.Stats.TasksCompleted) / float64(total) * 100
-			}
-		}
-	}
-
-	return nil
-}
-
-// processTask processes a single task with an agent
-func (m *Manager) processTask(agent *Agent, task *tm.Task) error {
-	ctx := context.Background()
-	startTime := time.Now()
-
-	m.logger.Info("Agent processing task",
-		slog.String("agent", agent.Name),
-		slog.String("task_id", task.ID),
-		slog.String("title", task.Title))
-
-	// Mark task as in progress
-	task.Status = tm.StatusInProgress
-	agent.CurrentTask = &task.ID
-
-	// Check if this task should generate subtasks (with LLM decision)
-	if m.shouldGenerateSubtasks(task) {
-		m.logger.Info("LLM determined task should generate subtasks", slog.String("task_id", task.ID))
-		if err := m.generateSubtasksForTask(ctx, task); err != nil {
-			m.logger.Warn("Failed to generate subtasks for task",
-				slog.String("task_id", task.ID),
-				slog.String("error", err.Error()))
-		} else {
-			m.logger.Info("Task converted to subtasks by agent using LLM analysis",
-				slog.String("task_id", task.ID),
-				slog.String("agent", agent.Name))
-			return nil
-		}
-	}
-
-	// Generate solution using LLM
-	solution, err := m.generateSolution(ctx, agent, task)
-	if err != nil {
-		return fmt.Errorf("failed to generate solution: %w", err)
-	}
-
-	// Create Git branch and commit solution
-	branchName := m.generateBranchName(task)
-	if err := m.createAndCommitSolution(branchName, task, solution, agent); err != nil {
-		return fmt.Errorf("failed to commit solution: %w", err)
-	}
-
-	// Create pull request
-	prURL, err := m.createPullRequest(ctx, task, solution, agent, branchName)
-	if err != nil {
-		return fmt.Errorf("failed to create pull request: %w", err)
-	}
-
-	// Update agent stats
-	duration := time.Since(startTime)
-	if agent.Stats.AvgTime == 0 {
-		agent.Stats.AvgTime = duration.Milliseconds()
-	} else {
-		agent.Stats.AvgTime = (agent.Stats.AvgTime + duration.Milliseconds()) / 2
-	}
-
-	m.logger.Info("Task completed by agent",
-		slog.String("task_id", task.ID),
-		slog.String("agent", agent.Name),
-		slog.Duration("duration", duration),
-		slog.String("pr_url", prURL))
-	return nil
-}
-
-// generateSolution uses the agent's LLM to generate a solution
-func (m *Manager) generateSolution(ctx context.Context, agent *Agent, task *tm.Task) (string, error) {
-	prompt := m.buildTaskPrompt(task)
-
-	req := llm.ChatCompletionRequest{
-		Model: agent.Model,
-		Messages: []llm.Message{
-			{
-				Role:    llm.RoleSystem,
-				Content: agent.SystemPrompt,
-			},
-			{
-				Role:    llm.RoleUser,
-				Content: prompt,
-			},
-		},
-		MaxTokens:   agent.MaxTokens,
-		Temperature: agent.Temperature,
-	}
-
-	resp, err := agent.Provider.ChatCompletion(ctx, req)
-	if err != nil {
-		return "", fmt.Errorf("LLM request failed: %w", err)
-	}
-
-	if len(resp.Choices) == 0 {
-		return "", fmt.Errorf("no response from LLM")
-	}
-
-	return resp.Choices[0].Message.Content, nil
-}
-
-// buildTaskPrompt creates a detailed prompt for the LLM
-func (m *Manager) buildTaskPrompt(task *tm.Task) string {
-	return fmt.Sprintf(`Task: %s
-
-Priority: %s
-Description: %s
-
-Please provide a complete solution for this task. Include:
-1. Detailed implementation plan
-2. Code changes needed (if applicable)
-3. Files to be created or modified
-4. Testing considerations
-5. Any dependencies or prerequisites
-
-Your response should be comprehensive and actionable.`,
-		task.Title,
-		task.Priority,
-		task.Description)
-}
-
-// generateBranchName creates a Git branch name for the task
-func (m *Manager) generateBranchName(task *tm.Task) string {
-	// Clean title for use in branch name
-	cleanTitle := strings.ToLower(task.Title)
-	cleanTitle = strings.ReplaceAll(cleanTitle, " ", "-")
-	cleanTitle = strings.ReplaceAll(cleanTitle, "/", "-")
-	// Remove special characters
-	var result strings.Builder
-	for _, r := range cleanTitle {
-		if (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') || r == '-' {
-			result.WriteRune(r)
-		}
-	}
-	cleanTitle = result.String()
-
-	// Limit length
-	if len(cleanTitle) > 40 {
-		cleanTitle = cleanTitle[:40]
-	}
-
-	return fmt.Sprintf("%s%s-%s", m.config.Git.BranchPrefix, task.ID, cleanTitle)
-}
-
-// createAndCommitSolution creates a Git branch and commits the solution using per-agent clones
-func (m *Manager) createAndCommitSolution(branchName string, task *tm.Task, solution string, agent *Agent) error {
-	ctx := context.Background()
-
-	// Get agent's dedicated Git clone
-	clonePath, err := m.cloneManager.GetAgentClonePath(agent.Name)
-	if err != nil {
-		return fmt.Errorf("failed to get agent clone: %w", err)
-	}
-
-	m.logger.Info("Agent working in clone",
-		slog.String("agent", agent.Name),
-		slog.String("clone_path", clonePath))
-
-	// Refresh the clone with latest changes
-	if err := m.cloneManager.RefreshAgentClone(agent.Name); err != nil {
-		m.logger.Warn("Failed to refresh clone for agent",
-			slog.String("agent", agent.Name),
-			slog.String("error", err.Error()))
-	}
-
-	// All Git operations use the agent's clone directory
-	gitCmd := func(args ...string) *exec.Cmd {
-		return exec.CommandContext(ctx, "git", append([]string{"-C", clonePath}, args...)...)
-	}
-
-	// Ensure we're on main branch before creating new branch
-	cmd := gitCmd("checkout", "main")
-	if err := cmd.Run(); err != nil {
-		// Try master branch if main doesn't exist
-		cmd = gitCmd("checkout", "master")
-		if err := cmd.Run(); err != nil {
-			return fmt.Errorf("failed to checkout main/master branch: %w", err)
-		}
-	}
-
-	// Create branch
-	cmd = gitCmd("checkout", "-b", branchName)
-	if err := cmd.Run(); err != nil {
-		return fmt.Errorf("failed to create branch: %w", err)
-	}
-
-	// Create solution file in agent's clone
-	solutionDir := filepath.Join(clonePath, "tasks", "solutions")
-	if err := os.MkdirAll(solutionDir, 0755); err != nil {
-		return fmt.Errorf("failed to create solution directory: %w", err)
-	}
-
-	solutionFile := filepath.Join(solutionDir, fmt.Sprintf("%s-solution.md", task.ID))
-	solutionContent := fmt.Sprintf(`# Solution for Task: %s
-
-**Agent:** %s (%s)  
-**Model:** %s  
-**Completed:** %s
-
-## Task Description
-%s
-
-## Solution
-%s
-
----
-*Generated by Staff AI Agent System*
-`, task.Title, agent.Name, agent.Role, agent.Model, time.Now().Format(time.RFC3339), task.Description, solution)
-
-	if err := os.WriteFile(solutionFile, []byte(solutionContent), 0644); err != nil {
-		return fmt.Errorf("failed to write solution file: %w", err)
-	}
-
-	// Stage files
-	relativeSolutionFile := filepath.Join("tasks", "solutions", fmt.Sprintf("%s-solution.md", task.ID))
-	cmd = gitCmd("add", relativeSolutionFile)
-	if err := cmd.Run(); err != nil {
-		return fmt.Errorf("failed to stage files: %w", err)
-	}
-
-	// Commit changes
-	commitMsg := m.buildCommitMessage(task, agent)
-	cmd = gitCmd("commit", "-m", commitMsg)
-	if err := cmd.Run(); err != nil {
-		return fmt.Errorf("failed to commit: %w", err)
-	}
-
-	// Push branch
-	cmd = gitCmd("push", "-u", "origin", branchName)
-	if err := cmd.Run(); err != nil {
-		return fmt.Errorf("failed to push branch: %w", err)
-	}
-
-	m.logger.Info("Agent successfully pushed branch",
-		slog.String("agent", agent.Name),
-		slog.String("branch", branchName))
-	return nil
-}
-
-// buildCommitMessage creates a commit message from template
-func (m *Manager) buildCommitMessage(task *tm.Task, agent *Agent) string {
-	template := m.config.Git.CommitMessageTemplate
-
-	replacements := map[string]string{
-		"{task_id}":    task.ID,
-		"{task_title}": task.Title,
-		"{agent_name}": agent.Name,
-		"{solution}":   "See solution file for details",
-	}
-
-	result := template
-	for placeholder, value := range replacements {
-		result = strings.ReplaceAll(result, placeholder, value)
-	}
-
-	return result
-}
-
-// createPullRequest creates a GitHub pull request
-func (m *Manager) createPullRequest(ctx context.Context, task *tm.Task, solution string, agent *Agent, branchName string) (string, error) {
-	title := fmt.Sprintf("Task %s: %s", task.ID, task.Title)
-
-	// Build PR description from template
-	description := m.buildPRDescription(task, solution, agent)
-
-	options := git.PullRequestOptions{
-		Title:       title,
-		Description: description,
-		HeadBranch:  branchName,
-		BaseBranch:  "main",
-		Labels:      []string{"ai-generated", "staff-agent", strings.ToLower(agent.Role)},
-		Draft:       false,
-	}
-
-	pr, err := m.prProvider.CreatePullRequest(ctx, options)
-	if err != nil {
-		return "", fmt.Errorf("failed to create PR: %w", err)
-	}
-
-	// Generate provider-specific PR URL
-	switch m.config.GetPrimaryGitProvider() {
-	case "github":
-		return fmt.Sprintf("https://github.com/%s/%s/pull/%d", m.config.GitHub.Owner, m.config.GitHub.Repo, pr.Number), nil
-	case "gerrit":
-		return fmt.Sprintf("%s/c/%s/+/%d", m.config.Gerrit.BaseURL, m.config.Gerrit.Project, pr.Number), nil
-	default:
-		return "", fmt.Errorf("unknown git provider")
-	}
-}
-
-// buildPRDescription creates PR description from template
-func (m *Manager) buildPRDescription(task *tm.Task, solution string, agent *Agent) string {
-	template := m.config.Git.PRTemplate
-
-	// Truncate solution for PR if too long
-	truncatedSolution := solution
-	if len(solution) > 1000 {
-		truncatedSolution = solution[:1000] + "...\n\n*See solution file for complete details*"
-	}
-
-	replacements := map[string]string{
-		"{task_id}":          task.ID,
-		"{task_title}":       task.Title,
-		"{task_description}": task.Description,
-		"{agent_name}":       fmt.Sprintf("%s (%s)", agent.Name, agent.Role),
-		"{priority}":         string(task.Priority),
-		"{solution}":         truncatedSolution,
-		"{files_changed}":    fmt.Sprintf("- `tasks/solutions/%s-solution.md`", task.ID),
-	}
-
-	result := template
-	for placeholder, value := range replacements {
-		result = strings.ReplaceAll(result, placeholder, value)
-	}
-
-	return result
-}
-
 // AutoAssignTask automatically assigns a task to the best matching agent
 func (m *Manager) AutoAssignTask(taskID string) error {
 	task, err := m.taskManager.GetTask(taskID)
@@ -640,108 +145,6 @@
 	return nil
 }
 
-// GetAgentStatus returns the status of all agents
-func (m *Manager) GetAgentStatus() map[string]AgentInfo {
-	status := make(map[string]AgentInfo)
-
-	for name, agent := range m.agents {
-		agentStatus := StatusIdle
-		if m.isRunning[name] {
-			if agent.CurrentTask != nil {
-				agentStatus = StatusRunning
-			}
-		} else {
-			agentStatus = StatusStopped
-		}
-
-		status[name] = AgentInfo{
-			Name:        agent.Name,
-			Role:        agent.Role,
-			Model:       agent.Model,
-			Status:      agentStatus,
-			CurrentTask: agent.CurrentTask,
-			Stats:       agent.Stats,
-		}
-	}
-
-	return status
-}
-
-// 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 evaluated
-	if task.SubtasksEvaluated {
-		return false
-	}
-
-	// Ask LLM to decide
-	ctx := context.Background()
-	decision, err := m.subtaskService.ShouldGenerateSubtasks(ctx, task)
-	if err != nil {
-		m.logger.Warn("Failed to get LLM subtask decision for task",
-			slog.String("task_id", task.ID),
-			slog.String("error", err.Error()))
-		// Fallback to simple heuristics
-		return task.Priority == tm.PriorityHigh || len(task.Description) > 200
-	}
-
-	task.SubtasksEvaluated = true
-	m.logger.Info("LLM subtask decision for task",
-		slog.String("task_id", task.ID),
-		slog.Bool("needs_subtasks", decision.NeedsSubtasks),
-		slog.Int("complexity_score", decision.ComplexityScore),
-		slog.String("reasoning", decision.Reasoning))
-
-	return decision.NeedsSubtasks
-}
-
-// generateSubtasksForTask analyzes a task and creates a PR with proposed subtasks
-func (m *Manager) generateSubtasksForTask(ctx context.Context, task *tm.Task) error {
-	if m.subtaskService == nil {
-		return fmt.Errorf("subtask service not initialized")
-	}
-
-	// Analyze the task for subtasks
-	analysis, err := m.subtaskService.AnalyzeTaskForSubtasks(ctx, task)
-	if err != nil {
-		return fmt.Errorf("failed to analyze task for subtasks: %w", err)
-	}
-
-	// Generate a PR with the subtask proposals
-	prURL, err := m.subtaskService.GenerateSubtaskPR(ctx, analysis)
-	if err != nil {
-		return fmt.Errorf("failed to generate subtask PR: %w", err)
-	}
-
-	// Update the task with subtask information
-	task.SubtasksPRURL = prURL
-	task.SubtasksGenerated = true
-
-	m.logger.Info("Generated subtask PR for task",
-		slog.String("task_id", task.ID),
-		slog.String("pr_url", prURL))
-	m.logger.Info("Proposed subtasks and new agents for task",
-		slog.String("task_id", task.ID),
-		slog.Int("subtask_count", len(analysis.Subtasks)),
-		slog.Int("new_agent_count", len(analysis.AgentCreations)))
-
-	// Log proposed new agents if any
-	if len(analysis.AgentCreations) > 0 {
-		for _, agent := range analysis.AgentCreations {
-			m.logger.Info("Proposed new agent",
-				slog.String("role", agent.Role),
-				slog.Any("skills", agent.Skills))
-		}
-	}
-
-	return nil
-}
-
 // IsAgentRunning checks if an agent is currently running
 func (m *Manager) IsAgentRunning(agentName string) bool {
 	return m.isRunning[agentName]
@@ -764,18 +167,5 @@
 				slog.String("error", err.Error()))
 		}
 	}
-
-	// Cleanup all agent Git clones
-	if err := m.cloneManager.CleanupAllClones(); err != nil {
-		m.logger.Error("Error cleaning up agent clones", slog.String("error", err.Error()))
-	}
-
-	// Cleanup subtask service
-	if m.subtaskService != nil {
-		if err := m.subtaskService.Close(); err != nil {
-			m.logger.Error("Error closing subtask service", slog.String("error", err.Error()))
-		}
-	}
-
 	return nil
 }