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

# Repo and git workflows with Claude Code

> Clone repositories into a Gravix Claude sandbox, add project context with CLAUDE.md, run Claude Code, and review diffs.

Most Claude Code value shows up on a **real codebase**: clone → orient → implement → review the diff. Gravix Layer exposes `runtime.git` and `runtime.file` for that loop.

Prerequisites: complete [Get started](/guides/claude-code/get-started) so Anthropic egress works. Extend the allowlist with your git host (below).

## Allow git egress

If your policy is an allowlist (not `allow_all`), add GitHub (or your forge):

```python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
client.network_policies.add_rule(
    os.environ["CLAUDE_NETWORK_POLICY_ID"],
    destination="github.com",
    port=443,
    protocol="tcp",
    description="GitHub HTTPS",
)
```

```bash theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
gravixlayer network-policy add-rule "$CLAUDE_NETWORK_POLICY_ID" \
  --destination github.com \
  --port 443 \
  --protocol tcp \
  --description "GitHub HTTPS"
```

Private repos: pass `auth_token=` to `runtime.git.clone`, or store `GITHUB_TOKEN` on an Identity provider.

## Full workflow: clone → CLAUDE.md → edit → diff

Uses the public [octocat/Hello-World](https://github.com/octocat/Hello-World) repo so the snippet runs without your org credentials.

<CodeGroup>
  ```python Python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  import os
  import uuid

  from gravixlayer import GravixLayer

  TEMPLATE = os.environ["GRAVIXLAYER_CLAUDE_TEMPLATE"]
  ANTHROPIC_API_KEY = os.environ["ANTHROPIC_API_KEY"]
  CLONE_URL = os.environ.get(
      "GIT_CLONE_URL",
      "https://github.com/octocat/Hello-World.git",
  )
  CLONE_BRANCH = os.environ.get("GIT_BRANCH", "master")
  REPO_PATH = "/workspace/repo"

  client = GravixLayer()

  provider_id = os.environ.get("ANTHROPIC_PROVIDER_ID")
  policy_id = os.environ.get("CLAUDE_NETWORK_POLICY_ID")

  if not provider_id:
      provider = client.identity.providers.create(
          name=f"anthropic-{uuid.uuid4().hex[:8]}",
          provider_type="api_key",
          secrets=[{"key": "ANTHROPIC_API_KEY", "value": ANTHROPIC_API_KEY}],
      )
      provider_id = provider.id

  if not policy_id:
      policy = client.network_policies.create(
          name=f"claude-git-{uuid.uuid4().hex[:8]}",
          egress_mode="allowlist",
          rules=[
              {"destination": "api.anthropic.com", "port": 443, "protocol": "tcp"},
              {"destination": "github.com", "port": 443, "protocol": "tcp"},
          ],
      )
      policy_id = policy.id

  runtime = client.runtime.create(
      template=TEMPLATE,
      providers=[provider_id],
      network_policy_ids=[policy_id],
      env_vars={"ANTHROPIC_API_KEY": ANTHROPIC_API_KEY},
      timeout=3600,
  )
  print("runtime_id:", runtime.runtime_id)

  clone = runtime.git.clone(
      url=CLONE_URL,
      path=REPO_PATH,
      branch=CLONE_BRANCH,
      depth=1,
      auth_token=os.environ.get("GITHUB_TOKEN") or None,
  )
  assert clone.success, clone.stderr or clone.stdout

  runtime.file.write(
      f"{REPO_PATH}/CLAUDE.md",
      "# Project notes\n\n"
      "- Prefer small, reviewable changes\n"
      "- Do not commit secrets\n",
  )

  result = runtime.run_cmd(
      command="claude",
      args=[
          "--dangerously-skip-permissions",
          "-p",
          "Add a one-line README note that this repo was touched by Claude Code "
          "in a Gravix Layer sandbox. Keep the change minimal.",
          "--output-format",
          "text",
      ],
      working_dir=REPO_PATH,
      timeout=1200,
  )
  print(result.stdout)
  print("exit_code:", result.exit_code)

  status = runtime.git.status(REPO_PATH)
  print("git status:\n", status.stdout)

  diff = runtime.run_cmd(
      command="git",
      args=["diff", "--stat"],
      working_dir=REPO_PATH,
      timeout=60,
  )
  print(diff.stdout)

  runtime.kill()
  ```

  ```bash CLI theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  # PROVIDER_ID + POLICY_ID must allow api.anthropic.com and github.com

  RT=$(gravixlayer runtime create \
    --template "$GRAVIXLAYER_CLAUDE_TEMPLATE" \
    --provider "$ANTHROPIC_PROVIDER_ID" \
    --network-policy "$CLAUDE_NETWORK_POLICY_ID" \
    --env "ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY" \
    --timeout 3600 \
    --wait \
    --output json | jq -r '.runtime_id')

  gravixlayer runtime exec "$RT" --timeout 180 -- \
    git clone --depth 1 --branch master \
    https://github.com/octocat/Hello-World.git /workspace/repo

  cat <<'EOF' | gravixlayer runtime files write "$RT" /workspace/repo/CLAUDE.md
  # Project notes

  - Prefer small, reviewable changes
  - Do not commit secrets
  EOF

  gravixlayer runtime exec "$RT" --timeout 1200 --workdir /workspace/repo -- \
    claude --dangerously-skip-permissions \
    -p 'Add a one-line README note that this repo was touched by Claude Code.' \
    --output-format text

  gravixlayer runtime exec "$RT" --workdir /workspace/repo -- git status
  gravixlayer runtime exec "$RT" --workdir /workspace/repo -- git diff --stat

  gravixlayer runtime kill "$RT" -y
  ```

  ```bash cURL theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
  API="https://api.gravixlayer.ai/v1"
  AUTH=(-H "Authorization: Bearer $GRAVIXLAYER_API_KEY" -H "Content-Type: application/json")

  # RT must already be running with Anthropic + github.com egress

  curl -sS -X POST "$API/agents/runtime/$RT/git/clone" "${AUTH[@]}" \
    -d '{
      "url": "https://github.com/octocat/Hello-World.git",
      "path": "/workspace/repo",
      "branch": "master",
      "depth": 1
    }' | jq .

  curl -sS -X POST "$API/agents/runtime/$RT/files/write" "${AUTH[@]}" \
    -d '{
      "path": "/workspace/repo/CLAUDE.md",
      "content": "# Project notes\n\n- Prefer small changes\n"
    }' | jq .

  curl -sS -X POST "$API/agents/runtime/$RT/commands/run" "${AUTH[@]}" \
    -d '{
      "command": "claude",
      "args": [
        "--dangerously-skip-permissions",
        "-p", "Add a one-line README note that this repo was touched by Claude Code.",
        "--output-format", "text"
      ],
      "working_dir": "/workspace/repo",
      "timeout": 1200000
    }' | jq .

  curl -sS -X POST "$API/agents/runtime/$RT/git/status" "${AUTH[@]}" \
    -d '{"repository_path": "/workspace/repo"}' | jq .
  ```
</CodeGroup>

## Download a changed file

```python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
content = runtime.file.download_file(f"{REPO_PATH}/README")
open("./README.downloaded", "wb").write(content)
```

## Commit and push (optional)

Requires push credentials. `runtime.git.push` accepts `username` / `password` (token as password is common for HTTPS).

```python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
branch = "agent/readme-note"
assert runtime.git.create_branch(REPO_PATH, branch).success
assert runtime.git.checkout(REPO_PATH, branch).success

assert runtime.git.add(REPO_PATH, paths=["."]).success
assert runtime.git.commit(
    REPO_PATH,
    message="docs: note Claude Code sandbox run",
    author_name="Claude on Gravix",
    author_email="agents@example.com",
).success

token = os.environ["GITHUB_TOKEN"]
push = runtime.git.push(
    REPO_PATH,
    remote="origin",
    username="x-access-token",
    password=token,
)
assert push.success, push.stderr or push.stdout
```

## Multi-step: plan then implement

```python theme={"theme":{"light":"catppuccin-latte","dark":"catppuccin-mocha"}}
import json

plan = runtime.run_cmd(
    command="claude",
    args=[
        "--dangerously-skip-permissions",
        "--output-format",
        "json",
        "-p",
        "Read the repo and produce a short plan to improve the README.",
    ],
    working_dir=REPO_PATH,
    timeout=900,
)
session_id = json.loads(plan.stdout)["session_id"]

runtime.run_cmd(
    command="claude",
    args=[
        "--dangerously-skip-permissions",
        "--resume",
        session_id,
        "-p",
        "Implement step 1 only.",
    ],
    working_dir=REPO_PATH,
    timeout=1200,
)
```

## Next

* [Long-running & parallel agents](/guides/claude-code/long-running-agents)
* [Custom templates & MCP](/guides/claude-code/custom-templates)
* [Git operations](/documentation/agentruntime/git-operations/git-clone)
