# Sandbox access

Some work is easier in code than with tools. For instance, to count every open issue that mentions login, your agent can page through them with a short Python program. Sandbox access lets that code call the connector's API with its connection, in the agent's [sandbox](https://getstream.io/agents/docs/flutter/harness-and-sandbox/#sandbox).

## Let code call GitHub

Set `sandbox: true` on the connector's entry. The agent needs a sandbox too:

```yaml title="agents/support/agent.yaml"
name: support
mode: text
llm: llm-fast
sandbox: daytona
connectors:
  - name: github
    connection: company # the label of a connection the app owns
    sandbox: true # code in the sandbox may call GitHub's API
```

Code that the agent runs with `run_code` now reads `GITHUB_TOKEN`. Its value is a placeholder, not the token. When the code sends the placeholder to GitHub, Stream puts the connection's token in its place on the way out. The code and the model never see the token.

>
> **Info:** Only the Go and JavaScript SDKs sync `sandbox` on a connector from `agent.yaml`.
>

## Worked example

This code, run by the agent, prints the GitHub login of the connection's account:

```python
import json
import os
import urllib.request

request = urllib.request.Request(
    "https://api.github.com/user",
    headers={
        "Authorization": "Bearer " + os.environ["GITHUB_TOKEN"],
        "User-Agent": "support-agent",
    },
)
with urllib.request.urlopen(request) as response:
    print(json.load(response)["login"])
```

## Where the placeholder works

| Connector | Env var        | Hosts                                                |
| --------- | -------------- | ---------------------------------------------------- |
| `github`  | `GITHUB_TOKEN` | `api.github.com`, `uploads.github.com`, `github.com` |

- The placeholder works only in a request header, over HTTPS, to one of these hosts. Anywhere else, such as in the URL's path or query or to another host, it stays a placeholder and gets no access.
- Code reaches these hosts even when `allowed_domains` does not list them.
- Code can read anything the token allows, not only what the entry's `tools` offers.
- Code only reads through a connector. A write is refused, such as `git lfs push`.

### Git over HTTPS

git takes the placeholder as the password in the remote's URL, with `x-access-token` as the user name. GitHub refuses a Bearer header from git, so use this form for `github.com`:

```python
import os
import subprocess

url = f"https://x-access-token:{os.environ['GITHUB_TOKEN']}@github.com/<owner>/<repo>.git"
print(subprocess.run(["git", "ls-remote", url], capture_output=True, text=True).stdout)
```

### Git LFS

The sandbox has no Git LFS. To pull a repository's large files, install it in the sandbox's `setup`:

```yaml title="agents/support/agent.yaml"
sandbox: daytona
sandbox_options:
  setup:
    - apt-get update && apt-get install -y git-lfs
```

Code can then run `git lfs pull` in a clone of a public repository made with the URL above.

## Turn it off

Remove `sandbox: true` from the entry, remove the entry, or delete the connection. Within a minute, the next code the agent runs gets no access, even in a conversation already running. A program already running keeps it until it ends.

## Going further

- [Harness & sandbox](https://getstream.io/agents/docs/flutter/harness-and-sandbox/): The sandbox, and what code in it may reach.
- [Connectors](https://getstream.io/agents/docs/flutter/connectors/): Whose account, the catalog, and the keys of a connector entry.

---

For the most recent version of this documentation, visit [https://getstream.io/agents/docs/flutter/connectors/sandbox/](https://getstream.io/agents/docs/flutter/connectors/sandbox/).