> ## Documentation Index
> Fetch the complete documentation index at: https://docs.declaw.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Git Clone and Fix

> Simulate cloning a repository, identifying a bug, applying a code fix, showing a diff, and verifying the fix with tests — all inside an isolated Declaw sandbox.

## What You'll Learn

* How to upload a multi-file Python project into a sandbox to simulate a repository
* How to run a test suite before and after a fix to demonstrate a regression cycle
* How to apply a targeted code fix by reading, patching, and writing a file
* How to show a simple diff of the change inside the sandbox

## Prerequisites

* Declaw running locally or in the cloud (see [Deployment](/deployment/overview))
* `DECLAW_API_KEY` and `DECLAW_DOMAIN` set in your environment

<Note>
  This example is available in Python. TypeScript support coming soon.
</Note>

## Code Walkthrough

### 1. The buggy repository

The simulated repository contains two modules and a test file. `string_utils.py` has a deliberate bug — the `count_vowels` function is missing `'u'` from the vowel set:

```python theme={null}
STRING_UTILS = """\
def count_vowels(s: str) -> int:
    \"\"\"Count the number of vowels in a string.\"\"\"
    # BUG: missing 'u' from vowels
    return sum(1 for c in s.lower() if c in "aeio")
"""

MATH_UTILS = """\
def factorial(n: int) -> int:
    if n < 0:
        raise ValueError("n must be non-negative")
    if n <= 1:
        return 1
    return n * factorial(n - 1)

def fibonacci(n: int) -> list:
    if n <= 0: return []
    if n == 1: return [0]
    seq = [0, 1]
    while len(seq) < n:
        seq.append(seq[-1] + seq[-2])
    return seq
"""
```

The test file has cases that will fail due to the bug:

```python theme={null}
TEST_FILE = """\
class TestStringUtils(unittest.TestCase):

    def test_count_vowels(self):
        self.assertEqual(count_vowels("hello"), 2)
        self.assertEqual(count_vowels("AEIOU"), 5)  # Will fail: counts 4, not 5
        self.assertEqual(count_vowels("ubuntu"), 3)  # Will fail: counts 2, not 3
"""
```

### 2. Upload and run tests before the fix

```python theme={null}
from declaw import Sandbox

sbx = Sandbox.create(template="python", timeout=300)
try:
    sbx.files.write("/home/user/repo/string_utils.py", STRING_UTILS)
    sbx.files.write("/home/user/repo/math_utils.py", MATH_UTILS)
    sbx.files.write("/home/user/repo/test_all.py", TEST_FILE)

    result_before = sbx.commands.run(
        "cd /home/user/repo && python3 -m unittest test_all -v 2>&1"
    )
    print(result_before.stdout)
    print(f"Exit code (before): {result_before.exit_code}")  # 1 (failure)
```

### 3. Apply the bug fix

The fix script reads the file, applies a targeted string replacement, and writes it back:

```python theme={null}
FIX_SCRIPT = """\
with open("/home/user/repo/string_utils.py", "r") as f:
    content = f.read()

# Save original for diff
with open("/home/user/repo/string_utils.py.orig", "w") as f:
    f.write(content)

# Apply the fix: add missing 'u' to vowels string
fixed = content.replace(
    'return sum(1 for c in s.lower() if c in "aeio")',
    'return sum(1 for c in s.lower() if c in "aeiou")'
)

with open("/home/user/repo/string_utils.py", "w") as f:
    f.write(fixed)

print("Fix applied: added 'u' to vowels in count_vowels()")
"""

sbx.files.write("/home/user/repo/fix.py", FIX_SCRIPT)
sbx.commands.run("python3 /home/user/repo/fix.py")
```

### 4. Show the diff

```python theme={null}
DIFF_SCRIPT = """\
with open("/home/user/repo/string_utils.py.orig") as f:
    original_lines = f.readlines()

with open("/home/user/repo/string_utils.py") as f:
    fixed_lines = f.readlines()

for i, (orig, fixed) in enumerate(zip(original_lines, fixed_lines), 1):
    if orig != fixed:
        print(f"Line {i}:")
        print(f"  - {orig.rstrip()}")
        print(f"  + {fixed.rstrip()}")
"""

sbx.files.write("/home/user/repo/diff.py", DIFF_SCRIPT)
diff_result = sbx.commands.run("python3 /home/user/repo/diff.py")
print(diff_result.stdout)
```

### 5. Run tests after the fix

```python theme={null}
    result_after = sbx.commands.run(
        "cd /home/user/repo && python3 -m unittest test_all -v 2>&1"
    )
    print(result_after.stdout)
    print(f"Exit code (after): {result_after.exit_code}")  # 0 (all pass)

    before_status = "PASS" if result_before.exit_code == 0 else "FAIL"
    after_status  = "PASS" if result_after.exit_code == 0 else "FAIL"
    print(f"Before fix: {before_status}")
    print(f"After fix:  {after_status}")
finally:
    sbx.kill()
```

## Expected Output

```
--- Running Tests (BEFORE fix) ---
test_capitalize_words ... ok
test_count_vowels ... FAIL
test_is_palindrome ... ok
test_reverse_string ... ok
test_factorial ... ok
test_fibonacci ... ok
test_gcd ... ok

FAILED (failures=1)
Exit code: 1

--- Applying Bug Fix ---
  Fix applied: added 'u' to vowels in count_vowels()

--- Diff (before vs after) ---
--- string_utils.py (before)
+++ string_utils.py (after)

Line 10:
  -     return sum(1 for c in s.lower() if c in "aeio")
  +     return sum(1 for c in s.lower() if c in "aeiou")

--- Running Tests (AFTER fix) ---
test_capitalize_words ... ok
test_count_vowels ... ok
test_is_palindrome ... ok
test_reverse_string ... ok
...

Ran 7 tests in 0.001s

OK
Exit code: 0

--- Summary ---
  Before fix: FAIL (exit code 1)
  After fix:  PASS (exit code 0)
```

## Extending to Real Git Repositories

The example simulates a repository by uploading files. To work with a real git repository, install `git` first and then clone:

```python theme={null}
sbx = Sandbox.create(
    template="python",
    timeout=600,
    network={"allow_out": ["github.com"]},  # Allow GitHub access
)
sbx.commands.run("apt-get install -y git 2>&1")
sbx.commands.run(
    "git clone https://github.com/your-org/your-repo /home/user/repo 2>&1"
)
```

<Warning>
  When cloning a public repository, set `network={"allow_out": ["github.com"]}` so the sandbox can reach GitHub but nothing else. For private repositories, pass a personal access token as an environment variable and restrict the allow-list to `github.com` only.
</Warning>
