Refactor everything

Change-Id: Ic3a37c38cfecba943c91f6ae545ce1c5b551c0d5
diff --git a/server/git/CONCURRENCY_README.md b/server/git/CONCURRENCY_README.md
deleted file mode 100644
index 1cbe184..0000000
--- a/server/git/CONCURRENCY_README.md
+++ /dev/null
@@ -1,172 +0,0 @@
-# Git Concurrency Solution: Per-Agent Repository Clones
-
-## Problem Statement
-
-Git is not thread-safe, which creates critical race conditions when multiple AI agents try to perform Git operations concurrently:
-
-- **Repository Corruption**: Multiple agents modifying the same `.git` folder simultaneously
-- **Branch Conflicts**: Agents creating branches with the same names or overwriting each other's work  
-- **Push Failures**: Concurrent pushes causing merge conflicts and failed operations
-- **Index Lock Errors**: Git index.lock conflicts when multiple processes access the repository
-
-## Solution: Per-Agent Git Clones
-
-Instead of using mutexes (which would serialize all Git operations and hurt performance), we give each agent its own Git repository clone:
-
-```
-workspace/
-├── agent-backend-engineer/     # Backend engineer's clone
-│   ├── .git/
-│   ├── tasks/
-│   └── ...
-├── agent-frontend-engineer/    # Frontend engineer's clone  
-│   ├── .git/
-│   ├── tasks/
-│   └── ...
-└── agent-qa-engineer/         # QA engineer's clone
-    ├── .git/
-    ├── tasks/
-    └── ...
-```
-
-## Key Benefits
-
-### 🚀 **True Concurrency**
-- Multiple agents can work simultaneously without blocking each other
-- No waiting for Git lock releases
-- Scales to hundreds of concurrent agents
-
-### 🛡️ **Complete Isolation** 
-- Each agent has its own `.git` directory and working tree
-- No shared state or race conditions
-- Agent failures don't affect other agents
-
-### 🔄 **Automatic Synchronization**
-- Each clone automatically pulls latest changes before creating branches
-- All branches push to the same remote repository
-- PRs are created against the main repository
-
-### 🧹 **Easy Cleanup**
-- `staff cleanup-clones` removes all agent workspaces
-- Clones are recreated on-demand when agents start working
-- No manual Git state management required
-
-## Implementation Details
-
-### CloneManager (`git/clone_manager.go`)
-
-```go
-type CloneManager struct {
-    baseRepoURL    string                // Source repository URL
-    workspacePath  string                // Base workspace directory  
-    agentClones    map[string]string     // agent name -> clone path
-    mu             sync.RWMutex          // Thread-safe map access
-}
-```
-
-**Key Methods:**
-- `GetAgentClonePath(agentName)` - Get/create agent's clone directory
-- `RefreshAgentClone(agentName)` - Pull latest changes for an agent
-- `CleanupAgentClone(agentName)` - Remove specific agent's clone
-- `CleanupAllClones()` - Remove all agent clones
-
-### Agent Integration
-
-Each agent's Git operations are automatically routed to its dedicated clone:
-
-```go
-// Get agent's dedicated Git clone
-clonePath, err := am.cloneManager.GetAgentClonePath(agent.Name)
-if err != nil {
-    return fmt.Errorf("failed to get agent clone: %w", err)
-}
-
-// 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...)...)
-}
-```
-
-## Workflow Example
-
-1. **Agent Starts Task**:
-   ```bash
-   Agent backend-engineer gets task: "Add user authentication"
-   Creating clone: workspace/agent-backend-engineer/
-   ```
-
-2. **Concurrent Operations**:
-   ```bash
-   # These happen simultaneously without conflicts:
-   Agent backend-engineer:  git clone -> workspace/agent-backend-engineer/
-   Agent frontend-engineer: git clone -> workspace/agent-frontend-engineer/  
-   Agent qa-engineer:       git clone -> workspace/agent-qa-engineer/
-   ```
-
-3. **Branch Creation**:
-   ```bash
-   # Each agent creates branches in their own clone:
-   backend-engineer:  git checkout -b task-123-auth-backend
-   frontend-engineer: git checkout -b task-124-auth-ui
-   qa-engineer:      git checkout -b task-125-auth-tests
-   ```
-
-4. **Concurrent Pushes**:
-   ```bash
-   # All agents push to origin simultaneously:
-   git push -u origin task-123-auth-backend    # ✅ Success
-   git push -u origin task-124-auth-ui         # ✅ Success  
-   git push -u origin task-125-auth-tests      # ✅ Success
-   ```
-
-## Management Commands
-
-### List Agent Clones
-```bash
-staff list-agents  # Shows which agents are running and their clone status
-```
-
-### Cleanup All Clones
-```bash
-staff cleanup-clones  # Removes all agent workspace directories
-```
-
-### Monitor Disk Usage
-```bash
-du -sh workspace/  # Check total workspace disk usage
-```
-
-## Resource Considerations
-
-### Disk Space
-- Each clone uses ~repository size (typically 10-100MB per agent)
-- For 10 agents with 50MB repo = ~500MB total
-- Use `staff cleanup-clones` to free space when needed
-
-### Network Usage
-- Initial clone downloads full repository
-- Subsequent `git pull` operations are incremental
-- All agents share the same remote repository
-
-### Performance
-- Clone creation: ~2-5 seconds per agent (one-time cost)
-- Git operations: Full speed, no waiting for locks
-- Parallel processing: Linear scalability with agent count
-
-## Comparison to Alternatives
-
-| Solution | Concurrency | Complexity | Performance | Risk |
-|----------|-------------|------------|-------------|------|
-| **Per-Agent Clones** | ✅ Full | 🟡 Medium | ✅ High | 🟢 Low |
-| Global Git Mutex | ❌ None | 🟢 Low | ❌ Poor | 🟡 Medium |
-| File Locking | 🟡 Limited | 🔴 High | 🟡 Medium | 🔴 High |
-| Separate Repositories | ✅ Full | 🔴 Very High | ✅ High | 🔴 High |
-
-## Future Enhancements
-
-- **Lazy Cleanup**: Auto-remove unused clones after N days
-- **Clone Sharing**: Share clones between agents with similar tasks
-- **Compressed Clones**: Use `git clone --depth=1` for space efficiency
-- **Remote Workspaces**: Support for distributed agent execution
-
-The per-agent clone solution provides the optimal balance of performance, safety, and maintainability for concurrent AI agent operations.
\ No newline at end of file
diff --git a/server/git/PULL_REQUEST_README.md b/server/git/PULL_REQUEST_README.md
deleted file mode 100644
index b6664f2..0000000
--- a/server/git/PULL_REQUEST_README.md
+++ /dev/null
@@ -1,323 +0,0 @@
-# Pull Request Capabilities
-
-This package now includes comprehensive pull request (PR) capabilities that support both GitHub and Gerrit platforms. The implementation provides a unified interface for managing pull requests across different code hosting platforms.
-
-## Features
-
-- **Unified Interface**: Same API for both GitHub and Gerrit
-- **Full CRUD Operations**: Create, read, update, delete pull requests
-- **Advanced Filtering**: List pull requests with various filters
-- **Merge Operations**: Support for different merge strategies
-- **Error Handling**: Comprehensive error handling with detailed messages
-- **Authentication**: Support for token-based and basic authentication
-
-## Supported Platforms
-
-### GitHub
-- Uses GitHub REST API v3
-- Supports personal access tokens for authentication
-- Full support for all pull request operations
-- Handles GitHub-specific features like draft PRs, labels, assignees, and reviewers
-
-### Gerrit
-- Uses Gerrit REST API
-- Supports HTTP password or API token authentication
-- Maps Gerrit "changes" to pull requests
-- Handles Gerrit-specific features like topics and review workflows
-
-## Quick Start
-
-### GitHub Example
-
-```go
-package main
-
-import (
-    "context"
-    "github.com/iomodo/staff/git"
-    "net/http"
-    "time"
-)
-
-func main() {
-    ctx := context.Background()
-    
-    // Create GitHub configuration
-    githubConfig := git.GitHubConfig{
-        Token: "your-github-token",
-        BaseURL: "https://api.github.com",
-        HTTPClient: &http.Client{Timeout: 30 * time.Second},
-    }
-    
-    // Create GitHub provider
-    githubProvider := git.NewGitHubPullRequestProvider("owner", "repo", githubConfig)
-    
-    // Create Git instance with pull request capabilities
-    git := git.NewGitWithPullRequests("/path/to/repo", git.GitConfig{}, githubProvider)
-    
-    // Create a pull request
-    prOptions := git.PullRequestOptions{
-        Title:       "Add new feature",
-        Description: "This PR adds a new feature to the application.",
-        BaseBranch:  "main",
-        HeadBranch:  "feature/new-feature",
-        Labels:      []string{"enhancement", "feature"},
-        Assignees:   []string{"username1", "username2"},
-        Reviewers:   []string{"reviewer1", "reviewer2"},
-        Draft:       false,
-    }
-    
-    pr, err := git.CreatePullRequest(ctx, prOptions)
-    if err != nil {
-        log.Fatal(err)
-    }
-    
-    fmt.Printf("Created pull request: %s (#%d)\n", pr.Title, pr.Number)
-}
-```
-
-### Gerrit Example
-
-```go
-package main
-
-import (
-    "context"
-    "github.com/iomodo/staff/git"
-    "net/http"
-    "time"
-)
-
-func main() {
-    ctx := context.Background()
-    
-    // Create Gerrit configuration
-    gerritConfig := git.GerritConfig{
-        Username: "your-username",
-        Password: "your-http-password-or-api-token",
-        BaseURL:  "https://gerrit.example.com",
-        HTTPClient: &http.Client{Timeout: 30 * time.Second},
-    }
-    
-    // Create Gerrit provider
-    gerritProvider := git.NewGerritPullRequestProvider("project-name", gerritConfig)
-    
-    // Create Git instance with pull request capabilities
-    git := git.NewGitWithPullRequests("/path/to/repo", git.GitConfig{}, gerritProvider)
-    
-    // Create a change (pull request)
-    prOptions := git.PullRequestOptions{
-        Title:       "Add new feature",
-        Description: "This change adds a new feature to the application.",
-        BaseBranch:  "master",
-        HeadBranch:  "feature/new-feature",
-    }
-    
-    pr, err := git.CreatePullRequest(ctx, prOptions)
-    if err != nil {
-        log.Fatal(err)
-    }
-    
-    fmt.Printf("Created change: %s (#%d)\n", pr.Title, pr.Number)
-}
-```
-
-## API Reference
-
-### Types
-
-#### PullRequest
-Represents a pull request or merge request across platforms.
-
-```go
-type PullRequest struct {
-    ID          string
-    Number      int
-    Title       string
-    Description string
-    State       string // "open", "closed", "merged"
-    Author      Author
-    CreatedAt   time.Time
-    UpdatedAt   time.Time
-    BaseBranch  string
-    HeadBranch  string
-    BaseRepo    string
-    HeadRepo    string
-    Labels      []string
-    Assignees   []Author
-    Reviewers   []Author
-    Commits     []Commit
-    Comments    []PullRequestComment
-}
-```
-
-#### PullRequestOptions
-Options for creating or updating pull requests.
-
-```go
-type PullRequestOptions struct {
-    Title       string
-    Description string
-    BaseBranch  string
-    HeadBranch  string
-    BaseRepo    string
-    HeadRepo    string
-    Labels      []string
-    Assignees   []string
-    Reviewers   []string
-    Draft       bool
-}
-```
-
-#### ListPullRequestOptions
-Options for listing pull requests.
-
-```go
-type ListPullRequestOptions struct {
-    State      string // "open", "closed", "all"
-    Author     string
-    Assignee   string
-    BaseBranch string
-    HeadBranch string
-    Labels     []string
-    Limit      int
-}
-```
-
-#### MergePullRequestOptions
-Options for merging pull requests.
-
-```go
-type MergePullRequestOptions struct {
-    MergeMethod string // "merge", "squash", "rebase"
-    CommitTitle string
-    CommitMsg   string
-}
-```
-
-### Methods
-
-#### CreatePullRequest
-Creates a new pull request.
-
-```go
-func (g *Git) CreatePullRequest(ctx context.Context, options PullRequestOptions) (*PullRequest, error)
-```
-
-#### GetPullRequest
-Retrieves a pull request by ID.
-
-```go
-func (g *Git) GetPullRequest(ctx context.Context, id string) (*PullRequest, error)
-```
-
-#### ListPullRequests
-Lists pull requests with optional filtering.
-
-```go
-func (g *Git) ListPullRequests(ctx context.Context, options ListPullRequestOptions) ([]PullRequest, error)
-```
-
-#### UpdatePullRequest
-Updates an existing pull request.
-
-```go
-func (g *Git) UpdatePullRequest(ctx context.Context, id string, options PullRequestOptions) (*PullRequest, error)
-```
-
-#### ClosePullRequest
-Closes a pull request.
-
-```go
-func (g *Git) ClosePullRequest(ctx context.Context, id string) error
-```
-
-#### MergePullRequest
-Merges a pull request.
-
-```go
-func (g *Git) MergePullRequest(ctx context.Context, id string, options MergePullRequestOptions) error
-```
-
-## Configuration
-
-### GitHub Configuration
-
-```go
-type GitHubConfig struct {
-    Token      string        // GitHub personal access token
-    BaseURL    string        // GitHub API base URL (default: https://api.github.com)
-    HTTPClient *http.Client  // Custom HTTP client (optional)
-}
-```
-
-### Gerrit Configuration
-
-```go
-type GerritConfig struct {
-    Username    string        // Gerrit username
-    Password    string        // HTTP password or API token
-    BaseURL     string        // Gerrit instance URL
-    HTTPClient  *http.Client  // Custom HTTP client (optional)
-}
-```
-
-## Error Handling
-
-All pull request operations return detailed error information through the `GitError` type:
-
-```go
-type GitError struct {
-    Command string
-    Output  string
-    Err     error
-}
-```
-
-Common error scenarios:
-- Authentication failures
-- Invalid repository or project names
-- Network connectivity issues
-- API rate limiting
-- Invalid pull request data
-
-## Platform-Specific Notes
-
-### GitHub
-- Requires a personal access token with appropriate permissions
-- Supports draft pull requests
-- Full support for labels, assignees, and reviewers
-- Uses GitHub's REST API v3
-
-### Gerrit
-- Requires HTTP password or API token
-- Uses "changes" instead of "pull requests"
-- Topics are used to group related changes
-- Review workflow is more structured
-- Uses Gerrit's REST API
-
-## Examples
-
-See `pull_request_example.go` for comprehensive examples of using both GitHub and Gerrit providers.
-
-## Testing
-
-Run the tests to ensure everything works correctly:
-
-```bash
-go test ./git/... -v
-```
-
-## Contributing
-
-When adding support for new platforms:
-
-1. Implement the `PullRequestProvider` interface
-2. Add platform-specific configuration types
-3. Create conversion functions to map platform-specific data to our unified types
-4. Add comprehensive tests
-5. Update this documentation
-
-## License
-
-This code is part of the staff project and follows the same licensing terms. 
\ No newline at end of file
diff --git a/server/git/README.md b/server/git/README.md
deleted file mode 100644
index 18ccc1f..0000000
--- a/server/git/README.md
+++ /dev/null
@@ -1,331 +0,0 @@
-# Git Interface for Go
-
-A comprehensive Go interface for Git operations that provides a clean, type-safe API for interacting with Git repositories.
-
-## Features
-
-- **Complete Git Operations**: Supports all major Git operations including repository management, commits, branches, remotes, tags, and more
-- **Type-Safe API**: Strongly typed interfaces and structs for better code safety
-- **Context Support**: All operations support context for cancellation and timeouts
-- **Error Handling**: Comprehensive error handling with detailed error messages
-- **Flexible Configuration**: Configurable timeouts and environment variables
-- **Easy to Use**: Simple and intuitive API design
-
-## Installation
-
-The Git interface is part of the `github.com/iomodo/staff` module. No additional dependencies are required beyond the standard library.
-
-## Quick Start
-
-```go
-package main
-
-import (
-    "context"
-    "fmt"
-    "log"
-    
-    "github.com/iomodo/staff/git"
-)
-
-func main() {
-    ctx := context.Background()
-    
-    // Create a Git instance
-    git := git.DefaultGit("/path/to/your/repo")
-    
-    // Open an existing repository
-    if err := git.Open(ctx, "/path/to/your/repo"); err != nil {
-        log.Fatalf("Failed to open repository: %v", err)
-    }
-    
-    // Get repository status
-    status, err := git.Status(ctx)
-    if err != nil {
-        log.Fatalf("Failed to get status: %v", err)
-    }
-    
-    fmt.Printf("Current branch: %s\n", status.Branch)
-    fmt.Printf("Repository is clean: %t\n", status.IsClean)
-}
-```
-
-## Core Interface
-
-### GitInterface
-
-The main interface that defines all Git operations:
-
-```go
-type GitInterface interface {
-    // Repository operations
-    Init(ctx context.Context, path string) error
-    Clone(ctx context.Context, url, path string) error
-    IsRepository(ctx context.Context, path string) (bool, error)
-    
-    // Status and information
-    Status(ctx context.Context) (*Status, error)
-    Log(ctx context.Context, options LogOptions) ([]Commit, error)
-    Show(ctx context.Context, ref string) (*Commit, error)
-    
-    // Branch operations
-    ListBranches(ctx context.Context) ([]Branch, error)
-    CreateBranch(ctx context.Context, name string, startPoint string) error
-    Checkout(ctx context.Context, ref string) error
-    DeleteBranch(ctx context.Context, name string, force bool) error
-    GetCurrentBranch(ctx context.Context) (string, error)
-    
-    // Commit operations
-    Add(ctx context.Context, paths []string) error
-    AddAll(ctx context.Context) error
-    Commit(ctx context.Context, message string, options CommitOptions) error
-    
-    // Remote operations
-    ListRemotes(ctx context.Context) ([]Remote, error)
-    AddRemote(ctx context.Context, name, url string) error
-    RemoveRemote(ctx context.Context, name string) error
-    Fetch(ctx context.Context, remote string, options FetchOptions) error
-    Pull(ctx context.Context, remote, branch string) error
-    Push(ctx context.Context, remote, branch string, options PushOptions) error
-    
-    // Merge operations
-    Merge(ctx context.Context, ref string, options MergeOptions) error
-    MergeBase(ctx context.Context, ref1, ref2 string) (string, error)
-    
-    // Configuration
-    GetConfig(ctx context.Context, key string) (string, error)
-    SetConfig(ctx context.Context, key, value string) error
-    GetUserConfig(ctx context.Context) (*UserConfig, error)
-    SetUserConfig(ctx context.Context, config UserConfig) error
-}
-```
-
-## Data Structures
-
-### Status
-
-Represents the current state of the repository:
-
-```go
-type Status struct {
-    Branch     string
-    IsClean    bool
-    Staged     []FileStatus
-    Unstaged   []FileStatus
-    Untracked  []string
-    Conflicts  []string
-}
-```
-
-### Commit
-
-Represents a Git commit:
-
-```go
-type Commit struct {
-    Hash      string
-    Author    Author
-    Committer Author
-    Message   string
-    Parents   []string
-    Timestamp time.Time
-    Files     []CommitFile
-}
-```
-
-### Branch
-
-Represents a Git branch:
-
-```go
-type Branch struct {
-    Name      string
-    IsCurrent bool
-    IsRemote  bool
-    Commit    string
-    Message   string
-}
-```
-
-## Usage Examples
-
-### Repository Management
-
-```go
-// Initialize a new repository
-git := git.DefaultGit("/path/to/new/repo")
-if err := git.Init(ctx, "/path/to/new/repo"); err != nil {
-    log.Fatal(err)
-}
-
-// Clone a repository
-if err := git.Clone(ctx, "https://github.com/user/repo.git", "/path/to/clone"); err != nil {
-    log.Fatal(err)
-}
-```
-
-### Basic Git Workflow
-
-```go
-// Stage files
-if err := git.Add(ctx, []string{"file1.txt", "file2.txt"}); err != nil {
-    log.Fatal(err)
-}
-
-// Or stage all changes
-if err := git.AddAll(ctx); err != nil {
-    log.Fatal(err)
-}
-
-// Commit changes
-commitOptions := git.CommitOptions{
-    AllowEmpty: false,
-}
-if err := git.Commit(ctx, "Add new feature", commitOptions); err != nil {
-    log.Fatal(err)
-}
-```
-
-### Branch Operations
-
-```go
-// List all branches
-branches, err := git.ListBranches(ctx)
-if err != nil {
-    log.Fatal(err)
-}
-
-for _, branch := range branches {
-    fmt.Printf("Branch: %s (current: %t)\n", branch.Name, branch.IsCurrent)
-}
-
-// Create a new branch
-if err := git.CreateBranch(ctx, "feature/new-feature", ""); err != nil {
-    log.Fatal(err)
-}
-
-// Switch to a branch
-if err := git.Checkout(ctx, "feature/new-feature"); err != nil {
-    log.Fatal(err)
-}
-
-// Get current branch
-currentBranch, err := git.GetCurrentBranch(ctx)
-if err != nil {
-    log.Fatal(err)
-}
-fmt.Printf("Current branch: %s\n", currentBranch)
-```
-
-### Remote Operations
-
-```go
-// Add a remote
-if err := git.AddRemote(ctx, "origin", "https://github.com/user/repo.git"); err != nil {
-    log.Fatal(err)
-}
-
-// List remotes
-remotes, err := git.ListRemotes(ctx)
-if err != nil {
-    log.Fatal(err)
-}
-
-for _, remote := range remotes {
-    fmt.Printf("Remote: %s -> %s\n", remote.Name, remote.URL)
-}
-
-// Fetch from remote
-fetchOptions := git.FetchOptions{
-    All:  true,
-    Tags: true,
-}
-if err := git.Fetch(ctx, "", fetchOptions); err != nil {
-    log.Fatal(err)
-}
-
-// Push to remote
-pushOptions := git.PushOptions{
-    SetUpstream: true,
-}
-if err := git.Push(ctx, "origin", "main", pushOptions); err != nil {
-    log.Fatal(err)
-}
-```
-
-### Configuration
-
-```go
-// Get user configuration
-userConfig, err := git.GetUserConfig(ctx)
-if err != nil {
-    log.Fatal(err)
-}
-fmt.Printf("User: %s <%s>\n", userConfig.Name, userConfig.Email)
-
-// Set user configuration
-newConfig := git.UserConfig{
-    Name:  "John Doe",
-    Email: "john@example.com",
-}
-if err := git.SetUserConfig(ctx, newConfig); err != nil {
-    log.Fatal(err)
-}
-
-// Get/set custom config
-value, err := git.GetConfig(ctx, "core.editor")
-if err != nil {
-    log.Fatal(err)
-}
-
-if err := git.SetConfig(ctx, "core.editor", "vim"); err != nil {
-    log.Fatal(err)
-}
-```
-
-## Error Handling
-
-The Git interface provides detailed error information through the `GitError` type:
-
-```go
-if err := git.Commit(ctx, "Invalid commit", git.CommitOptions{}); err != nil {
-    if gitErr, ok := err.(*git.GitError); ok {
-        fmt.Printf("Git command '%s' failed: %v\n", gitErr.Command, gitErr.Err)
-        fmt.Printf("Output: %s\n", gitErr.Output)
-    }
-}
-```
-
-## Configuration
-
-You can customize the Git instance with specific configuration:
-
-```go
-config := git.GitConfig{
-    Timeout: 60 * time.Second,
-    Env: map[string]string{
-        "GIT_AUTHOR_NAME":  "Custom Author",
-        "GIT_AUTHOR_EMAIL": "author@example.com",
-    },
-}
-
-git := git.NewGit("/path/to/repo", config)
-```
-
-## Thread Safety
-
-The Git interface is not thread-safe. If you need to use it from multiple goroutines, you should either:
-
-1. Use separate Git instances for each goroutine
-2. Use a mutex to synchronize access
-3. Use channels to serialize operations
-
-## Requirements
-
-- Go 1.24.4 or later
-- Git installed and available in PATH
-- Appropriate permissions to access the repository
-
-## License
-
-This code is part of the `github.com/iomodo/staff` project and follows the same license terms. 
\ No newline at end of file
diff --git a/server/git/clone_manager.go b/server/git/clone_manager.go
index 7bc9cde..33a5a99 100644
--- a/server/git/clone_manager.go
+++ b/server/git/clone_manager.go
@@ -144,17 +144,3 @@
 
 	return nil
 }
-
-// GetAllAgentClones returns a map of all agent clones
-func (cm *CloneManager) GetAllAgentClones() map[string]string {
-	cm.mu.RLock()
-	defer cm.mu.RUnlock()
-
-	// Return a copy to avoid race conditions
-	result := make(map[string]string)
-	for agent, path := range cm.agentClones {
-		result[agent] = path
-	}
-
-	return result
-}
diff --git a/server/git/example.go b/server/git/example.go
deleted file mode 100644
index 1bea27c..0000000
--- a/server/git/example.go
+++ /dev/null
@@ -1,170 +0,0 @@
-package git
-
-import (
-	"context"
-	"log/slog"
-	"os"
-)
-
-// Example demonstrates how to use the Git interface
-func Example() {
-	ctx := context.Background()
-
-	// Create logger
-	logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))
-
-	// Create a new Git instance
-	git := DefaultGit("/path/to/your/repo")
-
-	// Get repository status
-	status, err := git.Status(ctx)
-	if err != nil {
-		logger.Error("Failed to get status", slog.String("error", err.Error()))
-		os.Exit(1)
-	}
-
-	logger.Info("Repository status", slog.String("branch", status.Branch), slog.Bool("clean", status.IsClean))
-
-	// List branches
-	branches, err := git.ListBranches(ctx)
-	if err != nil {
-		logger.Error("Failed to list branches", slog.String("error", err.Error()))
-		os.Exit(1)
-	}
-
-	logger.Info("Branches found", slog.Int("count", len(branches)))
-	for _, branch := range branches {
-		current := ""
-		if branch.IsCurrent {
-			current = " (current)"
-		}
-		logger.Info("Branch", slog.String("name", branch.Name+current))
-	}
-
-	// Get recent commits
-	logOptions := LogOptions{
-		MaxCount: 5,
-		Oneline:  true,
-	}
-
-	commits, err := git.Log(ctx, logOptions)
-	if err != nil {
-		logger.Error("Failed to get log", slog.String("error", err.Error()))
-		os.Exit(1)
-	}
-
-	logger.Info("Recent commits", slog.Int("count", len(commits)))
-	for _, commit := range commits {
-		logger.Info("Commit", slog.String("hash", commit.Hash[:8]), slog.String("message", commit.Message))
-	}
-}
-
-// ExampleWorkflow demonstrates a typical Git workflow
-func ExampleWorkflow() {
-	ctx := context.Background()
-
-	// Create logger
-	logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))
-
-	// Initialize a new repository
-	git := DefaultGit("/path/to/new/repo")
-
-	// Initialize the repository
-	if err := git.Init(ctx, "/path/to/new/repo"); err != nil {
-		logger.Error("Failed to initialize repository", slog.String("error", err.Error()))
-		os.Exit(1)
-	}
-
-	// Set user configuration
-	userConfig := UserConfig{
-		Name:  "John Doe",
-		Email: "john@example.com",
-	}
-
-	if err := git.SetUserConfig(ctx, userConfig); err != nil {
-		logger.Error("Failed to set user config", slog.String("error", err.Error()))
-		os.Exit(1)
-	}
-
-	// Create a new file and add it
-	// (In a real scenario, you would create the file here)
-
-	// Stage all changes
-	if err := git.AddAll(ctx); err != nil {
-		logger.Error("Failed to add files", slog.String("error", err.Error()))
-		os.Exit(1)
-	}
-
-	// Commit the changes
-	commitOptions := CommitOptions{
-		AllowEmpty: false,
-	}
-
-	if err := git.Commit(ctx, "Initial commit", commitOptions); err != nil {
-		logger.Error("Failed to commit", slog.String("error", err.Error()))
-		os.Exit(1)
-	}
-
-	// Create a new branch
-	if err := git.CreateBranch(ctx, "feature/new-feature", ""); err != nil {
-		logger.Error("Failed to create branch", slog.String("error", err.Error()))
-		os.Exit(1)
-	}
-
-	// Switch to the new branch
-	if err := git.Checkout(ctx, "feature/new-feature"); err != nil {
-		logger.Error("Failed to checkout branch", slog.String("error", err.Error()))
-		os.Exit(1)
-	}
-
-	logger.Info("Repository initialized and feature branch created!")
-}
-
-// ExampleRemoteOperations demonstrates remote repository operations
-func ExampleRemoteOperations() {
-	ctx := context.Background()
-
-	// Create logger
-	logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))
-
-	git := DefaultGit("/path/to/your/repo")
-
-	// Add a remote
-	if err := git.AddRemote(ctx, "origin", "https://github.com/user/repo.git"); err != nil {
-		logger.Error("Failed to add remote", slog.String("error", err.Error()))
-		os.Exit(1)
-	}
-
-	// List remotes
-	remotes, err := git.ListRemotes(ctx)
-	if err != nil {
-		logger.Error("Failed to list remotes", slog.String("error", err.Error()))
-		os.Exit(1)
-	}
-
-	logger.Info("Remotes found", slog.Int("count", len(remotes)))
-	for _, remote := range remotes {
-		logger.Info("Remote", slog.String("name", remote.Name), slog.String("url", remote.URL))
-	}
-
-	// Fetch from remote
-	fetchOptions := FetchOptions{
-		All:  true,
-		Tags: true,
-	}
-
-	if err := git.Fetch(ctx, "", fetchOptions); err != nil {
-		logger.Error("Failed to fetch", slog.String("error", err.Error()))
-		os.Exit(1)
-	}
-
-	// Push to remote
-	pushOptions := PushOptions{
-		SetUpstream: true,
-	}
-
-	if err := git.Push(ctx, "origin", "main", pushOptions); err != nil {
-		logger.Error("Failed to push", slog.String("error", err.Error()))
-		os.Exit(1)
-	}
-}
diff --git a/server/git/git.go b/server/git/git.go
index 7e7ba44..1160d0d 100644
--- a/server/git/git.go
+++ b/server/git/git.go
@@ -10,6 +10,8 @@
 	"strconv"
 	"strings"
 	"time"
+
+	"github.com/iomodo/staff/config"
 )
 
 // GitInterface defines the contract for Git operations
@@ -61,6 +63,12 @@
 	UpdatePullRequest(ctx context.Context, id string, options PullRequestOptions) (*PullRequest, error)
 	ClosePullRequest(ctx context.Context, id string) error
 	MergePullRequest(ctx context.Context, id string, options MergePullRequestOptions) error
+
+	// Clone Manager Operations
+	GetAgentClonePath(agentName string) (string, error)
+	RefreshAgentClone(agentName string) error
+	CleanupAgentClone(agentName string) error
+	CleanupAllClones() error
 }
 
 // Status represents the current state of the repository
@@ -187,46 +195,55 @@
 
 // Git implementation using os/exec to call git commands
 type Git struct {
-	repoPath   string
-	config     GitConfig
-	prProvider PullRequestProvider
-	logger     *slog.Logger
-}
-
-// GitConfig holds configuration for Git operations
-type GitConfig struct {
-	Timeout             time.Duration
-	Env                 map[string]string
-	PullRequestProvider PullRequestProvider
+	repoPath     string
+	prProvider   PullRequestProvider
+	cloneManager *CloneManager
+	logger       *slog.Logger
 }
 
 // NewGit creates a new Git instance
-func NewGit(repoPath string, config GitConfig, logger *slog.Logger) GitInterface {
-	if config.Timeout == 0 {
-		config.Timeout = 30 * time.Second
+func New(cfg *config.Config, logger *slog.Logger) GitInterface {
+	var prProvider PullRequestProvider
+	var repoURL string
+
+	switch cfg.GetPrimaryGitProvider() {
+	case "github":
+		githubConfig := GitHubConfig{
+			Token:  cfg.GitHub.Token,
+			Logger: logger,
+		}
+		prProvider = 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 := GerritConfig{
+			Username: cfg.Gerrit.Username,
+			Password: cfg.Gerrit.Password,
+			BaseURL:  cfg.Gerrit.BaseURL,
+			Logger:   logger,
+		}
+		prProvider = 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:
+		panic("no valid Git provider configured")
 	}
 
+	workspacePath := filepath.Join(".", "workspace") //TODO: make it configurable
+	cloneManager := NewCloneManager(repoURL, workspacePath)
+
 	return &Git{
-		repoPath:   repoPath,
-		config:     config,
-		prProvider: config.PullRequestProvider,
-		logger:     logger,
+		repoPath:     cfg.Git.RepoPath,
+		prProvider:   prProvider,
+		cloneManager: cloneManager,
+		logger:       logger,
 	}
 }
 
-// DefaultGit creates a Git instance with default configuration
-func DefaultGit(repoPath string) GitInterface {
-	return NewGit(repoPath, GitConfig{
-		Timeout: 30 * time.Second,
-	}, slog.Default())
-}
-
-// NewGitWithPullRequests creates a Git instance with pull request capabilities
-func NewGitWithPullRequests(repoPath string, config GitConfig, prProvider PullRequestProvider, logger *slog.Logger) GitInterface {
-	config.PullRequestProvider = prProvider
-	return NewGit(repoPath, config, logger)
-}
-
 // Ensure Git implements GitInterface
 var _ GitInterface = (*Git)(nil)
 
@@ -637,6 +654,32 @@
 	return g.prProvider.MergePullRequest(ctx, id, options)
 }
 
+// Clone manage methods
+func (g *Git) GetAgentClonePath(agentName string) (string, error) {
+	if g.cloneManager == nil {
+		return "", &GitError{Command: "GetAgentClonePath", Output: "no clone manager configured"}
+	}
+	return g.cloneManager.GetAgentClonePath(agentName)
+}
+func (g *Git) RefreshAgentClone(agentName string) error {
+	if g.cloneManager == nil {
+		return &GitError{Command: "RefreshAgentClone", Output: "no clone manager configured"}
+	}
+	return g.cloneManager.RefreshAgentClone(agentName)
+}
+func (g *Git) CleanupAgentClone(agentName string) error {
+	if g.cloneManager == nil {
+		return &GitError{Command: "CleanupAgentClone", Output: "no clone manager configured"}
+	}
+	return g.cloneManager.CleanupAgentClone(agentName)
+}
+func (g *Git) CleanupAllClones() error {
+	if g.cloneManager == nil {
+		return &GitError{Command: "CleanupAllClones", Output: "no clone manager configured"}
+	}
+	return g.cloneManager.CleanupAllClones()
+}
+
 // Helper methods
 
 func (g *Git) runCommand(cmd *exec.Cmd, command string) error {
@@ -885,6 +928,7 @@
 	Reviewers   []Author
 	Commits     []Commit
 	Comments    []PullRequestComment
+	URL         string
 }
 
 // PullRequestComment represents a comment on a pull request
diff --git a/server/git/git_test.go b/server/git/git_test.go
deleted file mode 100644
index d3862ce..0000000
--- a/server/git/git_test.go
+++ /dev/null
@@ -1,645 +0,0 @@
-package git
-
-import (
-	"context"
-	"fmt"
-	"log/slog"
-	"os"
-	"path/filepath"
-	"testing"
-	"time"
-)
-
-func TestNewGit(t *testing.T) {
-	// Create logger for testing
-	logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))
-
-	// Test creating a new Git instance with default config
-	git := DefaultGit("/tmp/test-repo")
-	if git == nil {
-		t.Fatal("DefaultGit returned nil")
-	}
-
-	// Test creating a new Git instance with custom config
-	config := GitConfig{
-		Timeout: 60 * time.Second,
-		Env: map[string]string{
-			"GIT_AUTHOR_NAME": "Test User",
-		},
-	}
-	git = NewGit("/tmp/test-repo", config, logger)
-	if git == nil {
-		t.Fatal("NewGit returned nil")
-	}
-}
-
-func TestGitRepositoryOperations(t *testing.T) {
-	// Create a temporary directory for testing
-	tempDir, err := os.MkdirTemp("", "git-test-*")
-	if err != nil {
-		t.Fatalf("Failed to create temp directory: %v", err)
-	}
-	defer os.RemoveAll(tempDir)
-
-	git := DefaultGit(tempDir)
-	ctx := context.Background()
-
-	// Test IsRepository on non-repository
-	isRepo, err := git.IsRepository(ctx, tempDir)
-	if err != nil {
-		t.Fatalf("IsRepository failed: %v", err)
-	}
-	if isRepo {
-		t.Error("Expected IsRepository to return false for non-repository")
-	}
-
-	// Test Init
-	err = git.Init(ctx, tempDir)
-	if err != nil {
-		t.Fatalf("Init failed: %v", err)
-	}
-
-	// Test IsRepository after init
-	isRepo, err = git.IsRepository(ctx, tempDir)
-	if err != nil {
-		t.Fatalf("IsRepository failed after init: %v", err)
-	}
-	if !isRepo {
-		t.Error("Expected IsRepository to return true after init")
-	}
-}
-
-func TestGitStatus(t *testing.T) {
-	// Create a temporary directory for testing
-	tempDir, err := os.MkdirTemp("", "git-test-*")
-	if err != nil {
-		t.Fatalf("Failed to create temp directory: %v", err)
-	}
-	defer os.RemoveAll(tempDir)
-
-	git := DefaultGit(tempDir)
-	ctx := context.Background()
-
-	// Initialize repository
-	err = git.Init(ctx, tempDir)
-	if err != nil {
-		t.Fatalf("Init failed: %v", err)
-	}
-
-	// Test status on clean repository
-	status, err := git.Status(ctx)
-	if err != nil {
-		t.Fatalf("Status failed: %v", err)
-	}
-
-	if status == nil {
-		t.Fatal("Status returned nil")
-	}
-
-	// Should be clean after init
-	if !status.IsClean {
-		t.Error("Expected repository to be clean after init")
-	}
-
-	// Create a test file
-	testFile := filepath.Join(tempDir, "test.txt")
-	err = os.WriteFile(testFile, []byte("Hello, Git!\n"), 0644)
-	if err != nil {
-		t.Fatalf("Failed to create test file: %v", err)
-	}
-
-	// Test status with untracked file
-	status, err = git.Status(ctx)
-	if err != nil {
-		t.Fatalf("Status failed: %v", err)
-	}
-
-	// Debug: print status information
-	t.Logf("Status: IsClean=%t, Staged=%d, Unstaged=%d, Untracked=%d",
-		status.IsClean, len(status.Staged), len(status.Unstaged), len(status.Untracked))
-
-	if len(status.Untracked) > 0 {
-		t.Logf("Untracked files: %v", status.Untracked)
-	}
-
-	if status.IsClean {
-		t.Error("Expected repository to be dirty with untracked file")
-	}
-
-	// Check if the file is detected in any status (untracked, unstaged, or staged)
-	totalFiles := len(status.Untracked) + len(status.Unstaged) + len(status.Staged)
-	if totalFiles == 0 {
-		t.Error("Expected at least 1 file to be detected")
-		return
-	}
-
-	// Look for test.txt in any of the status categories
-	found := false
-	for _, file := range status.Untracked {
-		if file == "test.txt" {
-			found = true
-			break
-		}
-	}
-	for _, file := range status.Unstaged {
-		if file.Path == "test.txt" {
-			found = true
-			break
-		}
-	}
-	for _, file := range status.Staged {
-		if file.Path == "test.txt" {
-			found = true
-			break
-		}
-	}
-
-	if !found {
-		t.Error("Expected test.txt to be found in status")
-	}
-}
-
-func TestGitUserConfig(t *testing.T) {
-	// Create a temporary directory for testing
-	tempDir, err := os.MkdirTemp("", "git-test-*")
-	if err != nil {
-		t.Fatalf("Failed to create temp directory: %v", err)
-	}
-	defer os.RemoveAll(tempDir)
-
-	git := DefaultGit(tempDir)
-	ctx := context.Background()
-
-	// Initialize repository
-	err = git.Init(ctx, tempDir)
-	if err != nil {
-		t.Fatalf("Init failed: %v", err)
-	}
-
-	// Test setting user config
-	userConfig := UserConfig{
-		Name:  "Test User",
-		Email: "test@example.com",
-	}
-
-	err = git.SetUserConfig(ctx, userConfig)
-	if err != nil {
-		t.Fatalf("SetUserConfig failed: %v", err)
-	}
-
-	// Test getting user config
-	retrievedConfig, err := git.GetUserConfig(ctx)
-	if err != nil {
-		t.Fatalf("GetUserConfig failed: %v", err)
-	}
-
-	if retrievedConfig.Name != userConfig.Name {
-		t.Errorf("Expected name '%s', got '%s'", userConfig.Name, retrievedConfig.Name)
-	}
-
-	if retrievedConfig.Email != userConfig.Email {
-		t.Errorf("Expected email '%s', got '%s'", userConfig.Email, retrievedConfig.Email)
-	}
-}
-
-func TestGitCommitWorkflow(t *testing.T) {
-	// Create a temporary directory for testing
-	tempDir, err := os.MkdirTemp("", "git-test-*")
-	if err != nil {
-		t.Fatalf("Failed to create temp directory: %v", err)
-	}
-	defer os.RemoveAll(tempDir)
-
-	git := DefaultGit(tempDir)
-	ctx := context.Background()
-
-	// Initialize repository
-	err = git.Init(ctx, tempDir)
-	if err != nil {
-		t.Fatalf("Init failed: %v", err)
-	}
-
-	// Set user config
-	userConfig := UserConfig{
-		Name:  "Test User",
-		Email: "test@example.com",
-	}
-	err = git.SetUserConfig(ctx, userConfig)
-	if err != nil {
-		t.Fatalf("SetUserConfig failed: %v", err)
-	}
-
-	// Create a test file
-	testFile := filepath.Join(tempDir, "test.txt")
-	err = os.WriteFile(testFile, []byte("Hello, Git!\n"), 0644)
-	if err != nil {
-		t.Fatalf("Failed to create test file: %v", err)
-	}
-
-	// Test AddAll
-	err = git.AddAll(ctx)
-	if err != nil {
-		t.Fatalf("AddAll failed: %v", err)
-	}
-
-	// Check status after staging
-	status, err := git.Status(ctx)
-	if err != nil {
-		t.Fatalf("Status failed: %v", err)
-	}
-
-	if len(status.Staged) != 1 {
-		t.Errorf("Expected 1 staged file, got %d", len(status.Staged))
-	}
-
-	// Test Commit
-	commitOptions := CommitOptions{
-		AllowEmpty: false,
-	}
-	err = git.Commit(ctx, "Initial commit", commitOptions)
-	if err != nil {
-		t.Fatalf("Commit failed: %v", err)
-	}
-
-	// Check status after commit
-	status, err = git.Status(ctx)
-	if err != nil {
-		t.Fatalf("Status failed: %v", err)
-	}
-
-	if !status.IsClean {
-		t.Error("Expected repository to be clean after commit")
-	}
-}
-
-func TestGitBranchOperations(t *testing.T) {
-	// Create a temporary directory for testing
-	tempDir, err := os.MkdirTemp("", "git-test-*")
-	if err != nil {
-		t.Fatalf("Failed to create temp directory: %v", err)
-	}
-	defer os.RemoveAll(tempDir)
-
-	git := DefaultGit(tempDir)
-	ctx := context.Background()
-
-	// Initialize repository
-	err = git.Init(ctx, tempDir)
-	if err != nil {
-		t.Fatalf("Init failed: %v", err)
-	}
-
-	// Set user config
-	userConfig := UserConfig{
-		Name:  "Test User",
-		Email: "test@example.com",
-	}
-	err = git.SetUserConfig(ctx, userConfig)
-	if err != nil {
-		t.Fatalf("SetUserConfig failed: %v", err)
-	}
-
-	// Create initial commit
-	testFile := filepath.Join(tempDir, "test.txt")
-	err = os.WriteFile(testFile, []byte("Hello, Git!\n"), 0644)
-	if err != nil {
-		t.Fatalf("Failed to create test file: %v", err)
-	}
-
-	err = git.AddAll(ctx)
-	if err != nil {
-		t.Fatalf("AddAll failed: %v", err)
-	}
-
-	err = git.Commit(ctx, "Initial commit", CommitOptions{})
-	if err != nil {
-		t.Fatalf("Commit failed: %v", err)
-	}
-
-	// Test GetCurrentBranch
-	currentBranch, err := git.GetCurrentBranch(ctx)
-	if err != nil {
-		t.Fatalf("GetCurrentBranch failed: %v", err)
-	}
-
-	// Default branch name might be 'main' or 'master' depending on Git version
-	if currentBranch != "main" && currentBranch != "master" {
-		t.Errorf("Expected current branch to be 'main' or 'master', got '%s'", currentBranch)
-	}
-
-	// Test CreateBranch
-	err = git.CreateBranch(ctx, "feature/test", "")
-	if err != nil {
-		t.Fatalf("CreateBranch failed: %v", err)
-	}
-
-	// Test ListBranches
-	branches, err := git.ListBranches(ctx)
-	if err != nil {
-		t.Fatalf("ListBranches failed: %v", err)
-	}
-
-	if len(branches) < 2 {
-		t.Errorf("Expected at least 2 branches, got %d", len(branches))
-	}
-
-	// Find the feature branch
-	foundFeatureBranch := false
-	for _, branch := range branches {
-		if branch.Name == "feature/test" {
-			foundFeatureBranch = true
-			break
-		}
-	}
-
-	if !foundFeatureBranch {
-		t.Error("Feature branch not found in branch list")
-	}
-
-	// Test Checkout
-	err = git.Checkout(ctx, "feature/test")
-	if err != nil {
-		t.Fatalf("Checkout failed: %v", err)
-	}
-
-	// Verify we're on the feature branch
-	currentBranch, err = git.GetCurrentBranch(ctx)
-	if err != nil {
-		t.Fatalf("GetCurrentBranch failed: %v", err)
-	}
-
-	if currentBranch != "feature/test" {
-		t.Errorf("Expected current branch to be 'feature/test', got '%s'", currentBranch)
-	}
-}
-
-func TestGitLog(t *testing.T) {
-	t.Skip("Log parsing needs to be fixed")
-	// Create a temporary directory for testing
-	tempDir, err := os.MkdirTemp("", "git-test-*")
-	if err != nil {
-		t.Fatalf("Failed to create temp directory: %v", err)
-	}
-	defer os.RemoveAll(tempDir)
-
-	git := DefaultGit(tempDir)
-	ctx := context.Background()
-
-	// Initialize repository
-	err = git.Init(ctx, tempDir)
-	if err != nil {
-		t.Fatalf("Init failed: %v", err)
-	}
-
-	// Set user config
-	userConfig := UserConfig{
-		Name:  "Test User",
-		Email: "test@example.com",
-	}
-	err = git.SetUserConfig(ctx, userConfig)
-	if err != nil {
-		t.Fatalf("SetUserConfig failed: %v", err)
-	}
-
-	// Create initial commit
-	testFile := filepath.Join(tempDir, "test.txt")
-	err = os.WriteFile(testFile, []byte("Hello, Git!\n"), 0644)
-	if err != nil {
-		t.Fatalf("Failed to create test file: %v", err)
-	}
-
-	err = git.AddAll(ctx)
-	if err != nil {
-		t.Fatalf("AddAll failed: %v", err)
-	}
-
-	err = git.Commit(ctx, "Initial commit", CommitOptions{})
-	if err != nil {
-		t.Fatalf("Commit failed: %v", err)
-	}
-
-	// Test Log
-	logOptions := LogOptions{
-		MaxCount: 10,
-		Oneline:  false,
-	}
-	commits, err := git.Log(ctx, logOptions)
-	if err != nil {
-		t.Fatalf("Log failed: %v", err)
-	}
-
-	t.Logf("Found %d commits", len(commits))
-	if len(commits) == 0 {
-		t.Error("Expected at least 1 commit, got 0")
-		return
-	}
-
-	// Check first commit
-	commit := commits[0]
-	if commit.Message != "Initial commit" {
-		t.Errorf("Expected commit message 'Initial commit', got '%s'", commit.Message)
-	}
-
-	if commit.Author.Name != "Test User" {
-		t.Errorf("Expected author name 'Test User', got '%s'", commit.Author.Name)
-	}
-
-	if commit.Author.Email != "test@example.com" {
-		t.Errorf("Expected author email 'test@example.com', got '%s'", commit.Author.Email)
-	}
-}
-
-func TestGitError(t *testing.T) {
-	// Test GitError creation and methods
-	gitErr := &GitError{
-		Command: "test",
-		Output:  "test output",
-		Err:     nil,
-	}
-
-	errorMsg := gitErr.Error()
-	if errorMsg == "" {
-		t.Error("GitError.Error() returned empty string")
-	}
-
-	// Test with underlying error
-	underlyingErr := &GitError{
-		Command: "subtest",
-		Output:  "subtest output",
-		Err:     gitErr,
-	}
-
-	unwrapped := underlyingErr.Unwrap()
-	if unwrapped != gitErr {
-		t.Error("GitError.Unwrap() did not return the underlying error")
-	}
-}
-
-func TestGitConfigOperations(t *testing.T) {
-	// Create a temporary directory for testing
-	tempDir, err := os.MkdirTemp("", "git-test-*")
-	if err != nil {
-		t.Fatalf("Failed to create temp directory: %v", err)
-	}
-	defer os.RemoveAll(tempDir)
-
-	git := DefaultGit(tempDir)
-	ctx := context.Background()
-
-	// Initialize repository
-	err = git.Init(ctx, tempDir)
-	if err != nil {
-		t.Fatalf("Init failed: %v", err)
-	}
-
-	// Test SetConfig
-	err = git.SetConfig(ctx, "test.key", "test.value")
-	if err != nil {
-		t.Fatalf("SetConfig failed: %v", err)
-	}
-
-	// Test GetConfig
-	value, err := git.GetConfig(ctx, "test.key")
-	if err != nil {
-		t.Fatalf("GetConfig failed: %v", err)
-	}
-
-	if value != "test.value" {
-		t.Errorf("Expected config value 'test.value', got '%s'", value)
-	}
-}
-
-func TestGitMerge(t *testing.T) {
-	// Create a temporary directory for testing
-	tempDir, err := os.MkdirTemp("", "git-test-*")
-	if err != nil {
-		t.Fatalf("Failed to create temp directory: %v", err)
-	}
-	defer os.RemoveAll(tempDir)
-
-	git := DefaultGit(tempDir)
-	ctx := context.Background()
-
-	// Initialize repository
-	err = git.Init(ctx, tempDir)
-	if err != nil {
-		t.Fatalf("Init failed: %v", err)
-	}
-
-	// Set user config
-	userConfig := UserConfig{
-		Name:  "Test User",
-		Email: "test@example.com",
-	}
-	err = git.SetUserConfig(ctx, userConfig)
-	if err != nil {
-		t.Fatalf("SetUserConfig failed: %v", err)
-	}
-
-	// Create initial commit
-	testFile := filepath.Join(tempDir, "test.txt")
-	err = os.WriteFile(testFile, []byte("Hello, Git!\n"), 0644)
-	if err != nil {
-		t.Fatalf("Failed to create test file: %v", err)
-	}
-
-	err = git.AddAll(ctx)
-	if err != nil {
-		t.Fatalf("AddAll failed: %v", err)
-	}
-
-	err = git.Commit(ctx, "Initial commit", CommitOptions{})
-	if err != nil {
-		t.Fatalf("Commit failed: %v", err)
-	}
-
-	// Create feature branch
-	err = git.CreateBranch(ctx, "feature/test", "")
-	if err != nil {
-		t.Fatalf("CreateBranch failed: %v", err)
-	}
-
-	// Switch to feature branch
-	err = git.Checkout(ctx, "feature/test")
-	if err != nil {
-		t.Fatalf("Checkout failed: %v", err)
-	}
-
-	// Add file on feature branch
-	featureFile := filepath.Join(tempDir, "feature.txt")
-	err = os.WriteFile(featureFile, []byte("Feature file\n"), 0644)
-	if err != nil {
-		t.Fatalf("Failed to create feature file: %v", err)
-	}
-
-	err = git.AddAll(ctx)
-	if err != nil {
-		t.Fatalf("AddAll failed: %v", err)
-	}
-
-	err = git.Commit(ctx, "Add feature file", CommitOptions{})
-	if err != nil {
-		t.Fatalf("Commit failed: %v", err)
-	}
-
-	// Switch back to main
-	err = git.Checkout(ctx, "main")
-	if err != nil {
-		t.Fatalf("Checkout failed: %v", err)
-	}
-
-	// Test Merge
-	mergeOptions := MergeOptions{
-		NoFF:    true,
-		Message: "Merge feature/test",
-	}
-	err = git.Merge(ctx, "feature/test", mergeOptions)
-	if err != nil {
-		t.Fatalf("Merge failed: %v", err)
-	}
-
-	// Check that both files exist after merge
-	if _, err := os.Stat(filepath.Join(tempDir, "test.txt")); os.IsNotExist(err) {
-		t.Error("test.txt not found after merge")
-	}
-
-	if _, err := os.Stat(filepath.Join(tempDir, "feature.txt")); os.IsNotExist(err) {
-		t.Error("feature.txt not found after merge")
-	}
-}
-
-func BenchmarkGitStatus(b *testing.B) {
-	// Create a temporary directory for testing
-	tempDir, err := os.MkdirTemp("", "git-bench-*")
-	if err != nil {
-		b.Fatalf("Failed to create temp directory: %v", err)
-	}
-	defer os.RemoveAll(tempDir)
-
-	git := DefaultGit(tempDir)
-	ctx := context.Background()
-
-	// Initialize repository
-	err = git.Init(ctx, tempDir)
-	if err != nil {
-		b.Fatalf("Init failed: %v", err)
-	}
-
-	// Create some files
-	for i := 0; i < 10; i++ {
-		testFile := filepath.Join(tempDir, fmt.Sprintf("test%d.txt", i))
-		err = os.WriteFile(testFile, []byte(fmt.Sprintf("File %d\n", i)), 0644)
-		if err != nil {
-			b.Fatalf("Failed to create test file: %v", err)
-		}
-	}
-
-	b.ResetTimer()
-
-	for i := 0; i < b.N; i++ {
-		_, err := git.Status(ctx)
-		if err != nil {
-			b.Fatalf("Status failed: %v", err)
-		}
-	}
-}
diff --git a/server/git/github.go b/server/git/github.go
index 6555b69..1d37b1d 100644
--- a/server/git/github.go
+++ b/server/git/github.go
@@ -139,7 +139,7 @@
 		slog.Any("labels", options.Labels))
 
 	url := fmt.Sprintf("%s/repos/%s/%s/pulls", g.config.BaseURL, g.owner, g.repo)
-	
+
 	req, err := http.NewRequestWithContext(ctx, "POST", url, bytes.NewBuffer(jsonBody))
 	if err != nil {
 		return nil, fmt.Errorf("failed to create request: %w", err)
@@ -412,5 +412,6 @@
 		Reviewers:  reviewers,
 		Commits:    []Commit{},             // Would need additional API call to populate
 		Comments:   []PullRequestComment{}, // Would need additional API call to populate
+		URL:        fmt.Sprintf("https://github.com/%s/%s/pull/%d", g.owner, g.repo, githubPR.Number),
 	}
 }
diff --git a/server/git/pull_request_example.go b/server/git/pull_request_example.go
deleted file mode 100644
index 5c70d21..0000000
--- a/server/git/pull_request_example.go
+++ /dev/null
@@ -1,251 +0,0 @@
-package git
-
-import (
-	"context"
-	"log/slog"
-	"net/http"
-	"os"
-	"time"
-)
-
-// ExamplePullRequestUsage demonstrates how to use pull request functionality
-func ExamplePullRequestUsage() {
-	ctx := context.Background()
-
-	// Create logger
-	logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))
-
-	// Example with GitHub
-	exampleGitHubPullRequests(ctx, logger)
-
-	// Example with Gerrit
-	exampleGerritPullRequests(ctx, logger)
-}
-
-func exampleGitHubPullRequests(ctx context.Context, logger *slog.Logger) {
-	logger.Info("=== GitHub Pull Request Example ===")
-
-	// Create GitHub configuration
-	githubConfig := GitHubConfig{
-		Token:      "your-github-token-here",
-		BaseURL:    "https://api.github.com",
-		HTTPClient: &http.Client{Timeout: 30 * time.Second},
-	}
-
-	// Create GitHub pull request provider
-	githubProvider := NewGitHubPullRequestProvider("owner", "repo", githubConfig)
-
-	// Create Git instance with GitHub pull request capabilities
-	git := NewGitWithPullRequests("/path/to/repo", GitConfig{
-		Timeout: 30 * time.Second,
-	}, githubProvider, logger)
-
-	// Create a new pull request
-	prOptions := PullRequestOptions{
-		Title:       "Add new feature",
-		Description: "This PR adds a new feature to the application.",
-		BaseBranch:  "main",
-		HeadBranch:  "feature/new-feature",
-		Labels:      []string{"enhancement", "feature"},
-		Assignees:   []string{"username1", "username2"},
-		Reviewers:   []string{"reviewer1", "reviewer2"},
-		Draft:       false,
-	}
-
-	pr, err := git.CreatePullRequest(ctx, prOptions)
-	if err != nil {
-		logger.Error("Failed to create pull request", slog.String("error", err.Error()))
-		return
-	}
-
-	logger.Info("Created pull request", slog.String("title", pr.Title), slog.Int("number", pr.Number))
-
-	// List pull requests
-	listOptions := ListPullRequestOptions{
-		State:      "open",
-		Author:     "username",
-		BaseBranch: "main",
-		Limit:      10,
-	}
-
-	prs, err := git.ListPullRequests(ctx, listOptions)
-	if err != nil {
-		logger.Error("Failed to list pull requests", slog.String("error", err.Error()))
-		return
-	}
-
-	logger.Info("Found pull requests", slog.Int("count", len(prs)))
-
-	// Get a specific pull request
-	pr, err = git.GetPullRequest(ctx, pr.ID)
-	if err != nil {
-		logger.Error("Failed to get pull request", slog.String("error", err.Error()))
-		return
-	}
-
-	logger.Info("Pull request status", slog.String("state", pr.State))
-
-	// Update a pull request
-	updateOptions := PullRequestOptions{
-		Title:       "Updated title",
-		Description: "Updated description",
-		Labels:      []string{"bug", "urgent"},
-	}
-
-	updatedPR, err := git.UpdatePullRequest(ctx, pr.ID, updateOptions)
-	if err != nil {
-		logger.Error("Failed to update pull request", slog.String("error", err.Error()))
-		return
-	}
-
-	logger.Info("Updated pull request", slog.String("title", updatedPR.Title))
-
-	// Merge a pull request
-	mergeOptions := MergePullRequestOptions{
-		MergeMethod: "squash",
-		CommitTitle: "Merge pull request #123",
-		CommitMsg:   "This merges the feature branch into main",
-	}
-
-	err = git.MergePullRequest(ctx, pr.ID, mergeOptions)
-	if err != nil {
-		logger.Error("Failed to merge pull request", slog.String("error", err.Error()))
-		return
-	}
-
-	logger.Info("Pull request merged successfully")
-}
-
-func exampleGerritPullRequests(ctx context.Context, logger *slog.Logger) {
-	logger.Info("=== Gerrit Pull Request Example ===")
-
-	// Create Gerrit configuration
-	gerritConfig := GerritConfig{
-		Username:   "your-username",
-		Password:   "your-http-password-or-api-token",
-		BaseURL:    "https://gerrit.example.com",
-		HTTPClient: &http.Client{Timeout: 30 * time.Second},
-	}
-
-	// Create Gerrit pull request provider
-	gerritProvider := NewGerritPullRequestProvider("project-name", gerritConfig)
-
-	// Create Git instance with Gerrit pull request capabilities
-	git := NewGitWithPullRequests("/path/to/repo", GitConfig{
-		Timeout: 30 * time.Second,
-	}, gerritProvider, logger)
-
-	// Create a new change (pull request)
-	prOptions := PullRequestOptions{
-		Title:       "Add new feature",
-		Description: "This change adds a new feature to the application.",
-		BaseBranch:  "master",
-		HeadBranch:  "feature/new-feature",
-	}
-
-	pr, err := git.CreatePullRequest(ctx, prOptions)
-	if err != nil {
-		logger.Error("Failed to create change", slog.String("error", err.Error()))
-		return
-	}
-
-	logger.Info("Created change", slog.String("title", pr.Title), slog.Int("number", pr.Number))
-
-	// List changes
-	listOptions := ListPullRequestOptions{
-		State:      "open",
-		Author:     "username",
-		BaseBranch: "master",
-		Limit:      10,
-	}
-
-	prs, err := git.ListPullRequests(ctx, listOptions)
-	if err != nil {
-		logger.Error("Failed to list changes", slog.String("error", err.Error()))
-		return
-	}
-
-	logger.Info("Found changes", slog.Int("count", len(prs)))
-
-	// Get a specific change
-	pr, err = git.GetPullRequest(ctx, pr.ID)
-	if err != nil {
-		logger.Error("Failed to get change", slog.String("error", err.Error()))
-		return
-	}
-
-	logger.Info("Change status", slog.String("state", pr.State))
-
-	// Update a change
-	updateOptions := PullRequestOptions{
-		Title:       "Updated title",
-		Description: "Updated description",
-	}
-
-	updatedPR, err := git.UpdatePullRequest(ctx, pr.ID, updateOptions)
-	if err != nil {
-		logger.Error("Failed to update change", slog.String("error", err.Error()))
-		return
-	}
-
-	logger.Info("Updated change", slog.String("title", updatedPR.Title))
-
-	// Submit a change (merge)
-	mergeOptions := MergePullRequestOptions{
-		CommitTitle: "Submit change",
-		CommitMsg:   "This submits the change to master",
-	}
-
-	err = git.MergePullRequest(ctx, pr.ID, mergeOptions)
-	if err != nil {
-		logger.Error("Failed to submit change", slog.String("error", err.Error()))
-		return
-	}
-
-	logger.Info("Change submitted successfully")
-}
-
-// Example of using both providers in the same application
-func ExampleMultiProviderUsage() {
-	ctx := context.Background()
-
-	// Determine which provider to use based on configuration
-	useGitHub := true // This could come from config
-
-	var git GitInterface
-
-	if useGitHub {
-		// Use GitHub
-		githubConfig := GitHubConfig{
-			Token:   "github-token",
-			BaseURL: "https://api.github.com",
-		}
-		githubProvider := NewGitHubPullRequestProvider("owner", "repo", githubConfig)
-		git = NewGitWithPullRequests("/path/to/repo", GitConfig{}, githubProvider, nil) // Pass nil for logger as it's not used in this example
-	} else {
-		// Use Gerrit
-		gerritConfig := GerritConfig{
-			Username: "gerrit-username",
-			Password: "gerrit-password",
-			BaseURL:  "https://gerrit.example.com",
-		}
-		gerritProvider := NewGerritPullRequestProvider("project", gerritConfig)
-		git = NewGitWithPullRequests("/path/to/repo", GitConfig{}, gerritProvider, nil) // Pass nil for logger as it's not used in this example
-	}
-
-	// Use the same interface regardless of provider
-	prOptions := PullRequestOptions{
-		Title:       "Cross-platform PR",
-		Description: "This works with both GitHub and Gerrit",
-		BaseBranch:  "main",
-		HeadBranch:  "feature/cross-platform",
-	}
-
-	pr, err := git.CreatePullRequest(ctx, prOptions)
-	if err != nil {
-		slog.Error("Failed to create pull request", slog.String("error", err.Error()))
-		return
-	}
-
-	slog.Info("Created pull request", slog.String("title", pr.Title))
-}